1!> \brief YAML output of SIESTA variables for external post-processors. 2!! 3!! This module provides facilities to output SIESTA variables into a YAML 4!! file at the end of a run. 5!! 6!! Variables are dumped in YAML format to provide structured data that 7!! can be read partially or fully, in any order, at the option of the user. 8!! 9!! The resulting output can be processed in C/C++ using LibYAML (found at 10!! https://github.com/yaml/libyaml), in Python through the ruamel.yaml 11!! package (found at https://pypi.python.org/pypi/ruamel.yaml), and in Perl 12!! thanks to the YAML::XS module (found at 13!! http://search.cpan.org/~tinita/YAML-LibYAML-0.69/lib/YAML/XS.pod). 14!! 15!! \author Yann Pouillon 16!! \date 2017-2018 17!! \copyright GNU General Public License version 3 18!! 19!! \note The interest of using the YAML format is that output can be achieved 20!! without introducing new external dependencies. 21!! 22module m_io_yaml 23 24 use precision, only: dp 25 26 implicit none 27 28 private 29 30 ! Ensure compliance with the YAML 1.2 file format 31 character(len=*), parameter :: CH10 = achar(10) !< New line 32 character(len=*), parameter :: CH34 = achar(34) !< Double quote 33 character(len=*), parameter :: YAML_HEADER = "%YAML 1.2"//CH10//"---"//CH10 34 character(len=*), parameter :: YAML_FOOTER = CH10//"..." 35 36 public :: siesta_write_yaml 37 38contains 39 40 !> \brief Creates a YAML file containing SIESTA build parameters and 41 !! final energy values. 42 !! 43 !! This routine calls io_assign() to get a free unit number and outputs 44 !! valid YAML data structures into the associated OUTVARS.yml file. The 45 !! data consists in two dictionaries: 46 !! - siesta: build parameters and status of optional features; 47 !! - energies: full decomposition of the total energy, using exactly 48 !! the same naming conventions as in the \ref m_energies module. 49 !! 50 !! The resulting file can easily be parsed using the ruamel.yaml Python 51 !! module. 52 !! 53 !! \todo Output forces and stress tensor. 54 subroutine siesta_write_yaml() 55 56 use m_energies 57 use version_info 58 59 implicit none 60 61 logical :: trigger 62 integer :: ierr, yaml_fd 63 64 ! Open YAML document 65 call io_assign(yaml_fd) 66 open(unit=yaml_fd, file='OUTVARS.yml', status='new', action='write', & 67& access='sequential', form='formatted', iostat=ierr) 68 ! FIXME: Find out why the system sometines reports a failure while things 69 ! have gone perfectly well. 70 !if ( ierr .ne. 0 ) call die('could not open OUTVARS.yml') 71 write(unit=yaml_fd, fmt='(A)') YAML_HEADER 72 73 ! Dump SIESTA information 74 write(unit=yaml_fd, fmt='(A)') "siesta:" 75 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "version", & 76& CH34, trim(adjustl(version_str)), CH34 77 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "arch", & 78& CH34, trim(adjustl(siesta_arch)), CH34 79 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "compiler", & 80& CH34, trim(adjustl(compiler_version)), CH34 81 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "fflags", & 82& CH34, trim(adjustl(fflags)), CH34 83 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "fppflags", & 84& CH34, trim(adjustl(fppflags)), CH34 85 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "libs", & 86& CH34, trim(adjustl(libs)), CH34 87#ifdef MPI 88 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "build", & 89& CH34, "mpi", CH34 90#else 91 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "build", & 92& CH34, "serial", CH34 93#endif 94#ifdef _OPENMP 95 trigger = .true. 96#else 97 trigger = .false. 98#endif 99 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "openmp", & 100& CH34, trim(yesno(trigger)), CH34 101#ifdef USE_GEMM3M 102 trigger = .true. 103#else 104 trigger = .false. 105#endif 106 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "gemm3m", & 107& CH34, trim(yesno(trigger)), CH34 108#ifdef CDF 109 trigger = .true. 110#else 111 trigger = .false. 112#endif 113 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "netcdf", & 114& CH34, trim(yesno(trigger)), CH34 115#ifdef NCDF_4 116 trigger = .true. 117#else 118 trigger = .false. 119#endif 120 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "netcdf4", & 121& CH34, trim(yesno(trigger)), CH34 122#ifdef NCDF_PARALLEL 123 trigger = .true. 124#else 125 trigger = .false. 126#endif 127 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "netcdf4_mpi", & 128& CH34, trim(yesno(trigger)), CH34 129#if defined(ON_DOMAIN_DECOMP) || defined(SIESTA__METIS) 130 trigger = .true. 131#else 132 trigger = .false. 133#endif 134 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "metis", & 135& CH34, trim(yesno(trigger)), CH34 136#ifdef SIESTA__CHESS 137 trigger = .true. 138#else 139 trigger = .false. 140#endif 141 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "chess", & 142& CH34, trim(yesno(trigger)), CH34 143#ifdef SIESTA__ELPA 144 trigger = .true. 145#else 146 trigger = .false. 147#endif 148 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "elpa", & 149& CH34, trim(yesno(trigger)), CH34 150#ifdef SIESTA__FLOOK 151 trigger = .true. 152#else 153 trigger = .false. 154#endif 155 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "flook", & 156& CH34, trim(yesno(trigger)), CH34 157#ifdef SIESTA__PEXSI 158 trigger = .true. 159#else 160 trigger = .false. 161#endif 162 write(unit=yaml_fd, fmt='(2X,A,":",1X,3(A))') "pexsi", & 163& CH34, trim(yesno(trigger)), CH34 164 165 ! Dump energies 166 write(unit=yaml_fd, fmt='(A,A)') CH10, "energies:" 167 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Ebs", Ebs 168 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Eions", Eions 169 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Ena", Ena 170 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Ekin", Ekin 171 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Enl", Enl 172 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Eso", Eso 173 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Edftu", Edftu 174 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "DEna", DEna 175 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "DUscf", DUscf 176 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "DUext", DUext 177 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Exc", Exc 178 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Ecorrec", Ecorrec 179 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Emadel", Emad 180 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Emeta", Emeta 181 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Emolmec", Emm 182 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Ekinion", Ekinion 183 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Eharris", Eharrs+Ekinion 184 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "Etot", Etot+Ekinion 185 write(unit=yaml_fd, fmt='(2X,A,":",1X,E24.8)') "FreeEng", FreeE+Ekinion 186 187 ! Close YAML document 188 write(unit=yaml_fd, fmt='(A)') YAML_FOOTER 189 call io_close(yaml_fd) 190 191 end subroutine siesta_write_yaml 192 193 !> \brief Internal function to translate booleans into "yes"/"no" strings. 194 !! 195 !! This function takes a boolean condition as input and returns a string 196 !! corresponding to the boolean value. 197 !! 198 !! \param[in] cond: boolean condition 199 !! \return string equal to "yes" for .true., and "no" for .false. 200 function yesno(cond) result(word) 201 202 logical, intent(in) :: cond 203 204 character(len=3) :: word 205 206 if ( cond ) then 207 word = "yes" 208 else 209 word = "no " 210 end if 211 212 end function yesno 213 214end module m_io_yaml 215