TABLE OF CONTENTS
create_a_crystal_den_file
[ Top ] [ etsf_io_tutorials ] [ Tutorials ]
NAME
create_a_crystal_den_file
FUNCTION
In this example, we will describe how to use the etsf_io_data_init() routine. This routine creates a file, conforming to the ETSF specifications, with several uninitialised variables in it. Then we will see how to write values into this file, using etsf_io_data_write().
To compile this exemple, use (assuming default installation paths):
${F90} -I/opt/include/${F90} -o create_a_crystal_den_file create_a_crystal_den_file.f90 -L/opt/lib -letsf_io -L/usr/lib -lnetcdf
SOURCE
program create_a_crystal_den_file use etsf_io integer :: i
NOTES
All routines from the group level requires two output arguments:
* lstat which is a logical. When .false. something goes wrong in the routine and the action is aborted. No actions are atomic, which means that if lstat is .false., the status of the NetCDF file (what have been done) is not guarantee. * error_data which a of type #etsf_io_low_error. It contains many informations about the error if lstat is .false.. One can use etsf_io_low_error_to_str to get a character(len = 1024) describing the error, or one can implement one itself since the type is public and documented.
SOURCE
logical :: lstat type(etsf_io_low_error) :: error_data
NOTES
To create a NetCDF, we need to give at creation time all the dimensions that define the variables. The file will then be allocated on disk and may be write with values later. All dimensions declared in the ETSF specifications are stored in a type called etsf_dims. Some of these dimensions are fixed by the specifications such as character_string_length and will be set by the etsf_io_data_init() routine itself. Other values are free to be chosen.
SOURCE
type(etsf_dims) :: dims
NOTES
To write values in one call into an already defined ETSF file, the type etsf_groups is used as a container for several groups. Here our container will have associated pointers on an etsf_geometry and an etsf_main. So we declare them. All the structures used in this library are only containers and do not have the allocated memory. This is done to avoid memory duplication when using the library with a code with its own variables. So we also need some variables (in a real case, they are declared in the main program) to stored our density and geometric informations.
SOURCE
! Specific variables required by the library type(etsf_groups_flags) :: flags type(etsf_groups) :: groups type(etsf_geometry), target :: geometry type(etsf_main), target :: main ! Variables that are declared in the main program in a real case double precision, allocatable, target :: density(:) integer, target :: space_group double precision, target :: primitive_vector(3, 3) double precision, allocatable, target :: reduced_atom_positions(:,:) integer, allocatable, target :: atom_species(:) character(len=2), allocatable, target :: chemical_symbols(:) integer, allocatable, target :: reduced_symmetry_matrices(:,:,:) double precision, allocatable, target :: reduced_symmetry_translations(:,:)
NOTES
We will create for example a file for the density of the silane molecule, without spin nor spin-orbit, 1 k point. We imagine that the molecule no symmetry except identity.
SOURCE
dims%max_number_of_coefficients = 1400 dims%max_number_of_states = 6 dims%number_of_atoms = 5 dims%number_of_atom_species = 2 dims%number_of_components = 1 dims%number_of_grid_points_vector1 = 36 dims%number_of_grid_points_vector2 = 36 dims%number_of_grid_points_vector3 = 36 dims%number_of_kpoints = 1 dims%number_of_spinor_components = 1 dims%number_of_spins = 1 dims%number_of_symmetry_operations = 1
NOTES
Now that dimensions have been stored in the appropriated structure, we can call the etsf_io_data_init() routine itself. The 'groups' argument is very important It will tell which variables will we allocated on disk. All variables are gathered by groups and one can choose one or several groups to be defined. To do it, use the flags from #FLAGS_VARIABLES, in a summation for each group in the etsf_groups_flags structure. By default no group will be defined, to add the geometry group, we will use the value etsf_geometry_all (from #FLAGS_VARIABLES) ; and to add the density variable (from the main group), and only this one, we will use etsf_main_denisty.
Other arguments of the routine are quite easy to understand. The optional k_dependent argument is here to handle the case of reduced_coordinates_of_plane_waves which shape depends on the value of this attribute. If k_dependent is given .false. (default is .true.), then all variables with this attribute will be labelled "no" and the variable reduced_coordinates_of_plane_waves will be a two dimensional array.
SOURCE
flags%geometry = etsf_geometry_all flags%main = etsf_main_density call etsf_io_data_init("create_a_crystal_den_file.nc", flags, dims, & & "Tutorial ETSF_IO, create a density file", & & "Created by the tutorial example of the library", & & lstat, error_data)
NOTES
The required variables for a density file are in etsf_geometry and in etsf_main, that's why the groups argument is the sum of the two flags.
We can now, handle the error, if one occured. The method etsf_io_low_error_handle() is used to print the contains of an error type on the standrard output. If one is interested on printing the error on something different than the standard output, one should convert the error into a character(len = 1024) with etsf_io_low_error_to_str() before.
SOURCE
if (.not. lstat) then call etsf_io_low_error_handle(error_data) stop end if
NOTES
At this time of the example, the disk space to store the density and the geometric informations has been reserved. In a real case, we let the main program computing the density and setting up the geometric informations.
SOURCE
! The main program allocate memory for its computation. allocate(density(36 * 36 * 36)) allocate(reduced_atom_positions(3,5)) allocate(atom_species(5)) allocate(chemical_symbols(2)) allocate(reduced_symmetry_matrices(3, 3, 1)) allocate(reduced_symmetry_translations(3, 1)) ! The main program compute all symmetries and set up the positions... space_group = 1 primitive_vector = reshape( (/ 10, 0, 0, 0, 10, 0, 0, 0, 10 /), (/ 3, 3 /)) reduced_symmetry_matrices = reshape( (/ 1, 0, 0, 0, 1, 0, 0, 0, 1 /), (/ 3, 3, 1 /)) reduced_symmetry_translations = reshape( (/ 0, 0, 0 /), (/ 3, 1 /)) reduced_atom_positions = reshape( (/ 0.5d0, 0.5d0, 0.5d0, & & 0.6d0, 0.6d0, 0.6d0, & & 0.6d0, 0.4d0, 0.4d0, & & 0.4d0, 0.4d0, 0.6d0, & & 0.4d0, 0.6d0, 0.4d0 /), (/ 3, 5 /)) atom_species = (/ 2, 1, 1, 1, 1 /) chemical_symbols = (/ "H ", "Si" /) ! We compute the density with a powerful algorithm. density = (/ (0.d0 + i, i = 1, 36 * 36 * 36) /)
NOTES
Before calling the etsf_io_data_write() routine, we associate the pointers of our group types to the main program memory data. Only associated pointers will be written. All other defined variables will be let untouched. Some variable are defined with a type called etsf_io_low_var_double or etsf_io_low_var_integer. These variables are arrays which could have a different shape in the main program and in the specifications. For instance, our density is 1D only whereas in the specifications the density is 5D. So we use the attribute %data1D of the structure etsf_io_low_var_double for the density. This will work because data in the main program memory has the same number of elements than the space defined in the ETSF file AND data are ordered in the same way (elements along X axis are varying quicker than along Y or Z).
SOURCE
! We associate the geometry geometry%space_group => space_group geometry%primitive_vectors => primitive_vector geometry%reduced_symmetry_matrices => reduced_symmetry_matrices geometry%reduced_symmetry_translations => reduced_symmetry_translations geometry%atom_species => atom_species geometry%reduced_atom_positions => reduced_atom_positions geometry%chemical_symbols => chemical_symbols ! We associate the main data ! We don't want to dupplicate the density data even if ours is 1D ! and ETSF is 5D, so we use the unformatted pointer in the etsf_main ! structure. main%density%data1D => density ! We associate our two group in the container. groups%geometry => geometry groups%main => main ! We write. call etsf_io_data_write("create_a_crystal_den_file.nc", & & groups, lstat, error_data) ! We handle the error if (.not. lstat) then call etsf_io_low_error_handle(error_data) stop end if ! The main program will deallocate its own memory. deallocate(density) deallocate(reduced_atom_positions) deallocate(atom_species) deallocate(chemical_symbols) deallocate(reduced_symmetry_matrices) deallocate(reduced_symmetry_translations) end program create_a_crystal_den_file