TABLE OF CONTENTS


convert_to_xyz

[ Top ] [ etsf_io_tutorials ] [ Tutorials ]

NAME

convert_to_xyz

FUNCTION

In this example, we will describe how to use the high level routines from etsf_io_file and etsf_io_tools (from library etsf_io_utils). Doing it, we will read a cristallographic file, check its validity and convert it to XYZ file, reading the coordinates of atoms and getting their names.

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

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

SOURCE

program convert_to_xyz

  use etsf_io_low_level
  use etsf_io
  use etsf_io_file
  use etsf_io_tools

  implicit none

  integer :: iargc
  character(len = etsf_io_low_error_len) :: filename, error_string
  logical :: lstat
  type(etsf_io_low_error) :: error_data
  integer :: i_atom
  double precision :: coord(etsf_3dimlen)

NOTES

In this tutorial, we will open an ETSF file, and some variable of the geometry group (see the first tutorial on how to create_a_crystal_den_file for further explanations on groups and especially etsf_geometry).

The required data to create an XYZ file are:

SOURCE

  integer :: ncid
  type(etsf_dims) :: dims_data
  type(etsf_geometry) :: geometry_data
  double precision, allocatable, target :: primitive_vectors(:,:)
  double precision, allocatable, target :: reduced_atom_positions(:,:)
  integer, allocatable, target :: atom_species(:)

NOTES

The names of atoms receives a special treatment since it can be found in several variables. The specifications are clear on preference and we will use the etsf_io_tools_get_atom_names() routine to handle this preference and read the atom names.

SOURCE

  character(len = etsf_charlen), allocatable :: atom_names(:)

NOTES

We read the number of argument and get the input filename from the command line.

SOURCE

  ! Read number of program argument, should be one.
  if (iargc() /= 1) then
     write(0, *) "Error: one argument is required."
     stop
  end if
  ! Read name of input file.
  call getarg(1, filename)

NOTES

Before doing anything else, we check that our file is a valid crystallographic file. To do it, we use the module etsf_io_file and its routine etsf_io_file_check(). This routine will open the given file and check that it machtes one or several requirements (see flags in ETSF_IO_VALIDITY_FLAGS). Flags can be added to form a complex validation on several specifications.

If an error occurs, we transform the error data to a string and output it on the standard error.

SOURCE

  call etsf_io_file_check(trim(filename), etsf_crystallographic_data, &
       & lstat, error_data)
  if (.not. lstat) then
     write(0, *) "Error: invalid input file, it does not match crystallographic"
     write(0, *) "       requirements. Given reason:"
     call etsf_io_low_error_to_str(error_string, error_data)
     write(0, "(A)") trim(error_string)
     stop
  end if

NOTES

Now that our file is valid, we will follow a step by step procedure to reopen it, read the dimensions, allocate our temporary arrays, read the required informations, get the atoms names, close the file and output the informations in XYZ format.

SOURCE

  call etsf_io_low_open_read(ncid, trim(filename), lstat, error_data = error_data)
  if (.not. lstat) then
     call etsf_io_low_error_to_str(error_string, error_data)
     write(0, "(A)") trim(error_string)
     stop
  end if

NOTES

The dimensions are read and stored into dims_data.

SOURCE

  call etsf_io_dims_get(ncid, dims_data, lstat, error_data)
  if (.not. lstat) then
     call etsf_io_low_error_to_str(error_string, error_data)
     write(0, "(A)") trim(error_string)
     stop
  end if

NOTES

We allocate the local arrays where to put the read informations.

SOURCE

  allocate(primitive_vectors(dims_data%number_of_cartesian_directions, &
       & dims_data%number_of_vectors))
  allocate(reduced_atom_positions(dims_data%number_of_reduced_dimensions, &
       & dims_data%number_of_atoms))
  allocate(atom_species(dims_data%number_of_atoms))
  allocate(atom_names(dims_data%number_of_atom_species))
  geometry_data%primitive_vectors => primitive_vectors
  geometry_data%reduced_atom_positions => reduced_atom_positions
  geometry_data%atom_species => atom_species

NOTES

We get the informations from the NetCDF file for the pointers that have been associated in geometry_data.

SOURCE

  call etsf_io_geometry_get(ncid, geometry_data, lstat, error_data)
  if (.not. lstat) then
     call etsf_io_low_error_to_str(error_string, error_data)
     write(0, "(A)") trim(error_string)
     stop
  end if

NOTES

We use the high level routine that get the names of atoms. If the file is valid, it always returns string informations (into @atom_names), but atomic numbers can also be returned as double values in an optional array (see @atom_numbers). We don't need here the double values, so we don't use the optional argument.

SOURCE

  call etsf_io_tools_get_atom_names(ncid, atom_names, lstat, error_data)
  if (.not. lstat) then
     call etsf_io_low_error_to_str(error_string, error_data)
     write(0, "(A)") trim(error_string)
     stop
  end if

NOTES

We don't forget to close the file.

SOURCE

  call etsf_io_low_close(ncid, lstat, error_data)
  if (.not. lstat) then
     call etsf_io_low_error_to_str(error_string, error_data)
     write(0, "(A)") trim(error_string)
     stop
  end if

NOTES

Finally we output informations in XYZ format.

SOURCE

  write(*, "(I0)") dims_data%number_of_atoms
  write(*, "(3A)") "Converted from '", trim(filename), "'"
  do i_atom = 1, dims_data%number_of_atoms, 1
     coord(1) = primitive_vectors(1, 1) * reduced_atom_positions(1, i_atom) + &
          & primitive_vectors(2, 1) * reduced_atom_positions(2, i_atom) + &
          & primitive_vectors(3, 1) * reduced_atom_positions(3, i_atom)
     coord(2) = primitive_vectors(1, 2) * reduced_atom_positions(1, i_atom) + &
          & primitive_vectors(2, 2) * reduced_atom_positions(2, i_atom) + &
          & primitive_vectors(3, 2) * reduced_atom_positions(3, i_atom)
     coord(3) = primitive_vectors(1, 3) * reduced_atom_positions(1, i_atom) + &
          & primitive_vectors(2, 3) * reduced_atom_positions(2, i_atom) + &
          & primitive_vectors(3, 3) * reduced_atom_positions(3, i_atom)
     write(*, "(A,3E16.6)") trim(atom_names(atom_species(i_atom))), coord
  end do

  deallocate(primitive_vectors)
  deallocate(reduced_atom_positions)
  deallocate(atom_species)
  deallocate(atom_names)
end program convert_to_xyz