TABLE OF CONTENTS


mix_ETSF_and_non_ETSF

[ Top ] [ etsf_io_tutorials ] [ Tutorials ]

NAME

mix_ETSF_and_non_ETSF

FUNCTION

This tutorial is based on the first tutorial that create a density file. In this example, we introduce how to mix ETSF variables (the density) and non-ETSF variables (user defined, program dependent values...).

The main difference is to use the etsf_io_<group>_put() routines instead of the all-in-one etsf_io_data_write() as introduced in the first tutorial. The changed lines of the first tutorial are kept as commentaries for comparison purposes.

To compile this exemple, use (assuming default installation paths):

   ${F90} -I/opt/include/${F90} -o mix_ETSF_and_non_ETSF mix_ETSF_and_non_ETSF.f90
          -L/opt/lib -letsf_io_utils -letsf_io -L/usr/lib -lnetcdf

SOURCE

program mix_ETSF_and_non_ETSF

  use etsf_io_low_level
  use etsf_io

  integer :: i

NOTES

In the variable declarations relative to ETSF_IO, the etsf_group structure is not used anymore, since the def and put actions will be more atomic (but not as atomic as handling each variable).

SOURCE

  integer                 :: ncid
  logical                 :: lstat
  type(etsf_io_low_error) :: error_data
  type(etsf_groups_flags) :: flags
  type(etsf_dims)         :: dims
  ! Specific variables required by the library
  !FIRST# type(etsf_groups)           :: groups
  type(etsf_geometry), target :: geometry
  type(etsf_main), target     :: main

NOTES

The variable declared in the main program are left unchanged.

SOURCE

  ! 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

The definition of the dimensions is still the same

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

The declaration of the file is almost left unchanged. A file is allocated on disk with the given dimensions (see the dims variable).

But, the main group is not defined here. This is done because the main group (density, coefficients of wavefunctions...) in the ETSF_IO specifications must be declared last.

SOURCE

  !FIRST# the etsf_grp_main was declared here.
  flags%geometry = etsf_geometry_all
  flags%main     = etsf_main_none
  call etsf_io_data_init("mix_ETSF_and_non_ETSF.nc", flags, dims, &
                       & "Tutorial ETSF_IO, create a density file", &
                       & "Created by the tutorial example of the library", &
                       & lstat, error_data, overwrite = .true.)
  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

The associations between the structures used in the group level and variable in the main program memory are also kept. Only the gathering of all groups in the etsf_groups structure is not done.

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
  !FIRST# ! We associate our two group in the container.
  !FIRST# groups%geometry => geometry
  !FIRST# groups%main => main

NOTES

The write action is modified. We prefer to do it to avoid to open the file for the ETSF variables, close it, and reopen it for the non-ETSF variable. This is of course possible, but the idea of this tutorial is to show how to use a lower level of access for the ETSF variables.

Then, we open the created file with etsf_io_low_open_modify(). The file is then in a define mode, so we can easily define the non-ETSF variables.

SOURCE

  ! Open file for writing
  call etsf_io_low_open_modify(ncid,"mix_ETSF_and_non_ETSF.nc", &
       & lstat, error_data = error_data)
  if (.not. lstat) then
    call etsf_io_low_error_handle(error_data)
    stop
  end if

  ! We define some private non-ETSF variables (and dimensions if necessary).
  call etsf_io_low_def_var(ncid, "age_of_captain", etsf_io_low_integer, &
       & lstat, error_data = error_data)
  if (.not. lstat) then
    call etsf_io_low_error_handle(error_data)
    stop
  end if
  call etsf_io_low_write_dim(ncid, "number_of_captains_children", 2, &
       & lstat, error_data = error_data)
  if (.not. lstat) then
    call etsf_io_low_error_handle(error_data)
    stop
  end if
  call etsf_io_low_def_var(ncid, "age_of_captains_children", etsf_io_low_integer, &
       & (/ "number_of_captains_children" /), lstat, error_data = error_data)
  if (.not. lstat) then
    call etsf_io_low_error_handle(error_data)
    stop
  end if

NOTES

Now that the non-ETSF variables has been added, we can defined the main ETSF variables that will be at the end of the file, as required in the specifications.

SOURCE

  call etsf_io_main_def(ncid, lstat, error_data, flags = etsf_main_density)
  if (.not. lstat) then
    call etsf_io_low_error_handle(error_data)
    stop
  end if

NOTES

The all-in-one routine etsf_io_data_write() is replaced here by a group per group put action.

SOURCE

  ! We write the ETSF variable with the group methods.
  call etsf_io_geometry_put(ncid, geometry, lstat, error_data)
  !FIRST# call etsf_io_data_write("create_a_crystal_den_file.nc", &
  !FIRST#                       & etsf_grp_main + etsf_grp_geometry, &
  !FIRST#                       & groups, lstat, error_data)
  if (.not. lstat) then
    call etsf_io_low_error_handle(error_data)
    stop
  end if
  call etsf_io_main_put(ncid, main, lstat, error_data)
  if (.not. lstat) then
    call etsf_io_low_error_handle(error_data)
    stop
  end if

NOTES

After that, we change the file status for write access with etsf_io_low_set_write_mode() (this is automatically done by the put() routines in the group level. The non-ETSF variables are written.

SOURCE

  ! We switch to write mode.
  call etsf_io_low_set_write_mode(ncid, lstat, error_data = error_data)
  if (.not. lstat) then
    call etsf_io_low_error_handle(error_data)
    stop
  end if

  ! We write the non-ETSF variables by hand.
  call etsf_io_low_write_var(ncid, "age_of_captain", 42, &
       & lstat, error_data = error_data)
  if (.not. lstat) then
    call etsf_io_low_error_handle(error_data)
    stop
  end if
  call etsf_io_low_write_var(ncid, "age_of_captains_children", (/ 12, 13 /), &
       & lstat, error_data = error_data)
  if (.not. lstat) then
    call etsf_io_low_error_handle(error_data)
    stop
  end if

NOTES

We don't forget to close the file!

SOURCE

  call etsf_io_low_close(ncid, lstat, error_data = error_data)
  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 mix_ETSF_and_non_ETSF