LCOV - code coverage report
Current view: top level - src/41_geometry - m_crystal.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.3 % 655 559
Test Date: 2026-09-21 13:49:52 Functions: 81.8 % 33 27

            Line data    Source code
       1              : !!****m* ABINIT/m_crystal
       2              : !! NAME
       3              : !! m_crystal
       4              : !!
       5              : !! FUNCTION
       6              : !! Module containing the definition of the crystal_t data type and methods used to handle it.
       7              : !!
       8              : !! COPYRIGHT
       9              : !!  Copyright (C) 2008-2026 ABINIT group (MG, YP, MJV, GA)
      10              : !!  This file is distributed under the terms of the
      11              : !!  GNU General Public License, see ~abinit/COPYING
      12              : !!  or http://www.gnu.org/copyleft/gpl.txt .
      13              : !!
      14              : !! SOURCE
      15              : 
      16              : #if defined HAVE_CONFIG_H
      17              : #include "config.h"
      18              : #endif
      19              : 
      20              : #include "abi_common.h"
      21              : 
      22              : module m_crystal
      23              : 
      24              :  use, intrinsic :: iso_c_binding
      25              :  use defs_basis
      26              :  use m_errors
      27              :  use m_abicore
      28              :  use m_atomdata
      29              :  use m_xmpi
      30              :  use m_nctk
      31              :  use netcdf
      32              : 
      33              :  use m_io_tools,       only : file_exists
      34              :  use m_numeric_tools,  only : set2unit
      35              :  use m_hide_lapack,    only : matrginv
      36              :  use m_fstrings,       only : int2char10, sjoin, yesno, itoa, strcat
      37              :  use m_matrix,         only : mati3inv
      38              :  use m_symtk,          only : sg_multable, symatm, print_symmetries
      39              :  use m_spgdata,        only : spgdata
      40              :  use m_geometry,       only : metric, xred2xcart, xcart2xred, remove_inversion, getspinrot, symredcart, normv
      41              :  use m_io_tools,       only : open_file
      42              :  use m_pptools,        only : write_xsf
      43              : 
      44              :  implicit none
      45              : 
      46              :  private
      47              : !!***
      48              : 
      49              : !----------------------------------------------------------------------
      50              : 
      51              : !!****t* m_crystal/crystal_t
      52              : !! NAME
      53              : !! crystal_t
      54              : !!
      55              : !! FUNCTION
      56              : !! Structure defining the unit cell (geometry, atomic positions and symmetry operations in real and reciprocal space)
      57              : !!
      58              : !! SOURCE
      59              : 
      60              :  type,public :: crystal_t
      61              : 
      62              : !scalars
      63              :   !integer :: point_group                    ! Point group
      64              :   !integer :: bravais,crystsys               ! Bravais lattice, Crystal system
      65              :   !integer :: nptsym                         ! No of point symmetries of the Bravais lattice
      66              :   !integer :: bravais(11)                    ! bravais(1)=iholohedry, bravais(2)=center
      67              :                                              ! bravais(3:11)=coordinates of rprim in the axes of the conventional
      68              :                                              ! bravais lattice (*2 if center/=0)
      69              :   !integer,pointer ptsymrel(:,:,:)
      70              :   !ptsymrel(3,3,nptsym)
      71              :   ! nptsym point-symmetry operations of the Bravais lattice in real space in terms of primitive translations.
      72              : 
      73              :   integer :: natom = -1
      74              :   ! Number of atoms
      75              : 
      76              :   integer :: nsym = -1
      77              :   ! Number of symmetry operations
      78              : 
      79              :   integer :: ntypat = -1
      80              :   ! Number of type of atoms
      81              : 
      82              :   integer :: nirredat = -1
      83              :   ! Number of irreducibel atoms
      84              : 
      85              :   integer :: npsp = -1
      86              :   ! No. of pseudopotentials
      87              : 
      88              :   integer :: space_group = -1
      89              :   ! Space group
      90              : 
      91              :   integer :: timrev = -1
      92              :   ! TODO BE CAREFUL here, as the convention used in abinit is different.
      93              :   ! 1 => do not use time-reversal symmetry.
      94              :   ! 2 => take advantage of time-reversal symmetry.
      95              : 
      96              :   real(dp) :: ucvol = zero
      97              :   ! Real space unit cell volume.
      98              : 
      99              :   logical :: use_antiferro
     100              :   ! .TRUE. if AFM symmetries are present and used.
     101              : 
     102              : !arrays
     103              :   real(dp) :: angdeg(3) = zero
     104              :   ! Angles among rprim (degree).
     105              : 
     106              :   real(dp) :: gmet(3,3) = zero
     107              :   ! Reciprocal space metric ($\textrm{bohr}^{-2}$).
     108              : 
     109              :   real(dp) :: gprimd(3,3) = zero
     110              :   ! Dimensional primitive translations for reciprocal space ($\textrm{bohr}^{-1}$)
     111              : 
     112              :   real(dp) :: rmet(3,3) = zero
     113              :   ! Metric in real space.
     114              : 
     115              :   real(dp) :: rprimd(3,3) = zero
     116              :   ! Direct lattice vectors, Bohr units.
     117              : 
     118              :   integer,allocatable :: indsym(:,:,:)
     119              :   ! indsym(4,nsym,natom)
     120              :   ! indirect indexing array for atoms, see symatm.F90.
     121              :   ! $ R^{-1} (xred(:,iat)-\tau) = xred(:,iat_sym) + R_0 $
     122              :   ! * indsym(4,  isym,iat) gives iat_sym in the original unit cell.
     123              :   ! * indsym(1:3,isym,iat) gives the lattice vector $R_0$.
     124              : 
     125              :   integer,allocatable :: symafm(:)
     126              :   ! symafm(nsym)
     127              :   ! (Anti)Ferromagnetic symmetries. +1/-1
     128              : 
     129              :   integer,allocatable :: symrec(:,:,:)
     130              :   ! symrec(3,3,nsym)
     131              :   ! Symmetry operation in reciprocal space (reduced coordinates)
     132              : 
     133              :   integer,allocatable :: symrel(:,:,:)
     134              :   ! symrel(3,3,nsym)
     135              :   ! Symmetry operations in direct space (reduced coordinates).
     136              : 
     137              :   real(dp),allocatable :: symrel_cart(:,:,:)
     138              :   ! symrel_cart(3,3,nsym)
     139              :   ! Symmetry operations in cartesian coordinates (same order as symrel)
     140              : 
     141              :   integer,allocatable :: atindx(:)
     142              :   integer,allocatable :: atindx1(:)
     143              :   ! atindx(natom), atindx1(natom)
     144              :   ! Index tables for atoms useful to treat atoms type after type.
     145              : 
     146              :   integer,allocatable :: typat(:)
     147              :   integer,allocatable :: nattyp(:)
     148              :   ! typat(natom), nattyp(ntypat)
     149              :   ! Type of each natom and number of atoms of each type.
     150              : 
     151              :   integer,allocatable :: irredatindx(:)
     152              :   ! Index of irreducible atoms
     153              : 
     154              :   real(dp),allocatable :: tnons(:,:)
     155              :   ! tnons(3,nsym)
     156              :   ! Fractional translations (reduced coordinates)
     157              : 
     158              :   real(dp),allocatable :: xcart(:,:)
     159              :   ! xcart(3,natom)
     160              :   ! Cartesian coordinates.
     161              : 
     162              :   real(dp),allocatable :: xred(:,:)
     163              :   ! xred(3,natom)
     164              :   ! Reduced coordinates.
     165              : 
     166              :   real(dp),allocatable :: spinrot(:,:)
     167              :   ! spinrot(4,nsym)
     168              :   ! spinor rotation matrices.
     169              : 
     170              :   real(dp),allocatable :: amu(:)
     171              :   !  amu(ntypat)
     172              :   !  mass of the atoms (atomic mass unit)
     173              : 
     174              :   real(dp),allocatable :: zion(:)
     175              :   ! zion(ntypat)
     176              :   ! Charge of the pseudo-ion
     177              :   ! (No of valence electrons needed to screen exactly the pseudopotential).
     178              : 
     179              :   !real(dp),allocatable :: znucltypat(:)
     180              :    ! znucltypat(ntypat)
     181              :    ! The atomic number of each type of atom (might be alchemy wrt psps)
     182              : 
     183              :   real(dp),allocatable :: znucl(:)
     184              :   ! znucl(npsp)
     185              :   ! Nuclear charge for each type of pseudopotential
     186              : 
     187              :   character(len=132),allocatable :: title(:)
     188              :    ! title(ntypat)
     189              :    ! The content of first line read from the psp file
     190              : 
     191              :  contains
     192              : 
     193              :    procedure :: init => crystal_init
     194              :     ! Main Creation method.
     195              : 
     196              :    procedure :: ncwrite => crystal_ncwrite
     197              :    ! Write the object in netcdf format
     198              : 
     199              :    procedure :: ncwrite_path => crystal_ncwrite_path
     200              :    ! Dump the object to netcdf file.
     201              : 
     202              :    procedure :: ncread => crystal_ncread
     203              :    ! Read the object from a netcdf file.
     204              : 
     205              :    procedure :: isymmorphic
     206              :    ! True if space group is symmorphic.
     207              : 
     208              :    procedure :: idx_spatial_inversion
     209              :    ! Return the index of the spatial inversion, 0 if not present.
     210              : 
     211              :    procedure :: isalchemical
     212              :    ! True if we are using alchemical pseudopotentials.
     213              : 
     214              :    procedure :: malloc => crystal_malloc
     215              :    ! Allocate memory.
     216              : 
     217              :    procedure :: free => crystal_free
     218              :    ! Free memory.
     219              : 
     220              :    procedure :: copy => crystal_copy
     221              :    ! Copy object.
     222              : 
     223              :    procedure :: bcast => crystal_bcast
     224              :    ! Master broadcasts data and others allocate their arrays.
     225              : 
     226              :    procedure :: new_without_symmetries => crystal_without_symmetries
     227              :    ! Return new object without symmetries (actually nsym = 1 and identity operation)
     228              : 
     229              :    procedure :: new_trinv_only => crystal_trinv_only
     230              :    ! Return new object without only identity, inversion & TR symmetries (if present)
     231              : 
     232              :    procedure :: get_point_group => crystal_point_group
     233              :    ! Return the symmetries of the point group of the crystal.
     234              : 
     235              :    procedure :: index_atoms => crystal_index_atoms
     236              :    ! Generate index table of atoms.
     237              : 
     238              :    procedure :: compute_sym => crystal_compute_sym
     239              :    ! Compute all symetries and construct tables.
     240              : 
     241              :    procedure :: compute_geometry => crystal_compute_geometry
     242              :    ! Compute the different metrics and the angle between primitive vectors.
     243              : 
     244              :    procedure :: symbol_type
     245              :    ! Return the atomic symbol from the itypat index.
     246              : 
     247              :    procedure :: symbol_iatom
     248              :    ! Return the atomic symbol from the iatom index.
     249              : 
     250              :    procedure :: adata_type
     251              :    ! Return atomic data from the itypat index.
     252              : 
     253              :    procedure :: compare => crystal_compare
     254              :    ! Compare two crystalline structures, write warning messages if they differ, return exit status
     255              : 
     256              :    procedure :: print => crystal_print
     257              :    ! Print dimensions and basic info stored in the object
     258              : 
     259              :    procedure :: print_abivars => crystal_print_abivars
     260              :    ! Print unit cell info in Abinit/abivars format
     261              : 
     262              :    procedure :: symmetrize_cart_vec3 => crystal_symmetrize_cart_vec3
     263              :    ! Symmetrize a 3d cartesian vector
     264              : 
     265              :    procedure :: symmetrize_cart_tens33 => crystal_symmetrize_cart_tens33
     266              :    ! Symmetrize a cartesian 3x3 tensor
     267              : 
     268              :    procedure :: get_redcart_qdirs => get_redcart_qdirs
     269              :    ! Return predefined list of 6 q-versors in reciprocal space reduced coordinates.
     270              : 
     271              :    procedure :: write_xsf_data => crystal_write_xsf_data
     272              :    !  Write array in real space in XSF format
     273              : 
     274              :  end type crystal_t
     275              : 
     276              :  public :: symbols_crystal         ! Return an array with the atomic symbol: ["Sr","Ru","O1","O2","O3"]
     277              :  public :: prt_cif                 ! Print CIF file.
     278              :  public :: prtposcar               ! output VASP style POSCAR and FORCES files.
     279              : !!***
     280              : 
     281              : CONTAINS  !====================================================================================================
     282              : !!***
     283              : 
     284              : !!****f* m_crystal/crystal_init
     285              : !! NAME
     286              : !!  crystal_init
     287              : !!
     288              : !! FUNCTION
     289              : !!  Initialize a crystal_t data type.
     290              : !!  Ideally the routine should work in two different modes:
     291              : !!  Either the symmetries are directly supplied or the space group
     292              : !!  is determined starting from the definition of the unit cell.
     293              : !!  Only the first method is implemented, the second one should be
     294              : !!  a wrapper for the symmetry finder library. To implement the
     295              : !!  second case I have to add additional entries in the object
     296              : !!  and I have also to pass an object describing the (optional) geometry builder.
     297              : !!
     298              : !! INPUTS
     299              : !!  natom=number of atom
     300              : !!  ntypat=number of type of atoms
     301              : !!  nsym=number of symmetry operations
     302              : !!  rprimd(3,3)=dimensional lattive vector (real space)
     303              : !!  typat(natom)=type of each atom
     304              : !!  xred(3,natom)=reduced coordinates of each atom
     305              : !!  symrel(3,3,nsym) [optional]=symmetry operations in real space
     306              : !!  space_group=Space group (0 if not available)
     307              : !!  tnons(3,nsym) [optional]=fractional Translations
     308              : !!  symafm(nsym) [optional]=  ferromagnetic symmetries
     309              : !!  remove_inv [optional]= if .TRUE. the inversion is removed from the set of symmetries
     310              : !!  timrev ==2 => take advantage of time-reversal symmetry
     311              : !!         ==1 ==> do not use time-reversal symmetry
     312              : !!
     313              : !! OUTPUT
     314              : !!  Cryst<crystal_t>= the object completely initialized.
     315              : !!
     316              : !! TODO
     317              : !!  Add additional entries in the class:
     318              : !!  1) Info on space and point group (generators?).
     319              : !!  2) alchemy
     320              : !!  3) masses and nuclear (pseudo&AE) charge
     321              : !!  4) forces stresses, velocities.
     322              : !!  5) constraints for the relaxation
     323              : !!  6) Likely I will need also info on the electric field and berryopt
     324              : !!
     325              : !! SOURCE
     326              : 
     327        31938 : subroutine crystal_init(cryst,amu,space_group,natom,npsp,ntypat,nsym,rprimd,typat,xred,&
     328        31938 :                         zion,znucl,timrev,use_antiferro,remove_inv,title,&
     329        95814 :                         symrel,tnons,symafm) ! Optional
     330              : 
     331              : !Arguments ------------------------------------
     332              : !scalars
     333              :  class(crystal_t),intent(inout) :: Cryst
     334              :  integer,intent(in) :: natom,ntypat,nsym,timrev,space_group,npsp
     335              :  logical,intent(in) :: remove_inv,use_antiferro
     336              : !arrays
     337              :  integer,intent(in) :: typat(natom)
     338              :  integer,optional,intent(in) :: symrel(3,3,nsym),symafm(nsym)
     339              :  real(dp),intent(in) :: amu(ntypat),xred(3,natom),rprimd(3,3),zion(ntypat),znucl(npsp)
     340              :  real(dp),optional,intent(in) :: tnons(3,nsym)
     341              :  character(len=*),intent(in) :: title(ntypat)
     342              : 
     343              : !Local variables-------------------------------
     344              : !scalars
     345              :  integer :: pinv,nsym_noI
     346              :  !character(len=500) :: msg
     347              : !arrays
     348        31938 :  integer,pointer :: symrel_noI(:,:,:)
     349        31938 :  real(dp),pointer :: tnons_noI(:,:)
     350              : ! *************************************************************************
     351              : 
     352              :  !@crystal_t
     353        31938 :  Cryst%natom = natom
     354        31938 :  Cryst%ntypat = ntypat
     355        31938 :  Cryst%npsp = npsp
     356        31938 :  Cryst%space_group = space_group
     357        31938 :  Cryst%nsym = nsym
     358        31938 :  Cryst%timrev = timrev
     359        31938 :  Cryst%use_antiferro = use_antiferro
     360       415194 :  Cryst%rprimd = rprimd
     361              : 
     362        31938 :  call Cryst%free()
     363        31938 :  call Cryst%malloc()
     364              : 
     365       107634 :  Cryst%amu   = amu
     366       145847 :  Cryst%typat = typat
     367       391760 :  Cryst%xred  = xred
     368       107634 :  Cryst%zion  = zion
     369       107724 :  Cryst%znucl = znucl
     370       107634 :  Cryst%title = title
     371              : 
     372        31938 :  call Cryst%compute_geometry()
     373              : 
     374        31938 :  call Cryst%index_atoms()
     375              : 
     376              :  ! TODO: Make this more elegant
     377        31938 :  if (PRESENT(symrel).and.PRESENT(tnons).and.PRESENT(symafm)) then
     378        31938 :    if (.not.remove_inv) then
     379              :      ! Just a copy
     380      9726473 :      Cryst%symrel=symrel
     381      3036980 :      Cryst%tnons=tnons
     382       807149 :      Cryst%symafm=symafm
     383              :    else
     384              :      ! Remove inversion, just to be compatible with old GW implementation
     385              :      ! TODO should be removed!
     386            2 :      call remove_inversion(nsym,symrel,tnons,nsym_noI,symrel_noI,tnons_noI,pinv)
     387            2 :      Cryst%nsym=nsym_noI
     388            2 :      ABI_SFREE(Cryst%symrel)
     389            2 :      ABI_SFREE(Cryst%symrec)
     390            2 :      ABI_SFREE(Cryst%tnons)
     391            2 :      ABI_SFREE(Cryst%symafm)
     392            6 :      ABI_MALLOC(Cryst%symrel,(3,3,nsym_noI))
     393            4 :      ABI_MALLOC(Cryst%symrec,(3,3,nsym_noI))
     394            6 :      ABI_MALLOC(Cryst%tnons,(3,nsym_noI))
     395            6 :      ABI_MALLOC(Cryst%symafm,(nsym_noI))
     396          628 :      Cryst%symrel=symrel_noI
     397          196 :      Cryst%tnons=tnons_noI
     398           50 :      if (ANY(symafm==-1)) then
     399            0 :        ABI_BUG('Solve the problem with inversion before adding ferromagnetic symmetries')
     400              :      end if
     401           50 :      Cryst%symafm=1
     402            2 :      ABI_FREE(symrel_noI)
     403            4 :      ABI_FREE(tnons_noI)
     404              :    end if
     405              : 
     406              :  else
     407              :    ! Find symmetries symrec,symrel,tnons,symafm
     408              :    ! TODO This should be a wrapper around the abinit library whose usage is not so straightforward
     409            0 :    ABI_BUG('NotImplememented: symrel, symrec and tnons should be specied')
     410              :  end if
     411              : 
     412              :  ! Compute all symetries and construct tables.
     413        31938 :  call Cryst%compute_sym()
     414              : 
     415       127752 : end subroutine crystal_init
     416              : !!***
     417              : 
     418              : !----------------------------------------------------------------------
     419              : 
     420              : !!****f* m_crystal/crystal_without_symmetries
     421              : !! NAME
     422              : !!  crystal_without_symmetries
     423              : !!
     424              : !! FUNCTION
     425              : !!  Return new crystal_t object without symmetries (actually nsym = 1 and identity operation)
     426              : !!
     427              : !! INPUTS
     428              : !!
     429              : !! OUTPUT
     430              : !!
     431              : !! SOURCE
     432              : 
     433            0 : type(crystal_t) function crystal_without_symmetries(self) result(new)
     434              : 
     435              : !Arguments ------------------------------------
     436              :  class(crystal_t), intent(in) :: self
     437              : 
     438              : !Local variables-------------------------------
     439              :  integer,parameter :: timrev1 = 1, new_symafm(1) = 1
     440              :  real(dp),parameter :: new_tnons(3,1) = zero
     441              : ! *************************************************************************
     442              : 
     443              :  call new%init(self%amu, 1, self%natom, self%npsp, self%ntypat, 1, self%rprimd, self%typat, &
     444              :   self%xred, self%zion, self%znucl, timrev1, .False., .False., self%title, &
     445            0 :   symrel=identity_3d, tnons=new_tnons, symafm=new_symafm)
     446              : 
     447            0 : end function crystal_without_symmetries
     448              : !!***
     449              : 
     450              : !----------------------------------------------------------------------
     451              : 
     452              : !!****f* m_crystal/crystal_trinv_only
     453              : !! NAME
     454              : !!  crystal_trinv_only
     455              : !!
     456              : !! FUNCTION
     457              : ! ! Return new crystal_t without only identity, inversion and TR symmetries (if present)
     458              : !!
     459              : !! SOURCE
     460              : 
     461            0 : type(crystal_t) function crystal_trinv_only(self) result(new)
     462              : 
     463              : !Arguments ------------------------------------
     464              :  class(crystal_t), intent(in) :: self
     465              : 
     466              : !Local variables-------------------------------
     467              :  integer,parameter :: timrev2 = 2
     468              :  real(dp),parameter :: new_tnons(3,2) = zero
     469              :  integer :: inv_idx, new_symafm(2), new_symrel(3,3,2)
     470              : ! *************************************************************************
     471              : 
     472            0 :  inv_idx = self%idx_spatial_inversion()
     473            0 :  if (inv_idx == 0) then
     474              :    ! no spatial inversion
     475            0 :    new = self%new_without_symmetries(); new%timrev = timrev2
     476              :  else
     477              :    ! spatial inversion is present
     478            0 :    new_symrel(:,:,1) = identity_3d; new_symrel(:,:,2) = self%symrel(:,:,inv_idx)
     479            0 :    new_symafm(1) = 1; new_symafm(2) = self%symafm(inv_idx)
     480              : 
     481              :    call new%init(self%amu, 2, self%natom, self%npsp, self%ntypat, 2, self%rprimd, self%typat, &
     482              :      self%xred, self%zion, self%znucl, timrev2, .False., .False., self%title, &
     483            0 :      symrel=new_symrel, tnons=new_tnons, symafm=new_symafm)
     484              :  endif
     485              : 
     486            0 : end function crystal_trinv_only
     487              : !!***
     488              : 
     489              : !----------------------------------------------------------------------
     490              : 
     491              : !!****f* m_crystal/crystal_index_atoms
     492              : !! NAME
     493              : !!  crystal_index_atoms
     494              : !!
     495              : !! FUNCTION
     496              : !!  Generate index table of atoms, in order for them to be used type after type.
     497              : !!
     498              : !! SOURCE
     499              : 
     500        32339 : subroutine crystal_index_atoms(Cryst)
     501              : 
     502              : !Arguments ------------------------------------
     503              :  class(crystal_t),intent(inout) :: Cryst
     504              : 
     505              : !Local variables-------------------------------
     506              :  integer :: iat,indx,itypat
     507              : ! *********************************************************************
     508              : 
     509        32339 :  indx=1
     510        76644 :  do itypat=1,Cryst%ntypat
     511        44305 :    Cryst%nattyp(itypat)=0
     512       197888 :    do iat=1,Cryst%natom
     513       165549 :      if (Cryst%typat(iat)==itypat) then
     514        82757 :        Cryst%atindx (iat )=indx
     515        82757 :        Cryst%atindx1(indx)=iat
     516        82757 :        indx=indx+1
     517        82757 :        Cryst%nattyp(itypat)=Cryst%nattyp(itypat)+1
     518              :      end if
     519              :    end do
     520              :  end do
     521              : 
     522        32339 : end subroutine crystal_index_atoms
     523              : !!***
     524              : 
     525              : !----------------------------------------------------------------------
     526              : 
     527              : !!****f* m_crystal/crystal_compute_sym
     528              : !! NAME
     529              : !!  crystal_compute_sym
     530              : !!
     531              : !! FUNCTION
     532              : !!  Get symmetries in cartesian coordinates, construct rotation tables
     533              : !!  for atoms with and without spinor, and construct list of reducible atoms.
     534              : !!
     535              : !! SOURCE
     536              : 
     537        32339 : subroutine crystal_compute_sym(Cryst)
     538              : 
     539              : !Arguments ------------------------------------
     540              :  class(crystal_t),intent(inout) :: Cryst
     541              : 
     542              : !Local variables-------------------------------
     543              : !scalars
     544              :  integer :: iat,indx,isym
     545              :  real(dp) :: tolsym8
     546        32339 :  logical, allocatable :: irredat_tmp(:)
     547              : !arrays
     548              :  integer :: symrec(3,3)
     549              : ! *********************************************************************
     550              : 
     551              :  ! Get symmetries in reciprocal space
     552       785523 :  do isym=1,Cryst%nsym
     553       753184 :    call mati3inv(Cryst%symrel(:,:,isym),symrec)
     554      9823731 :    Cryst%symrec(:,:,isym)=symrec
     555              :  end do
     556              : 
     557              :  ! Get symmetries in cartesian coordinates
     558       785523 :  do isym =1,Cryst%nsym
     559       753184 :    call symredcart(Cryst%rprimd, Cryst%gprimd, Cryst%symrel_cart(:,:,isym), Cryst%symrel(:,:,isym))
     560              :    ! purify operations in cartesian coordinates.
     561      9823731 :    where (abs(Cryst%symrel_cart(:,:,isym)) < tol14)
     562              :      Cryst%symrel_cart(:,:,isym) = zero
     563              :    end where
     564              :  end do
     565              : 
     566              :  ! === Obtain a list of rotated atoms ===
     567              :  ! $ R^{-1} (xred(:,iat)-\tau) = xred(:,iat_sym) + R_0 $
     568              :  ! * indsym(4,  isym,iat) gives iat_sym in the original unit cell.
     569              :  ! * indsym(1:3,isym,iat) gives the lattice vector $R_0$.
     570              :  !
     571        32339 :  tolsym8=tol8
     572        32339 :  call symatm(Cryst%indsym, Cryst%natom, Cryst%nsym, Cryst%symrec, Cryst%tnons, tolsym8, Cryst%typat, Cryst%xred)
     573              : 
     574              :  ! Rotations in spinor space
     575       785523 :  do isym=1,Cryst%nsym
     576       785523 :    call getspinrot(Cryst%rprimd, Cryst%spinrot(:,isym), Cryst%symrel(:,:,isym))
     577              :  end do
     578              : 
     579              :  ! Find list of irreducible atoms by using the indsym
     580        97017 :  ABI_MALLOC(irredat_tmp, (Cryst%natom))
     581       115096 :  irredat_tmp = .TRUE.
     582              : 
     583        32339 :  Cryst%nirredat = 0
     584       115096 :  do iat = 1,Cryst%natom
     585       115096 :    if(irredat_tmp(iat))then
     586        65172 :       Cryst%nirredat = Cryst%nirredat + 1
     587      1037801 :       do isym = 1,Cryst%nsym
     588      1037801 :          if (Cryst%indsym(4,isym,iat) /= iat)then
     589       248167 :            irredat_tmp(Cryst%indsym(4,isym,iat)) = .FALSE.
     590              :          endif
     591              :       enddo
     592              :    endif
     593              :  enddo
     594              : 
     595              :  ! Write indexes of irreducible atoms
     596        97017 :  ABI_MALLOC(Cryst%irredatindx, (Cryst%nirredat))
     597        32339 :  indx = 0
     598       115096 :  do iat = 1,Cryst%natom
     599       115096 :     if (irredat_tmp(iat)) then
     600        65172 :       indx = indx + 1
     601        65172 :       cryst%irredatindx(indx) = iat
     602              :     endif
     603              :  enddo
     604              : 
     605        32339 :  ABI_SFREE(irredat_tmp)
     606              : 
     607        32339 : end subroutine crystal_compute_sym
     608              : !!***
     609              : 
     610              : !----------------------------------------------------------------------
     611              : 
     612              : !!****f* m_crystal/crystal_compute_geometry
     613              : !! NAME
     614              : !!  crystal_compute_geometry
     615              : !!
     616              : !! FUNCTION
     617              : !!  Compute the different metrics and the angle between primitive vectors.
     618              : !!  Also compute cartesian coordinates of atoms.
     619              : !!
     620              : !! SOURCE
     621              : 
     622        32339 : subroutine crystal_compute_geometry(Cryst)
     623              : 
     624              : !Arguments ------------------------------------
     625              :  class(crystal_t),intent(inout) :: Cryst
     626              : ! *********************************************************************
     627              : 
     628        32339 :  call metric(Cryst%gmet,Cryst%gprimd,-1,Cryst%rmet,Cryst%rprimd,Cryst%ucvol)
     629              : 
     630        32339 :  Cryst%angdeg(1)=ACOS(Cryst%rmet(2,3)/SQRT(Cryst%rmet(2,2)*Cryst%rmet(3,3)))/two_pi*360.0d0
     631        32339 :  Cryst%angdeg(2)=ACOS(Cryst%rmet(1,3)/SQRT(Cryst%rmet(1,1)*Cryst%rmet(3,3)))/two_pi*360.0d0
     632        32339 :  Cryst%angdeg(3)=ACOS(Cryst%rmet(1,2)/SQRT(Cryst%rmet(1,1)*Cryst%rmet(2,2)))/two_pi*360.0d0
     633              : 
     634        32339 :  call xred2xcart(Cryst%natom,Cryst%rprimd,Cryst%xcart,Cryst%xred)
     635              : 
     636        32339 : end subroutine crystal_compute_geometry
     637              : !!***
     638              : 
     639              : !----------------------------------------------------------------------
     640              : 
     641              : !!****f* m_crystal/crystal_malloc
     642              : !! NAME
     643              : !!  crystal_malloc
     644              : !!
     645              : !! FUNCTION
     646              : !!  Allocate the dynamic arrays in a crystal_t data type.
     647              : !!
     648              : !! SOURCE
     649              : 
     650        32884 : subroutine crystal_malloc(Cryst)
     651              : 
     652              : !Arguments ------------------------------------
     653              :  class(crystal_t),intent(inout) :: Cryst
     654              : 
     655              : !Local variables-------------------------------
     656              :  integer :: ii
     657              : ! *********************************************************************
     658              : 
     659              : !integer
     660        98652 :  ABI_MALLOC(Cryst%typat,(Cryst%natom))
     661        98652 :  ABI_MALLOC(Cryst%xred,(3,Cryst%natom))
     662        65768 :  ABI_MALLOC(Cryst%xcart,(3,Cryst%natom))
     663        98652 :  ABI_MALLOC(Cryst%zion,(Cryst%ntypat))
     664        98652 :  ABI_MALLOC(Cryst%znucl,(Cryst%npsp))
     665        65768 :  ABI_MALLOC(Cryst%amu, (Cryst%ntypat))
     666              : 
     667        98652 :  ABI_MALLOC(Cryst%symrel,(3,3,Cryst%nsym))
     668        65768 :  ABI_MALLOC(Cryst%symrec,(3,3,Cryst%nsym))
     669        98652 :  ABI_MALLOC(Cryst%tnons,(3,Cryst%nsym))
     670        98652 :  ABI_MALLOC(Cryst%symafm,(Cryst%nsym))
     671        98652 :  ABI_MALLOC(Cryst%symrel_cart, (3, 3, Cryst%nsym))
     672       131536 :  ABI_MALLOC(Cryst%indsym,(4, Cryst%nsym, Cryst%natom))
     673              : 
     674        65768 :  ABI_MALLOC(Cryst%atindx,(Cryst%natom))
     675        65768 :  ABI_MALLOC(Cryst%atindx1,(Cryst%natom))
     676        98652 :  ABI_MALLOC(Cryst%nattyp,(Cryst%ntypat))
     677        98652 :  ABI_MALLOC(Cryst%spinrot, (4, Cryst%nsym))
     678              : 
     679        98652 :  ABI_MALLOC(Cryst%title,(Cryst%ntypat))
     680              : 
     681              :  ! nirredat must first be computed from indsym
     682              :  !ABI_MALLOC(Cryst%irredatindx,(Cryst%nirredat))
     683              : 
     684       117047 :  Cryst%typat = zero
     685       369536 :  Cryst%xred = zero
     686       369536 :  Cryst%xcart = zero
     687        78115 :  Cryst%zion = zero
     688        78205 :  Cryst%znucl = zero
     689        78115 :  Cryst%amu = zero
     690     10063060 :  Cryst%symrel = zero
     691     10063060 :  Cryst%symrec = zero
     692      3119092 :  Cryst%tnons = zero
     693       804436 :  Cryst%symafm = zero
     694     10063060 :  Cryst%symrel_cart = zero
     695      8604972 :  Cryst%indsym = zero
     696       117047 :  Cryst%atindx = zero
     697       117047 :  Cryst%atindx1 = zero
     698        78115 :  Cryst%nattyp = zero
     699      3890644 :  Cryst%spinrot = zero
     700              : 
     701        78115 :  do ii=1,Cryst%ntypat
     702        78115 :    Cryst%title(ii) = ''
     703              :  end do
     704              : 
     705        32884 : end subroutine crystal_malloc
     706              : !!***
     707              : 
     708              : !----------------------------------------------------------------------
     709              : 
     710              : !!****f* m_crystal/crystal_free
     711              : !! NAME
     712              : !!  crystal_free
     713              : !!
     714              : !! FUNCTION
     715              : !!  Free dynamic memory in a crystal_t data type.
     716              : !!
     717              : !! SOURCE
     718              : 
     719        66144 : subroutine crystal_free(Cryst)
     720              : 
     721              : !Arguments ------------------------------------
     722              :  class(crystal_t),intent(inout) :: Cryst
     723              : ! *********************************************************************
     724              : 
     725              : !integer
     726        66144 :  ABI_SFREE(Cryst%indsym)
     727        66144 :  ABI_SFREE(Cryst%symafm)
     728        66144 :  ABI_SFREE(Cryst%symrec)
     729        66144 :  ABI_SFREE(Cryst%symrel)
     730        66144 :  ABI_SFREE(Cryst%symrel_cart)
     731        66144 :  ABI_SFREE(Cryst%atindx)
     732        66144 :  ABI_SFREE(Cryst%atindx1)
     733        66144 :  ABI_SFREE(Cryst%typat)
     734        66144 :  ABI_SFREE(Cryst%nattyp)
     735        66144 :  ABI_SFREE(Cryst%irredatindx)
     736              : 
     737              : !real
     738        66144 :  ABI_SFREE(Cryst%tnons)
     739        66144 :  ABI_SFREE(Cryst%xcart)
     740        66144 :  ABI_SFREE(Cryst%xred)
     741        66144 :  ABI_SFREE(Cryst%zion)
     742        66144 :  ABI_SFREE(Cryst%znucl)
     743        66144 :  ABI_SFREE(Cryst%amu)
     744        66144 :  ABI_SFREE(Cryst%spinrot)
     745              : 
     746              : !character
     747        66144 :  ABI_SFREE(Cryst%title)
     748              : 
     749        66144 : end subroutine crystal_free
     750              : !!***
     751              : 
     752              : !----------------------------------------------------------------------
     753              : 
     754              : !!****f* m_crystal/crystal_copy
     755              : !! NAME
     756              : !!  crystal_copy
     757              : !!
     758              : !! FUNCTION
     759              : !!  Copy the object.
     760              : !!
     761              : !! OUTPUTS
     762              : !!  new = A new crystal instance
     763              : !!
     764              : !! SOURCE
     765              : 
     766          529 : subroutine crystal_copy(Cryst, new)
     767              : 
     768              : !Arguments ------------------------------------
     769              :  class(crystal_t),intent(in) :: Cryst
     770              :  class(crystal_t),intent(out) :: new
     771              : ! *********************************************************************
     772              : 
     773              :  ! Copy dimensions, scalar variables, and static arrays
     774          529 :  new%natom = Cryst%natom
     775          529 :  new%nsym = Cryst%nsym
     776          529 :  new%ntypat = Cryst%ntypat
     777          529 :  new%nirredat = Cryst%nirredat
     778          529 :  new%npsp = Cryst%npsp
     779          529 :  new%space_group = Cryst%space_group
     780          529 :  new%timrev = Cryst%timrev
     781          529 :  new%ucvol = Cryst%ucvol
     782          529 :  new%use_antiferro = Cryst%use_antiferro
     783         2116 :  new%angdeg = Cryst%angdeg
     784         6877 :  new%gmet = Cryst%gmet
     785         6877 :  new%gprimd = Cryst%gprimd
     786         6877 :  new%rmet = Cryst%rmet
     787         6877 :  new%rprimd = Cryst%rprimd
     788              : 
     789              :  ! Allocate memory
     790          529 :  call new%malloc()
     791          529 :  if (allocated(Cryst%irredatindx)) then
     792         1563 :    ABI_MALLOC(new%irredatindx,(new%nirredat))
     793              :  end if
     794              : 
     795              :  ! Copy dynamic arrays
     796       198482 :  new%indsym = Cryst%indsym
     797        18946 :  new%symafm = Cryst%symafm
     798       233602 :  new%symrec = Cryst%symrec
     799       233602 :  new%symrel = Cryst%symrel
     800       233602 :  new%symrel_cart = Cryst%symrel_cart
     801         2392 :  new%atindx = Cryst%atindx
     802         2392 :  new%atindx1 = Cryst%atindx1
     803         2392 :  new%typat = Cryst%typat
     804         1944 :  new%nattyp = Cryst%nattyp
     805        72610 :  new%tnons = Cryst%tnons
     806         6394 :  new%xcart = Cryst%xcart
     807         6394 :  new%xred = Cryst%xred
     808        90498 :  new%spinrot = Cryst%spinrot
     809         1944 :  new%amu = Cryst%amu
     810         1944 :  new%zion = Cryst%zion
     811         1944 :  new%znucl = Cryst%znucl
     812         1944 :  new%title = Cryst%title
     813          529 :  if (allocated(Cryst%irredatindx)) then
     814         2054 :    new%irredatindx = Cryst%irredatindx
     815              :  end if
     816              : 
     817          529 : end subroutine crystal_copy
     818              : !!***
     819              : 
     820              : !----------------------------------------------------------------------
     821              : 
     822              : !!****f* m_crystal/crystal_bcast
     823              : !! NAME
     824              : !!  crystal_bcast
     825              : !!
     826              : !! FUNCTION
     827              : !!  Master broadcasts data and others allocate their arrays.
     828              : !!
     829              : !! SOURCE
     830              : 
     831           24 : subroutine crystal_bcast(Cryst, comm)
     832              : 
     833              : !Arguments ------------------------------------
     834              :  class(crystal_t),intent(inout) :: Cryst
     835              :  integer, intent(in) :: comm
     836              : 
     837              : !Local variables -------------------------
     838              :  integer, parameter :: master=0
     839              :  integer :: ierr
     840              : ! *********************************************************************
     841              : 
     842           24 :  if (xmpi_comm_size(comm) == 1) return
     843              : 
     844              :  DBG_ENTER("COLL")
     845              : 
     846              :  ! Integers
     847           24 :  call xmpi_bcast(Cryst%natom, master, comm, ierr)
     848           24 :  call xmpi_bcast(Cryst%nsym, master, comm, ierr)
     849           24 :  call xmpi_bcast(Cryst%ntypat, master, comm, ierr)
     850           24 :  call xmpi_bcast(Cryst%nirredat, master, comm, ierr)
     851           24 :  call xmpi_bcast(Cryst%npsp, master, comm, ierr)
     852           24 :  call xmpi_bcast(Cryst%space_group, master, comm, ierr)
     853           24 :  call xmpi_bcast(Cryst%timrev, master, comm, ierr)
     854           24 :  call xmpi_bcast(Cryst%use_antiferro, master, comm, ierr)
     855              : 
     856           24 :  if (xmpi_comm_rank(comm) /= master) then
     857           16 :    call Cryst%free()
     858           16 :    call Cryst%malloc()
     859              :  end if
     860              : 
     861              :  ! Floats
     862           24 :  call xmpi_bcast(Cryst%ucvol, master, comm, ierr)
     863              : 
     864              :  ! Arrays
     865           24 :  call xmpi_bcast(Cryst%angdeg, master, comm, ierr)
     866           24 :  call xmpi_bcast(Cryst%gmet, master, comm, ierr)
     867           24 :  call xmpi_bcast(Cryst%gprimd, master, comm, ierr)
     868           24 :  call xmpi_bcast(Cryst%rmet, master, comm, ierr)
     869           24 :  call xmpi_bcast(Cryst%rprimd, master, comm, ierr)
     870           24 :  call xmpi_bcast(Cryst%indsym, master, comm, ierr)
     871           24 :  call xmpi_bcast(Cryst%symafm, master, comm, ierr)
     872           24 :  call xmpi_bcast(Cryst%symrec, master, comm, ierr)
     873           24 :  call xmpi_bcast(Cryst%symrel, master, comm, ierr)
     874           24 :  call xmpi_bcast(Cryst%symrel_cart, master, comm, ierr)
     875           24 :  call xmpi_bcast(Cryst%atindx, master, comm, ierr)
     876           24 :  call xmpi_bcast(Cryst%atindx1, master, comm, ierr)
     877           24 :  call xmpi_bcast(Cryst%typat, master, comm, ierr)
     878           24 :  call xmpi_bcast(Cryst%nattyp, master, comm, ierr)
     879           24 :  call xmpi_bcast(Cryst%tnons, master, comm, ierr)
     880           24 :  call xmpi_bcast(Cryst%xcart, master, comm, ierr)
     881           24 :  call xmpi_bcast(Cryst%xred, master, comm, ierr)
     882           24 :  call xmpi_bcast(Cryst%spinrot, master, comm, ierr)
     883           24 :  call xmpi_bcast(Cryst%amu, master, comm, ierr)
     884           24 :  call xmpi_bcast(Cryst%zion, master, comm, ierr)
     885           24 :  call xmpi_bcast(Cryst%znucl, master, comm, ierr)
     886           24 :  call xmpi_bcast(Cryst%title, master, comm, ierr)
     887              : 
     888              :  ! It is not always allocated on master node,
     889              :  ! and it can be computed afterward on each node.
     890              :  !call xmpi_bcast(Cryst%irredatindx, master, comm, ierr)
     891              : 
     892              :  DBG_EXIT("COLL")
     893              : 
     894              : end subroutine crystal_bcast
     895              : !!***
     896              : 
     897              : !----------------------------------------------------------------------
     898              : 
     899              : !!****f* m_crystal/crystal_compare
     900              : !! NAME
     901              : !!  crystal_compare
     902              : !!
     903              : !! FUNCTION
     904              : !!   Compare two crystalline structures,
     905              : !!   write warning messages to stdout if they differ, return exit status
     906              : !!
     907              : !! INPUTS
     908              : !!  [header]=Optional header message.
     909              : !!
     910              : !! OUTPUT
     911              : !!
     912              : !! SOURCE
     913              : 
     914          258 : integer function crystal_compare(self, other, header) result(ierr)
     915              : 
     916              : !Arguments ------------------------------------
     917              :  class(crystal_t),intent(in) :: self, other
     918              :  character(len=*),optional,intent(in) :: header
     919              : 
     920              : !Local variables-------------------------------
     921              :  !integer :: isym, iat, itypat
     922              : ! *********************************************************************
     923              : 
     924          258 :  if (present(header)) call wrtout(std_out, header)
     925          258 :  ierr = 0
     926              : 
     927              :  ! Test basic dimensions and metadata.
     928          258 :  ABI_CHECK_IEQ_IERR(self%natom, other%natom, "Different natom" , ierr)
     929          258 :  ABI_CHECK_IEQ_IERR(self%ntypat, other%ntypat, "Different ntypat" , ierr)
     930          258 :  ABI_CHECK_IEQ_IERR(self%npsp, other%npsp, "Different npsp" , ierr)
     931          258 :  ABI_CHECK_IEQ_IERR(self%nsym, other%nsym, "Different nsym" , ierr)
     932          258 :  ABI_CHECK_IEQ_IERR(self%timrev, other%timrev, "Different timrev" , ierr)
     933              : 
     934          258 :  if (ierr /= 0) goto 10
     935              :  ! After this point, we know that basic dimensions agree with each other.
     936              :  ! Yes, I use GOTO and I'm proud of that!
     937              : 
     938              :  ! Check direct lattice
     939         3354 :  if (any(abs(self%rprimd - other%rprimd) > tol6)) then
     940            0 :    ABI_WARNING("Found critical diffs in rprimd lattice vectors.")
     941            0 :    ierr = ierr + 1
     942              :  end if
     943              : 
     944              :  ! Check Symmetries
     945       145234 :  if (any(self%symrel /= other%symrel)) then
     946            0 :    ABI_WARNING("Found critical diffs in symrel symmetries.")
     947            0 :    ierr = ierr + 1
     948              :  end if
     949        44866 :  if (any(abs(self%tnons - other%tnons) > tol3)) then
     950            0 :    ABI_WARNING("Found critical diffs in fractional translations tnons.")
     951            0 :    ierr = ierr + 1
     952              :  end if
     953          258 :  if (self%use_antiferro .neqv. other%use_antiferro) then
     954            0 :    ABI_WARNING("Different values of use_antiferro")
     955            0 :    ierr = ierr + 1
     956              :  end if
     957              : 
     958              :  ! Atoms
     959          754 :  if (any(self%typat /= other%typat)) then
     960            0 :    ABI_WARNING("Found critical diffs in typat.")
     961              :    !print *, self%typat; print *, other%typat
     962            0 :    ierr = ierr + 1
     963              :  end if
     964          648 :  if (any(abs(self%zion - other%zion) > tol3)) then
     965            0 :    ABI_WARNING("Found critical diffs in zion.")
     966            0 :    ierr = ierr + 1
     967              :  end if
     968          648 :  if (any(abs(self%znucl - other%znucl) > tol3)) then
     969            0 :    ABI_WARNING("Found critical diffs in znucl.")
     970            0 :    ierr = ierr + 1
     971              :  end if
     972          648 :  if (any(abs(self%amu - other%amu) > tol3)) then
     973            0 :    ABI_WARNING("Found critical diffs in amu.")
     974            0 :    ierr = ierr + 1
     975              :  end if
     976         2242 :  if (any(abs(self%xred - other%xred) > tol6)) then
     977            0 :    ABI_WARNING("Found critical diffs in xred.")
     978            0 :    ierr = ierr + 1
     979              :  end if
     980              : 
     981          258 :  if (ierr /= 0) goto 10
     982            0 :  return
     983              : 
     984              :  ! Print structure to aid debugging. Caller will handle exit status.
     985            0 : 10 call wrtout(std_out, " Comparing crystal1 and crystal2 for possible differences before returning ierr /= 0!")
     986            0 :    call self%print(header="crystal1")
     987            0 :    call wrtout(std_out, "")
     988            0 :    call other%print(header="crystal2")
     989            0 :    call wrtout(std_out, "")
     990              : 
     991            0 : end function crystal_compare
     992              : !!***
     993              : 
     994              : !----------------------------------------------------------------------
     995              : 
     996              : !!****f* m_crystal/crystal_print
     997              : !! NAME
     998              : !!  crystal_print
     999              : !!
    1000              : !! FUNCTION
    1001              : !!  Print the content of crystal_t data type
    1002              : !!
    1003              : !! INPUTS
    1004              : !!  Cryst<crystal_t>=The structure.
    1005              : !!  [unit]=Unit number for output. Defaults to std_out
    1006              : !!  [prtvol]=Verbosity level. If prtvol== -1, only lattice parameters are printed. Defaults to 0
    1007              : !!  [mode_paral]=Either "COLL" or "PERS"
    1008              : !!  [header]=String to be printed as header for additional info.
    1009              : !!
    1010              : !! OUTPUT
    1011              : !!  Only printing
    1012              : !!
    1013              : !! SOURCE
    1014              : 
    1015         1232 : subroutine crystal_print(Cryst, header, unit, mode_paral, prtvol)
    1016              : 
    1017              : !Arguments ------------------------------------
    1018              : !scalars
    1019              :  class(crystal_t),intent(in) :: Cryst
    1020              :  integer,optional,intent(in) :: unit, prtvol
    1021              :  character(len=*),optional,intent(in) :: mode_paral
    1022              :  character(len=*),optional,intent(in) :: header
    1023              : 
    1024              : !Local variables-------------------------------
    1025              :  integer :: my_unt,my_prtvol,nu,iatom, isym, ii, nsym, units(1)
    1026              :  character(len=4) :: my_mode
    1027              :  character(len=500) :: msg
    1028              : ! *********************************************************************
    1029              : 
    1030          694 :  my_unt   =std_out; if (PRESENT(unit      )) my_unt   =unit
    1031         1232 :  my_prtvol=0      ; if (PRESENT(prtvol    )) my_prtvol=prtvol
    1032         1232 :  my_mode  ='COLL' ; if (PRESENT(mode_paral)) my_mode  =mode_paral
    1033              : 
    1034         2464 :  units = [my_unt]
    1035              : 
    1036         1232 :  msg=' ==== Info on the Cryst% object ==== '
    1037         1232 :  if (PRESENT(header)) msg=' ==== '//TRIM(ADJUSTL(header))//' ==== '
    1038         1232 :  call wrtout(my_unt, sjoin(ch10, msg), my_mode)
    1039              : 
    1040         1232 :  write(msg,'(a)')' Real(R)+Recip(G) space primitive vectors, cartesian coordinates (Bohr,Bohr^-1):'
    1041         1232 :  call wrtout(my_unt,msg,my_mode)
    1042         4928 :  do nu=1,3
    1043              :    write(msg,'(1x,a,i1,a,3f11.7,2x,a,i1,a,3f11.7)')&
    1044        14784 :     'R(',nu,')=',Cryst%rprimd(:,nu)+tol10, &
    1045        18480 :     'G(',nu,')=',Cryst%gprimd(:,nu)+tol10  ! tol10 is used to be consistent with metric.F90
    1046         4928 :    call wrtout(my_unt,msg,my_mode)
    1047              :  end do
    1048              : 
    1049         1232 :  write(msg,'(a,1p,e15.7,a)')' Unit cell volume ucvol=',Cryst%ucvol+tol10,' bohr^3'
    1050         1232 :  call wrtout(my_unt,msg,my_mode)
    1051              : 
    1052         1232 :  write(msg,'(a,3es16.8,a)')' Angles (23,13,12)=',Cryst%angdeg(1:3),' degrees'
    1053         1232 :  call wrtout(my_unt,msg,my_mode)
    1054              : 
    1055         1232 :  if (Cryst%timrev==1) then
    1056          198 :    msg = ' Time-reversal symmetry is not present '
    1057         1034 :  else if (Cryst%timrev==2) then
    1058         1034 :    msg = ' Time-reversal symmetry is present '
    1059              :  else
    1060            0 :    ABI_BUG(sjoin('Wrong value for timrev:', itoa(cryst%timrev)))
    1061              :  end if
    1062         1232 :  call wrtout(my_unt,msg,my_mode)
    1063         1232 :  if (my_prtvol == -1) return
    1064              : 
    1065         1229 :  if (my_prtvol > 0) then
    1066            0 :    call print_symmetries(units, Cryst%nsym, Cryst%symrel, Cryst%tnons, Cryst%symafm)
    1067            0 :    if (Cryst%use_antiferro) call wrtout(my_unt,' System has magnetic symmetries ',my_mode)
    1068              : 
    1069              :    ! Print indsym using the same format as in symatm
    1070            0 :    nsym = cryst%nsym
    1071            0 :    do iatom=1,cryst%natom
    1072            0 :      write(msg, '(a,i0,a)' )' symatm: atom number ',iatom,' is reached starting at atom'
    1073            0 :      call wrtout(std_out, msg)
    1074            0 :      do ii=1,(nsym-1)/24+1
    1075            0 :        if (cryst%natom<100) then
    1076            0 :          write(msg, '(1x,24i3)' ) (cryst%indsym(4,isym,iatom),isym=1+(ii-1)*24,min(nsym,ii*24))
    1077              :        else
    1078            0 :          write(msg, '(1x,24i6)' ) (cryst%indsym(4,isym,iatom),isym=1+(ii-1)*24,min(nsym,ii*24))
    1079              :        end if
    1080            0 :        call wrtout(std_out, msg)
    1081              :      end do
    1082              :    end do
    1083              : 
    1084              :  end if
    1085              : 
    1086         1229 :  call wrtout(my_unt, " Reduced atomic positions [iatom, xred, symbol]:", my_mode)
    1087         4242 :  do iatom=1,cryst%natom
    1088         3013 :    write(msg,"(i5,a,2x,3f11.7,2x,a)")iatom,")",cryst%xred(:,iatom), cryst%symbol_type(cryst%typat(iatom))
    1089         4242 :    call wrtout(my_unt,msg,my_mode)
    1090              :  end do
    1091              : 
    1092         1232 : end subroutine crystal_print
    1093              : !!***
    1094              : 
    1095              : !!****f* m_crystal/crystal_print_abivars
    1096              : !! NAME
    1097              : !!  crystal_print_abivars
    1098              : !!
    1099              : !! FUNCTION
    1100              : !!   Print unit cell info in Abinit/abivars format
    1101              : !!
    1102              : !! INPUTS
    1103              : !!  unit=Output unit
    1104              : !!
    1105              : !! OUTPUT
    1106              : !!  Only printing
    1107              : !!
    1108              : !! SOURCE
    1109              : 
    1110            0 : subroutine crystal_print_abivars(cryst, unit)
    1111              : 
    1112              : !Arguments ------------------------------------
    1113              : !scalars
    1114              :  class(crystal_t),intent(in) :: cryst
    1115              :  integer,intent(in) :: unit
    1116              : 
    1117              : !Local variables-------------------------------
    1118              :  integer :: iatom, ii
    1119              :  !character(len=500) :: fmt
    1120              : ! *********************************************************************
    1121              : 
    1122            0 :  if (unit == dev_null) return
    1123              : 
    1124              :  ! Write variables using standard Abinit input format.
    1125            0 :  write(unit, "(/,/,a)")" # Abinit variables"
    1126            0 :  write(unit, "(a)")" acell 1.0 1.0 1.0"
    1127            0 :  write(unit, "(a)")" rprimd"
    1128            0 :  do ii=1,3
    1129            0 :     write(unit, "(3(f11.7,1x))")cryst%rprimd(:, ii)
    1130              :  end do
    1131            0 :  write(unit, "(a, i0)")" natom ", cryst%natom
    1132            0 :  write(unit, "(a, i0)")" ntypat ", cryst%ntypat
    1133            0 :  write(unit, strcat("(a, ", itoa(cryst%natom), "(i0,1x))")) " typat ", cryst%typat
    1134            0 :  write(unit, strcat("(a, ", itoa(cryst%npsp), "(f5.1,1x))")) " znucl ", cryst%znucl
    1135            0 :  write(unit, "(a)")" xred"
    1136            0 :  do iatom=1,cryst%natom
    1137            0 :    write(unit,"(1x, 3f11.7,2x,2a)")cryst%xred(:,iatom), " # ", cryst%symbol_type(cryst%typat(iatom))
    1138              :  end do
    1139              : 
    1140              :  ! Write variables using the abivars format supported by structure variable.
    1141              :  !write(unit, "(/,/,a)")" # Abivars format (external file with structure variable)"
    1142              :  !write(unit, "(a)")" acell 1.0 1.0 1.0"
    1143              :  !write(unit, "(a)")" rprimd"
    1144              :  !do ii=1,3
    1145              :  !   write(unit, "(1x, 3(f11.7,1x))")cryst%rprimd(:, ii)
    1146              :  !end do
    1147              :  !write(unit, "(a, i0)")" natom ", cryst%natom
    1148              :  !write(unit, "(a)")" xred_symbols"
    1149              :  !do iatom=1,cryst%natom
    1150              :  !  write(unit,"(1x, 3f11.7,2x,a)")cryst%xred(:,iatom), cryst%symbol_type(cryst%typat(iatom))
    1151              :  !end do
    1152              : 
    1153              : end subroutine crystal_print_abivars
    1154              : !!***
    1155              : 
    1156              : !----------------------------------------------------------------------
    1157              : 
    1158              : !!****f* m_crystal/symbols_crystal
    1159              : !!
    1160              : !! NAME
    1161              : !! symbols_crystal
    1162              : !!
    1163              : !! FUNCTION
    1164              : !! Return a array with the symbol of each atoms with indexation e.g.
    1165              : !! ["Sr","Ru","O1","O2","O3"]
    1166              : !!
    1167              : !! INPUTS
    1168              : !! natom = number of atoms
    1169              : !! ntypat = number of typat
    1170              : !! npsp =  number of pseudopotentials
    1171              : !! znucl = Nuclear charge for each type of pseudopotential
    1172              : !!
    1173              : !! OUTPUT
    1174              : !! symbols = array with the symbol of each atoms
    1175              : !!
    1176              : !! SOURCE
    1177              : 
    1178          104 : subroutine symbols_crystal(natom, ntypat, npsp, symbols, typat, znucl)
    1179              : 
    1180              : !Arguments ------------------------------------
    1181              : !scalars
    1182              :  integer,intent(in) :: natom,ntypat,npsp
    1183              : !arrays
    1184              :  real(dp),intent(in):: znucl(npsp)
    1185              :  integer,intent(in) :: typat(natom)
    1186              :  character(len=5),intent(out) :: symbols(natom)
    1187              :  character(len=3) :: powerchar
    1188              : 
    1189              : !Local variables-------------------------------
    1190              : !scalar
    1191              :  integer :: ia,ii,itypat,jj
    1192              : ! *************************************************************************
    1193              : 
    1194              :  ! Fill the symbols array
    1195          624 :  do ia=1,natom
    1196          624 :    symbols(ia) = adjustl(znucl2symbol(znucl(typat(ia))))
    1197              :  end do
    1198          104 :  itypat = 0
    1199          416 :  do itypat =1,ntypat
    1200              :    ii = 0
    1201         1872 :    do ia=1,natom
    1202         1872 :      if(typat(ia)==itypat) then
    1203          520 :        ii = ii + 1
    1204              :      end if
    1205              :    end do
    1206          416 :    if(ii>1)then
    1207          104 :      jj=1
    1208          624 :      do ia=1,natom
    1209          624 :        if(typat(ia)==itypat) then
    1210          312 :          write(powerchar,'(I0)') jj
    1211          312 :          symbols(ia) = trim(symbols(ia))//trim(powerchar)
    1212          312 :          jj=jj+1
    1213              :        end if
    1214              :      end do
    1215              :    end if
    1216              :  end do
    1217              : 
    1218          104 : end subroutine symbols_crystal
    1219              : !!***
    1220              : 
    1221              : !----------------------------------------------------------------------
    1222              : 
    1223              : !!****f* m_crystal/idx_spatial_inversion
    1224              : !! NAME
    1225              : !!  idx_spatial_inversion
    1226              : !!
    1227              : !! FUNCTION
    1228              : !!  Return the index of the spatial inversion, 0 if not present
    1229              : !!
    1230              : !! SOURCE
    1231              : 
    1232           18 : pure integer function idx_spatial_inversion(Cryst) result(inv_idx)
    1233              : 
    1234              : !Arguments ------------------------------------
    1235              :  class(crystal_t),intent(in) :: Cryst
    1236              : 
    1237              : !Local variables-------------------------------
    1238              :  integer :: isym
    1239              : ! *************************************************************************
    1240              : 
    1241           18 :  inv_idx=0
    1242          427 :  do isym=1,cryst%nsym
    1243          677 :    if (all(cryst%symrel(:,:,isym) == inversion_3d)) then
    1244           18 :     inv_idx=isym; return
    1245              :    end if
    1246              :  end do
    1247              : 
    1248              : end function idx_spatial_inversion
    1249              : !!***
    1250              : 
    1251              : !----------------------------------------------------------------------
    1252              : 
    1253              : !!****f* m_crystal/isymmorphic
    1254              : !! NAME
    1255              : !!  isymmorphic
    1256              : !!
    1257              : !! FUNCTION
    1258              : !!  Returns .TRUE. if space group is symmorphic, i.e. all fractional translations are zero.
    1259              : !!
    1260              : !! SOURCE
    1261              : 
    1262        18636 : pure logical function isymmorphic(Cryst) result(ans)
    1263              : 
    1264              : !Arguments ------------------------------------
    1265              :  class(crystal_t),intent(in) :: Cryst
    1266              : ! *************************************************************************
    1267              : 
    1268      1030544 :  ans = ALL(ABS(Cryst%tnons) < tol6)
    1269              : 
    1270        18636 : end function isymmorphic
    1271              : !!***
    1272              : 
    1273              : !----------------------------------------------------------------------
    1274              : 
    1275              : !!****f* m_crystal/isalchemical
    1276              : !! NAME
    1277              : !!  isalchemical
    1278              : !!
    1279              : !! FUNCTION
    1280              : !!  Returns .TRUE. if we are using alchemical pseudopotentials
    1281              : !!
    1282              : !! SOURCE
    1283              : 
    1284        18636 : pure logical function isalchemical(Cryst) result(ans)
    1285              : 
    1286              : !Arguments ------------------------------------
    1287              :  class(crystal_t),intent(in) :: Cryst
    1288              : ! *************************************************************************
    1289              : 
    1290        18636 :  ans = (Cryst%npsp /= Cryst%ntypat)
    1291              : 
    1292        18636 : end function isalchemical
    1293              : !!***
    1294              : 
    1295              : !----------------------------------------------------------------------
    1296              : 
    1297              : !!****f* m_crystal/adata_type
    1298              : !! NAME
    1299              : !!  adata_type
    1300              : !!
    1301              : !! FUNCTION
    1302              : !!  Return atomic data from the itypat index
    1303              : !!
    1304              : !! SOURCE
    1305              : 
    1306        18574 : type(atomdata_t) function adata_type(crystal, itypat) result(atom)
    1307              : 
    1308              : !Arguments ------------------------------------
    1309              :  class(crystal_t),intent(in) :: crystal
    1310              :  integer,intent(in) :: itypat
    1311              : ! *************************************************************************
    1312              : 
    1313        18574 :  call atomdata_from_znucl(atom, crystal%znucl(itypat))
    1314              : 
    1315        18574 : end function adata_type
    1316              : !!***
    1317              : 
    1318              : !----------------------------------------------------------------------
    1319              : 
    1320              : !!****f* m_crystal/symbol_type
    1321              : !! NAME
    1322              : !!  symbol_type
    1323              : !!
    1324              : !! FUNCTION
    1325              : !!  Return the atomic symbol from the itypat index
    1326              : !!
    1327              : !! SOURCE
    1328              : 
    1329        18574 : function symbol_type(crystal, itypat) result(symbol)
    1330              : 
    1331              : !Arguments ------------------------------------
    1332              : !scalars
    1333              :  class(crystal_t),intent(in) :: crystal
    1334              :  integer,intent(in) :: itypat
    1335              :  character(len=2) :: symbol
    1336              : 
    1337              : !Local variables-------------------------------
    1338              :  type(atomdata_t) :: atom
    1339              : ! *************************************************************************
    1340              : 
    1341        18574 :  atom = crystal%adata_type(itypat)
    1342        18574 :  symbol = atom%symbol
    1343              : 
    1344        18574 : end function symbol_type
    1345              : !!***
    1346              : 
    1347              : !----------------------------------------------------------------------
    1348              : 
    1349              : !!****f* m_crystal/symbol_iatom
    1350              : !! NAME
    1351              : !!  symbol_iatom
    1352              : !!
    1353              : !! FUNCTION
    1354              : !!  Return the atomic symbol from the iatom index
    1355              : !!
    1356              : !! SOURCE
    1357              : 
    1358        15561 : function symbol_iatom(crystal, iatom) result(symbol)
    1359              : 
    1360              : !Arguments ------------------------------------
    1361              : !scalars
    1362              :  class(crystal_t),intent(in) :: crystal
    1363              :  integer,intent(in) :: iatom
    1364              :  character(len=2) :: symbol
    1365              : ! *************************************************************************
    1366              : 
    1367        15561 :  symbol = crystal%symbol_type(crystal%typat(iatom))
    1368              : 
    1369        15561 : end function symbol_iatom
    1370              : !!***
    1371              : 
    1372              : !----------------------------------------------------------------------
    1373              : 
    1374              : !!****f* m_crystal/crystal_point_group
    1375              : !! NAME
    1376              : !!  crystal_point_group
    1377              : !!
    1378              : !! FUNCTION
    1379              : !!  Return the symmetries of the point group of the crystal.
    1380              : !!
    1381              : !! INPUTS
    1382              : !!  [include_timrev]=If True, time-reversal symmetry is included in the point group unless
    1383              : !!    the system has spatial inversion. Default: False
    1384              : !!
    1385              : !! OUTPUT
    1386              : !!  ptg_nsym=Number of symmetries in the point group
    1387              : !!  ptg_symrel(3,3,ptg_nsym)=Rotations in real space
    1388              : !!  ptg_symrec(3,3,ptg_nsym)=Rotations in reciprocal space
    1389              : !!  has_inversion=True if spatial inversion is present in the point group.
    1390              : !!
    1391              : !! SOURCE
    1392              : 
    1393            6 : subroutine crystal_point_group(cryst, ptg_nsym, ptg_symrel, ptg_symrec, has_inversion, include_timrev)
    1394              : 
    1395              : !Arguments ------------------------------------
    1396              : !scalars
    1397              :  class(crystal_t),intent(in) :: cryst
    1398              :  integer,intent(out) :: ptg_nsym
    1399              :  logical,intent(out) :: has_inversion
    1400              :  logical,optional,intent(in) :: include_timrev
    1401              : !arrays
    1402              :  integer,allocatable,intent(out) :: ptg_symrel(:,:,:),ptg_symrec(:,:,:)
    1403              : 
    1404              : !Local variables-------------------------------
    1405              : !scalars
    1406              :  integer :: isym, search, tmp_nsym, ierr
    1407              :  logical :: found, my_include_timrev, debug
    1408              : !arrays
    1409           12 :  integer :: work_symrel(3,3,cryst%nsym)
    1410            6 :  integer,allocatable :: symafm(:)
    1411              : ! *************************************************************************
    1412              : 
    1413            6 :  my_include_timrev = .False.; if (present(include_timrev)) my_include_timrev = include_timrev
    1414              : 
    1415           78 :  tmp_nsym = 1; work_symrel(:,:,1) = cryst%symrel(:,:,1)
    1416          288 :  do isym=2,cryst%nsym
    1417          282 :    if (cryst%symafm(isym) == -1) cycle
    1418         7050 :    do search=1,tmp_nsym
    1419        11124 :      found = all(work_symrel(:,:,search) == cryst%symrel(:,:,isym))
    1420         7050 :      if (found) exit
    1421              :    end do
    1422          288 :    if (.not. found) then
    1423          282 :      tmp_nsym = tmp_nsym + 1
    1424         3666 :      work_symrel(:,:,tmp_nsym) = cryst%symrel(:,:,isym)
    1425              :    end if
    1426              :  end do
    1427              : 
    1428            6 :  has_inversion = .False.
    1429           12 :  do isym=1,tmp_nsym
    1430           84 :    if (all(work_symrel(:,:,isym) == inversion_3d) ) then
    1431            6 :      has_inversion = .True.; exit
    1432              :    end if
    1433              :  end do
    1434              : 
    1435              :  ! Now we know the symmetries of the point group.
    1436            6 :  ptg_nsym = tmp_nsym; if (.not. has_inversion .and. my_include_timrev) ptg_nsym = 2 * tmp_nsym
    1437           18 :  ABI_MALLOC(ptg_symrel, (3, 3, ptg_nsym))
    1438           12 :  ABI_MALLOC(ptg_symrec, (3, 3, ptg_nsym))
    1439              : 
    1440         3750 :  ptg_symrel(:,:,1:tmp_nsym) = work_symrel(:,:,1:tmp_nsym)
    1441          294 :  do isym=1,tmp_nsym
    1442          294 :    call mati3inv(ptg_symrel(:,:,isym), ptg_symrec(:,:,isym))
    1443              :  end do
    1444              : 
    1445            6 :  if (.not. has_inversion .and. my_include_timrev) then
    1446            0 :    ptg_symrel(:,:,tmp_nsym+1:) = -work_symrel(:,:,1:tmp_nsym)
    1447            0 :    do isym=tmp_nsym+1,ptg_nsym
    1448            0 :      call mati3inv(ptg_symrel(:,:,isym), ptg_symrec(:,:,isym))
    1449              :    end do
    1450              :  end if
    1451              : 
    1452            6 :  debug = .False.
    1453              :  if (debug) then
    1454              :    ABI_MALLOC(symafm, (ptg_nsym))
    1455              :    symafm = 1
    1456              :    call sg_multable(ptg_nsym, symafm, ptg_symrel, ierr)
    1457              :    ABI_CHECK(ierr == 0, "point group is not a group! See messages above")
    1458              :    ABI_FREE(symafm)
    1459              :  end if
    1460              : 
    1461            6 : end subroutine crystal_point_group
    1462              : !!***
    1463              : 
    1464              : !----------------------------------------------------------------------
    1465              : 
    1466              : !!****f* m_crystal/crystal_ncwrite
    1467              : !! NAME
    1468              : !! crystal_ncwrite
    1469              : !!
    1470              : !! FUNCTION
    1471              : !! Output system geometry to a file, using the NETCDF file format and ETSF I/O.
    1472              : !! Data are taken from the crystal_t object.
    1473              : !!
    1474              : !! INPUTS
    1475              : !!  cryst<crystal_t>=Object defining the unit cell and its symmetries.
    1476              : !!  ncid=NC file handle.
    1477              : !!
    1478              : !! OUTPUT
    1479              : !!  Only writing
    1480              : !!
    1481              : !! NOTES
    1482              : !!  Alchemy not treated, since crystal should be initialized at the beginning of the run.
    1483              : !!
    1484              : !! SOURCE
    1485              : 
    1486        18636 : integer function crystal_ncwrite(cryst, ncid) result(ncerr)
    1487              : 
    1488              : !Arguments ------------------------------------
    1489              : !scalars
    1490              :  class(crystal_t),intent(in) :: cryst
    1491              :  integer,intent(in) :: ncid
    1492              : 
    1493              : !Local variables-------------------------------
    1494              : !scalars
    1495              :  integer :: itypat
    1496              :  character(len=500) :: msg
    1497              :  character(len=etsfio_charlen) :: symmorphic
    1498              :  type(atomdata_t) :: atom
    1499              : !arrays
    1500        37272 :  character(len=2) :: symbols(cryst%ntypat)
    1501        37272 :  character(len=80) :: psp_desc(cryst%ntypat),symbols_long(cryst%ntypat)
    1502              : ! *************************************************************************
    1503              : 
    1504              :  ! TODO alchemy not treated correctly by ETSF_IO specs.
    1505        18636 :  if (cryst%isalchemical()) then
    1506              :    write(msg,"(3a)")&
    1507           70 :     "Alchemical crystals are not fully supported by the netcdf format",ch10,&
    1508          140 :     "Important parameters (e.g. znucl, symbols) are not written with the correct value"
    1509           70 :    ABI_WARNING(msg)
    1510              :  end if
    1511              : 
    1512        18636 :  symmorphic = yesno(cryst%isymmorphic())
    1513              : 
    1514              :  ! Define dimensions.
    1515              :  ! npsp added in v9.
    1516              :  ncerr = nctk_def_dims(ncid, [ &
    1517              :    nctkdim_t("complex", 2), nctkdim_t("symbol_length", 2),&
    1518              :    nctkdim_t("character_string_length", 80), nctkdim_t("number_of_cartesian_directions", 3),&
    1519              :    nctkdim_t("number_of_reduced_dimensions", 3), nctkdim_t("number_of_vectors", 3),&
    1520              :    nctkdim_t("number_of_atoms", cryst%natom), nctkdim_t("number_of_atom_species", cryst%ntypat),&
    1521              :    nctkdim_t("number_of_atom_pseudopotentials", cryst%npsp),&
    1522       204996 :    nctkdim_t("number_of_symmetry_operations", cryst%nsym)], defmode=.True.)
    1523        18636 :  NCF_CHECK(ncerr)
    1524              : 
    1525              :  ! Define variables
    1526              :  ncerr = nctk_def_iscalars(ncid, [character(len=nctk_slen) :: &
    1527        74544 :     "space_group", "time_reversal", "use_antiferromagnetic_symmetries"])
    1528        18636 :  NCF_CHECK(ncerr)
    1529              : 
    1530              :  ncerr = nctk_def_arrays(ncid, [ &
    1531              :   ! Atomic structure and symmetry operations
    1532              :   nctkarr_t("primitive_vectors", "dp", "number_of_cartesian_directions, number_of_vectors"), &
    1533              :   nctkarr_t("reduced_symmetry_matrices", "int", &
    1534              :     "number_of_reduced_dimensions, number_of_reduced_dimensions, number_of_symmetry_operations"), &
    1535              :   nctkarr_t("reduced_symmetry_translations", "dp", "number_of_reduced_dimensions, number_of_symmetry_operations"), &
    1536              :   nctkarr_t("atom_species", "int", "number_of_atoms"), &
    1537              :   nctkarr_t("reduced_atom_positions", "dp", "number_of_reduced_dimensions, number_of_atoms"), &
    1538              :   nctkarr_t("atomic_numbers", "dp", "number_of_atom_species"), &
    1539              :   nctkarr_t("atom_species_names", "char", "character_string_length, number_of_atom_species"), &
    1540              :   nctkarr_t("chemical_symbols", "char", "symbol_length, number_of_atom_species"), &
    1541              :   nctkarr_t('atomic_mass_units', "dp", "number_of_atom_species"), &
    1542              :   ! Atomic information.
    1543              :   nctkarr_t("valence_charges", "dp", "number_of_atom_species"), &  ! NB: This variable is not written if alchemical
    1544              :   nctkarr_t("pseudopotential_types", "char", "character_string_length, number_of_atom_species") &
    1545       223632 :  ])
    1546        18636 :  NCF_CHECK(ncerr)
    1547              : 
    1548              :  ! Some variables require the "symmorphic" attribute.
    1549        18636 :  NCF_CHECK(nf90_put_att(ncid, vid("reduced_symmetry_matrices"), "symmorphic", symmorphic))
    1550        18636 :  NCF_CHECK(nf90_put_att(ncid, vid("reduced_symmetry_translations"), "symmorphic", symmorphic))
    1551              : 
    1552              :  ! At this point we have an ETSF-compliant file. Add additional data for internal use in abinit.
    1553              :  ncerr = nctk_def_arrays(ncid, [ &
    1554              :    nctkarr_t('symafm', "int", "number_of_symmetry_operations"), &
    1555              :    nctkarr_t('symrel_cart', "dp", "three, three, number_of_symmetry_operations"), &
    1556              :    nctkarr_t('indsym', "int", "four, number_of_symmetry_operations, number_of_atoms") &
    1557        74544 :  ])
    1558        18636 :  NCF_CHECK(ncerr)
    1559              : 
    1560              :  ! Set-up atomic symbols.
    1561        42668 :  do itypat=1,cryst%ntypat
    1562        24032 :    call atomdata_from_znucl(atom, cryst%znucl(itypat))
    1563        24032 :    symbols(itypat) = atom%symbol
    1564        24032 :    write(symbols_long(itypat),'(a2,a78)') symbols(itypat),REPEAT(CHAR(0),78)
    1565              :    write(psp_desc(itypat),'(2a)') &
    1566       790344 :      cryst%title(itypat)(1:MIN(80,LEN_TRIM(cryst%title(itypat)))),REPEAT(CHAR(0),MAX(0,80-LEN_TRIM(cryst%title(itypat))))
    1567              :  end do
    1568              : 
    1569              :  ! Write data.
    1570        18636 :  NCF_CHECK(nctk_set_datamode(ncid))
    1571        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("space_group"), cryst%space_group))
    1572        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("primitive_vectors"), cryst%rprimd))
    1573        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("reduced_symmetry_matrices"), cryst%symrel))
    1574        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("reduced_symmetry_translations"), cryst%tnons))
    1575        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("atom_species"), cryst%typat))
    1576        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("reduced_atom_positions"), cryst%xred))
    1577        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("atomic_numbers"), cryst%znucl(1:cryst%ntypat)))
    1578        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("atom_species_names"), symbols_long))
    1579        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("chemical_symbols"), symbols))
    1580        18636 :  NCF_CHECK(nf90_put_var(ncid, vid('atomic_mass_units'), cryst%amu))
    1581        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("pseudopotential_types"), psp_desc))
    1582        18636 :  if (cryst%npsp == cryst%ntypat) then
    1583        18566 :    NCF_CHECK(nf90_put_var(ncid, vid("valence_charges"), cryst%zion))
    1584              :  end if
    1585              : 
    1586        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("symafm"), cryst%symafm))
    1587        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("symrel_cart"), cryst%symrel_cart))
    1588        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("indsym"), cryst%indsym))
    1589              : 
    1590              : ! Variables pertaining to the symmetry of the wavefunctions.
    1591              : ! Note that these variables will be used in crystal_compare
    1592        18636 :  NCF_CHECK(nf90_put_var(ncid, vid("time_reversal"), cryst%timrev))
    1593              : 
    1594        18636 :  if (cryst%use_antiferro) then
    1595          119 :     NCF_CHECK(nf90_put_var(ncid, vid("use_antiferromagnetic_symmetries"), 1))
    1596              :  else
    1597        18517 :     NCF_CHECK(nf90_put_var(ncid, vid("use_antiferromagnetic_symmetries"), 0))
    1598              :  end if
    1599              : 
    1600              : contains
    1601       354014 :  integer function vid(vname)
    1602              :    character(len=*),intent(in) :: vname
    1603       354014 :    vid = nctk_idname(ncid, vname)
    1604              :  end function vid
    1605              : 
    1606              : end function crystal_ncwrite
    1607              : !!***
    1608              : 
    1609              : !----------------------------------------------------------------------
    1610              : 
    1611              : !!****f* m_crystal/crystal_ncwrite_path
    1612              : !! NAME
    1613              : !! crystal_ncwrite_path
    1614              : !!
    1615              : !! FUNCTION
    1616              : !! Output system geometry to a file, using the NETCDF file format and ETSF I/O.
    1617              : !!
    1618              : !! INPUTS
    1619              : !!  crystal<crystal_t>=Object defining the unit cell and its symmetries.
    1620              : !!  path=filename
    1621              : !!
    1622              : !! OUTPUT
    1623              : !!  Only writing
    1624              : !!
    1625              : !! SOURCE
    1626              : 
    1627            0 : integer function crystal_ncwrite_path(crystal, path) result(ncerr)
    1628              : 
    1629              : !Arguments ------------------------------------
    1630              : !scalars
    1631              :  character(len=*),intent(in) :: path
    1632              :  class(crystal_t),intent(in) :: crystal
    1633              : 
    1634              : !Local variables-------------------------------
    1635              :  integer :: ncid
    1636              : ! *************************************************************************
    1637              : 
    1638            0 :  ncerr = nf90_noerr
    1639            0 :  if (file_exists(path)) then
    1640            0 :    NCF_CHECK(nctk_open_modify(ncid, path, xmpi_comm_self))
    1641              :  else
    1642            0 :    ncerr = nctk_open_create(ncid, path, xmpi_comm_self)
    1643            0 :    NCF_CHECK_MSG(ncerr, sjoin("creating:", path))
    1644              :  end if
    1645              : 
    1646            0 :  NCF_CHECK(crystal_ncwrite(crystal, ncid))
    1647            0 :  NCF_CHECK(nf90_close(ncid))
    1648              : 
    1649            0 : end function crystal_ncwrite_path
    1650              : !!***
    1651              : 
    1652              : !----------------------------------------------------------------------
    1653              : 
    1654              : !!****f* m_crystal/crystal_ncread
    1655              : !! NAME
    1656              : !! crystal_ncread
    1657              : !!
    1658              : !! FUNCTION
    1659              : !! Read the crystal object from a NETCDF file.
    1660              : !!
    1661              : !! INPUTS
    1662              : !!  cryst<crystal_t>=Object defining the unit cell and its symmetries.
    1663              : !!  ncid=NC file handle.
    1664              : !!
    1665              : !! OUTPUT
    1666              : !!  crystal
    1667              : !!
    1668              : !! SOURCE
    1669              : 
    1670          401 : subroutine crystal_ncread(cryst, ncid)
    1671              : 
    1672              : !Arguments ------------------------------------
    1673              : !scalars
    1674              :  class(crystal_t),intent(inout) :: cryst
    1675              :  integer,intent(in) :: ncid
    1676              : 
    1677              : !Local variables ------------------------------------
    1678              :  integer :: use_antiferro
    1679              : ! *************************************************************************
    1680              : 
    1681              :  ! ---------------
    1682              :  ! Read dimensions
    1683              :  ! ---------------
    1684          401 :  NCF_CHECK(nctk_get_dim(ncid, "number_of_atoms", cryst%natom))
    1685          401 :  NCF_CHECK(nctk_get_dim(ncid, "number_of_atom_species", cryst%ntypat))
    1686          401 :  NCF_CHECK(nctk_get_dim(ncid, "number_of_atom_pseudopotentials", cryst%npsp))
    1687          401 :  NCF_CHECK(nctk_get_dim(ncid, "number_of_symmetry_operations", cryst%nsym))
    1688              : 
    1689              :  ! ---------------
    1690              :  ! Allocate memory
    1691              :  ! ---------------
    1692          401 :  call cryst%malloc()
    1693              : 
    1694              :  ! ------------
    1695              :  ! read scalars
    1696              :  ! ------------
    1697          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "space_group"), cryst%space_group))
    1698          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "time_reversal"), cryst%timrev))
    1699          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "use_antiferromagnetic_symmetries"), use_antiferro))
    1700          401 :  cryst%use_antiferro = .False.
    1701          401 :  if (use_antiferro /= 0) cryst%use_antiferro = .True.
    1702              : 
    1703              :  ! -----------
    1704              :  ! read arrays
    1705              :  ! -----------
    1706          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "primitive_vectors"), cryst%rprimd))
    1707          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "reduced_symmetry_matrices"), cryst%symrel))
    1708          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "reduced_symmetry_translations"), cryst%tnons))
    1709          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "atom_species"), cryst%typat))
    1710          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "reduced_atom_positions"), cryst%xred))
    1711          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "atomic_numbers"), cryst%znucl(1:cryst%ntypat)))
    1712          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "atomic_mass_units"), cryst%amu))
    1713          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "symafm"), cryst%symafm))
    1714          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "symrel_cart"), cryst%symrel_cart))
    1715          401 :  NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "indsym"), cryst%indsym))
    1716              : 
    1717          401 :  if (cryst%npsp == cryst%ntypat) then
    1718          401 :    NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "valence_charges"), cryst%zion))
    1719              :  end if
    1720              : 
    1721              :  ! Ignore those
    1722              :  !NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "pseudopotential_types"), psp_desc))
    1723              :  !NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "atom_species_names"), symbols_long))
    1724              :  !NCF_CHECK(nf90_get_var(ncid, nctk_idname(ncid, "chemical_symbols"), symbols))
    1725              : 
    1726              :  ! -----------------------
    1727              :  ! Complete initialization
    1728              :  ! -----------------------
    1729              : 
    1730          401 :  call cryst%compute_geometry()
    1731          401 :  call cryst%index_atoms()
    1732          401 :  call cryst%compute_sym()
    1733              : 
    1734          401 : end subroutine crystal_ncread
    1735              : !!***
    1736              : 
    1737              : !----------------------------------------------------------------------
    1738              : 
    1739              : !!****f* m_crystal/prt_cif
    1740              : !! NAME
    1741              : !! prt_cif
    1742              : !!
    1743              : !! FUNCTION
    1744              : !!   print out CIF format file
    1745              : !!
    1746              : !! INPUTS
    1747              : !!
    1748              : !! OUTPUT
    1749              : !!
    1750              : !! SOURCE
    1751              : 
    1752            4 : subroutine prt_cif(brvltt, ciffname, natom, nsym, ntypat, rprimd, &
    1753            2 :                    spgaxor, spgroup, spgorig, symrel, tnon, typat, xred, znucl)
    1754              : 
    1755              : !Arguments ------------------------------------
    1756              : !scalars
    1757              :  integer,intent(in) :: natom, ntypat, nsym
    1758              :  integer, intent(in) :: brvltt, spgaxor, spgroup, spgorig
    1759              : !arrays
    1760              :  integer, intent(in) :: typat(natom)
    1761              :  integer, intent(in) :: symrel(3,3,nsym)
    1762              :  character(len=*), intent(in) :: ciffname
    1763              :  real(dp), intent(in) :: tnon(3,nsym)
    1764              :  real(dp), intent(in) :: rprimd(3,3)
    1765              :  real(dp), intent(in) :: xred(3,natom)
    1766              :  real(dp), intent(in) :: znucl(ntypat)
    1767              : 
    1768              : !Local variables -------------------------------
    1769              : !scalars
    1770              :  integer :: unitcif, iatom, isym, sporder, itypat, nat_this_type
    1771              :  real(dp) :: ucvol
    1772              :  type(atomdata_t) :: atom
    1773              : !arrays
    1774              :  character(len=80) :: tmpstring
    1775              :  character(len=1) :: brvsb
    1776              :  character(len=15) :: intsb,ptintsb,ptschsb,schsb
    1777              :  character(len=35) :: intsbl
    1778              :  character(len=10) :: str_nat_type
    1779              :  character(len=100) :: chemformula
    1780              :  character(len=500) :: msg
    1781              :  real(dp) :: angle(3), gprimd(3,3), rmet(3,3), gmet(3,3)
    1782              : 
    1783              : !*************************************************************************
    1784              : 
    1785              :  ! open file in append mode xlf and other compilers refuse append mode
    1786            2 :  if (open_file(ciffname,msg,newunit=unitcif) /=0) then
    1787            0 :    ABI_WARNING(msg)
    1788            0 :    return
    1789              :  end if
    1790              : 
    1791              :  ! print title for dataset
    1792            2 :  write (unitcif,'(a)') 'data_set'
    1793              : 
    1794              :  ! print cell parameters a,b,c, angles, volume
    1795            2 :  call metric(gmet,gprimd,-1,rmet,rprimd,ucvol)
    1796            2 :  angle(1)=acos(rmet(2,3)/sqrt(rmet(2,2)*rmet(3,3)))/two_pi*360.0_dp
    1797            2 :  angle(2)=acos(rmet(1,3)/sqrt(rmet(1,1)*rmet(3,3)))/two_pi*360.0_dp
    1798            2 :  angle(3)=acos(rmet(1,2)/sqrt(rmet(1,1)*rmet(2,2)))/two_pi*360.0_dp
    1799              : 
    1800            2 :  write (unitcif,'(a,E20.10)') '_cell_length_a                     ', sqrt(rmet(1,1))*Bohr_Ang
    1801            2 :  write (unitcif,'(a,E20.10)') '_cell_length_b                     ', sqrt(rmet(2,2))*Bohr_Ang
    1802            2 :  write (unitcif,'(a,E20.10)') '_cell_length_c                     ', sqrt(rmet(3,3))*Bohr_Ang
    1803            2 :  write (unitcif,'(a,E20.10)') '_cell_angle_alpha                  ', angle(1)
    1804            2 :  write (unitcif,'(a,E20.10)') '_cell_angle_beta                   ', angle(2)
    1805            2 :  write (unitcif,'(a,E20.10)') '_cell_angle_gamma                  ', angle(3)
    1806            2 :  write (unitcif,'(a,E20.10)') '_cell_volume                       ', ucvol*(Bohr_Ang)**3
    1807              : 
    1808              :  ! print reduced positions
    1809            2 :  write (unitcif,'(a)') 'loop_'
    1810            2 :  write (unitcif,'(a,E20.10)') '  _atom_site_label                   '
    1811            2 :  write (unitcif,'(a,E20.10)') '  _atom_site_fract_x                 '
    1812            2 :  write (unitcif,'(a,E20.10)') '  _atom_site_fract_y                 '
    1813            2 :  write (unitcif,'(a,E20.10)') '  _atom_site_fract_z                 '
    1814            5 :  do iatom = 1, natom
    1815            3 :    call atomdata_from_znucl(atom,znucl(typat(iatom)))
    1816            5 :    write (unitcif,'(2a,3E20.10)') '  ', atom%symbol, xred(:,iatom)
    1817              :  end do
    1818              : 
    1819              : !other specs in CIF dictionary which may be useful:
    1820              : !GEOM_BOND GEOM_ANGLE GEOM_TORSION
    1821              : 
    1822              :  ! print chemical composition in simplest form
    1823            2 :  chemformula = "'"
    1824            4 :  do itypat = 1, ntypat
    1825            2 :    nat_this_type = 0
    1826            5 :    do iatom = 1, natom
    1827            5 :      if (typat(iatom) == itypat) nat_this_type = nat_this_type+1
    1828              :    end do
    1829            2 :    call atomdata_from_znucl(atom,znucl(itypat))
    1830            2 :    call int2char10(nat_this_type, str_nat_type)
    1831            6 :    chemformula = trim(chemformula) // atom%symbol // trim(str_nat_type) // "  "
    1832              :  end do
    1833            2 :  chemformula = trim(chemformula) // "'"
    1834            2 :  write (unitcif,'(2a)') '_chemical_formula_analytical              ', chemformula
    1835              : 
    1836              :  !FIXME: check that brvltt is correctly used here - is it equal to bravais(1) in the invars routines?
    1837            2 :  if (brvltt==1) then
    1838            0 :    write (unitcif,'(a)') '_symmetry_cell_setting             triclinic'
    1839              :  else if(brvltt==2)then
    1840            0 :    write (unitcif,'(a)') '_symmetry_cell_setting             monoclinic'
    1841              :  else if(brvltt==3)then
    1842            0 :    write (unitcif,'(a)') '_symmetry_cell_setting             orthorhombic'
    1843              :  else if(brvltt==4)then
    1844            0 :    write (unitcif,'(a)') '_symmetry_cell_setting             tetragonal'
    1845              :  else if(brvltt==5)then
    1846            0 :    write (unitcif,'(a)') '_symmetry_cell_setting             rhombohedral'
    1847              :  else if(brvltt==6)then
    1848            0 :    write (unitcif,'(a)') '_symmetry_cell_setting             hexagonal'
    1849              :  else if(brvltt==7)then
    1850            0 :    write (unitcif,'(a)') '_symmetry_cell_setting             cubic'
    1851              :  end if
    1852              : 
    1853            2 :  call spgdata(brvsb,intsb,intsbl,ptintsb,ptschsb,schsb,spgaxor,spgroup,sporder,spgorig)
    1854              : 
    1855              :  ! print symmetry operations
    1856            2 :  write (unitcif,'(a,I6)') "_symmetry_Int_Tables_number          ", spgroup
    1857            2 :  write (unitcif,'(5a)') "_symmetry_space_group_name_H-M        '", brvsb, " ", trim(intsb), "'"
    1858            2 :  write (unitcif,'(a)') ''
    1859            2 :  write (unitcif,'(a)') 'loop_'
    1860            2 :  write (unitcif,'(a)') '  _symmetry_equiv_pos_as_xyz           '
    1861           74 :  do isym = 1, nsym
    1862           72 :    call  symrel2string(symrel(:,:,isym), tnon(:,isym), tmpstring)
    1863           74 :    write (unitcif,'(2a)') '  ', trim(tmpstring)
    1864              :  end do
    1865              : 
    1866            2 :  close(unitcif)
    1867              : 
    1868              : end subroutine prt_cif
    1869              : !!***
    1870              : 
    1871              : !!****f* m_crystal/symrel2string
    1872              : !! NAME
    1873              : !! symrel2string
    1874              : !!
    1875              : !! FUNCTION
    1876              : !!
    1877              : !! INPUTS
    1878              : !!
    1879              : !! OUTPUT
    1880              : !!
    1881              : !! NOTES
    1882              : !!
    1883              : !! SOURCE
    1884              : 
    1885           72 : subroutine symrel2string(symrel1, tnon, string)
    1886              : 
    1887              : !Arguments ------------------------------------
    1888              : !scalars
    1889              :  integer, intent(in) :: symrel1(3,3)
    1890              :  real(dp), intent(in) :: tnon(3)
    1891              :  character(len=80), intent(out) :: string
    1892              : 
    1893              : !Local variables -------------------------
    1894              : !scalars
    1895              :  integer :: i1,i2
    1896              :  character(len=1) :: xyz(3)
    1897              : 
    1898              : ! *********************************************************************
    1899              : 
    1900           72 :  xyz(1) = 'x'
    1901           72 :  xyz(2) = 'y'
    1902           72 :  xyz(3) = 'z'
    1903              : 
    1904           72 :  string = ''
    1905          288 :  do i1=1,3
    1906          216 :    if (abs(tnon(i1)) > tol10) then
    1907              :      ! find fraction 1/n for tnon, otherwise do not know what to print
    1908           36 :      if (abs(one-two*tnon(i1)) < tol10) string = trim(string)//'1/2'
    1909           36 :      if (abs(one+two*tnon(i1)) < tol10) string = trim(string)//'-1/2'
    1910              : 
    1911           36 :      if (abs(one-three*tnon(i1)) < tol10) string = trim(string)//'1/3'
    1912           36 :      if (abs(one+three*tnon(i1)) < tol10) string = trim(string)//'-1/3'
    1913           36 :      if (abs(two-three*tnon(i1)) < tol10) string = trim(string)//'2/3'
    1914           36 :      if (abs(two+three*tnon(i1)) < tol10) string = trim(string)//'-2/3'
    1915              : 
    1916           36 :      if (abs(one-six*tnon(i1)) < tol10) string = trim(string)//'1/6'
    1917           36 :      if (abs(one+six*tnon(i1)) < tol10) string = trim(string)//'-1/6'
    1918           36 :      if (abs(five-six*tnon(i1)) < tol10) string = trim(string)//'5/6'
    1919           36 :      if (abs(five+six*tnon(i1)) < tol10) string = trim(string)//'-5/6'
    1920              :    end if
    1921          864 :    do i2=1,3
    1922              :      ! FIXME: check if this is correct ordering for symrel(i1,i2) looks ok
    1923          648 :      if (symrel1(i1,i2) == 1)  string = trim(string)//'+'//xyz(i2)
    1924          864 :      if (symrel1(i1,i2) == -1) string = trim(string)//'-'//xyz(i2)
    1925              :    end do
    1926          288 :    if (i1 /= 3) string = trim(string)//','
    1927              :  end do
    1928              : 
    1929           72 : end subroutine symrel2string
    1930              : !!***
    1931              : 
    1932              : !!****f* m_crystal/prtposcar
    1933              : !! NAME
    1934              : !!  prtposcar
    1935              : !!
    1936              : !! FUNCTION
    1937              : !!  output VASP style POSCAR and FORCES files for use with frozen phonon codes, like
    1938              : !!  PHON from Dario Alfe' or frophon
    1939              : !!  IMPORTANT: the order of atoms is fixed such that typat is re-grouped.
    1940              : !!  First typat=1 then typat=2, etc...
    1941              : !!  Only master should call this routine in MPI-mode.
    1942              : !!
    1943              : !! INPUTS
    1944              : !!  fcart = forces on atoms in cartesian coordinates
    1945              : !!  natom = number of atoms
    1946              : !!  ntypat = number of types of atoms
    1947              : !!  rprimd = lattice vectors for the primitive cell
    1948              : !!  typat = type for each of the natom atoms
    1949              : !!  ucvol = unit cell volume
    1950              : !!  xred = reduced positions of the atoms
    1951              : !!  znucl = nuclear charge of each atomic type
    1952              : !!
    1953              : !! OUTPUTS
    1954              : !!   Only files written
    1955              : !!
    1956              : !! SOURCE
    1957              : 
    1958            1 : subroutine prtposcar(fcart, fnameradix, natom, ntypat, rprimd, typat, ucvol, xred, znucl)
    1959              : 
    1960              : !Arguments ------------------------------------
    1961              : !scalars
    1962              :  integer, intent(in) :: natom, ntypat
    1963              :  real(dp), intent(in) :: ucvol
    1964              : !arrays
    1965              :  integer, intent(in) :: typat(natom)
    1966              :  real(dp), intent(in) :: fcart(3,natom)
    1967              :  real(dp), intent(in) :: rprimd(3,3)
    1968              :  real(dp), intent(in) :: xred(3,natom)
    1969              :  real(dp), intent(in) :: znucl(ntypat)
    1970              :  character(len=fnlen), intent(in) :: fnameradix
    1971              : 
    1972              : !Local variables-------------------------------
    1973              : !scalars
    1974              :  integer :: iatom, itypat, iout
    1975              :  type(atomdata_t) :: atom
    1976              : ! arrays
    1977            2 :  integer :: natoms_this_type(ntypat)
    1978              :  character(len=2) :: symbol
    1979              :  character(len=7) :: natoms_this_type_str
    1980              :  character(len=100) :: chem_formula, natoms_all_types, atomsstring_all_types
    1981              :  character(len=500) :: msg
    1982              : !************************************************************************
    1983              : 
    1984              :  ! Output POSCAR file for positions, atom types etc
    1985            1 :  if (open_file(trim(fnameradix)//"_POSCAR", msg, newunit=iout) /= 0) then
    1986            0 :    ABI_ERROR(msg)
    1987              :  end if
    1988              : 
    1989            3 :  natoms_this_type = 0
    1990            3 :  do itypat=1,ntypat
    1991           21 :    do iatom=1,natom
    1992           20 :      if (typat(iatom) == itypat) natoms_this_type(itypat) = natoms_this_type(itypat) + 1
    1993              :    end do
    1994              :  end do
    1995              : 
    1996            1 :  chem_formula = ""
    1997            1 :  atomsstring_all_types = "  "
    1998            3 :  do itypat=1, ntypat
    1999            2 :    call atomdata_from_znucl(atom, znucl(itypat))
    2000            2 :    symbol = atom%symbol
    2001            2 :    if (natoms_this_type(itypat) < 10) then
    2002            2 :      write(natoms_this_type_str, '(I1)') natoms_this_type(itypat)
    2003            0 :    else if (natoms_this_type(itypat) < 100) then
    2004            0 :      write(natoms_this_type_str, '(I2)') natoms_this_type(itypat)
    2005            0 :    else if (natoms_this_type(itypat) < 1000) then
    2006            0 :      write(natoms_this_type_str, '(I3)') natoms_this_type(itypat)
    2007              :    end if
    2008            2 :    chem_formula = trim(chem_formula) // symbol // trim(natoms_this_type_str)
    2009            5 :    atomsstring_all_types = trim(atomsstring_all_types) // "  " // symbol
    2010              :  end do
    2011              : 
    2012            1 :  write (iout,'(3a,E24.14)') "ABINIT generated POSCAR file. Chemical formula is ",trim(chem_formula), &
    2013            2 :                             "  Volume (AA^3) = ", ucvol*Bohr_Ang*Bohr_Ang*Bohr_Ang
    2014              : 
    2015            1 :  write (iout,'(E10.1)')  1.0_dp
    2016            4 :  write (iout,'(3E24.14,1x)') Bohr_Ang*rprimd(:,1) ! (angstr? bohr?)
    2017            4 :  write (iout,'(3E24.14,1x)') Bohr_Ang*rprimd(:,2)
    2018            4 :  write (iout,'(3E24.14,1x)') Bohr_Ang*rprimd(:,3)
    2019            1 :  write (iout, '(a)') atomsstring_all_types
    2020              : 
    2021            1 :  natoms_all_types = "   "
    2022            3 :  do itypat=1, ntypat
    2023            2 :    write (natoms_this_type_str, '(I7)') natoms_this_type(itypat)
    2024            3 :    natoms_all_types = trim(natoms_all_types) // "   " // trim(natoms_this_type_str)
    2025              :  end do
    2026              : 
    2027            1 :  write(iout,'(a)') trim(natoms_all_types)
    2028            1 :  write(iout,'(a)') "Direct"
    2029              : 
    2030            3 :  do itypat=1, ntypat
    2031           21 :    do iatom=1,natom
    2032           18 :      if (typat(iatom) /= itypat) cycle
    2033           20 :      write (iout,'(3(E24.14,1x))') xred(:,iatom)
    2034              :    end do
    2035              :  end do
    2036            1 :  close(iout)
    2037              : 
    2038              :  ! output FORCES file for forces in same order as positions above
    2039            1 :  if (open_file(trim(fnameradix)//"_FORCES", msg, newunit=iout) /= 0 ) then
    2040            0 :    ABI_ERROR(msg)
    2041              :  end if
    2042              : 
    2043              :  !ndisplacements
    2044              :  !iatom_displaced displacement_red_coord(3)
    2045              :  !forces_cart_ev_Angstr(3)
    2046              :  !...
    2047              :  !<repeat for other displaced atoms>
    2048            1 :  write(iout,'(I7)') 1
    2049            1 :  write(iout,'(a)') '1 0 0 0        ! TO BE FILLED IN '
    2050            3 :  do itypat=1, ntypat
    2051           21 :    do iatom=1,natom
    2052           18 :      if (typat(iatom) /= itypat) cycle
    2053           47 :      write(iout,'(3(E24.14,1x))') Ha_eV/Bohr_Ang*fcart(:,iatom)
    2054              :    end do
    2055              :  end do
    2056              : 
    2057            1 :  close(iout)
    2058              : 
    2059            1 : end subroutine prtposcar
    2060              : !!***
    2061              : 
    2062              : !----------------------------------------------------------------------
    2063              : 
    2064              : !!****f* m_crystal/crystal_symmetrize_cart_vec3
    2065              : !! NAME
    2066              : !!  crystal_symmetrize_cart_vec3
    2067              : !!
    2068              : !! FUNCTION
    2069              : !!  Use spatial and time-reversal symmetry (TR) to symmetrize a Cartesian vector of real elements.
    2070              : !!
    2071              : !! INPUTS
    2072              : !!  v(3)=Vector in Cartesian coordinates.
    2073              : !!  time_opt=Prefactor that defines how the vectors transforms under TR. Usually +1 or -1
    2074              : !!      Note that TR is used only if cryst%timrev == 2. time_opt = 0 disables TR for testing purposes.
    2075              : !!
    2076              : !! SOURCE
    2077              : 
    2078         4495 : function crystal_symmetrize_cart_vec3(cryst, v, time_opt) result(vsum)
    2079              : 
    2080              : !Arguments ------------------------------------
    2081              :  class(crystal_t),intent(in) :: cryst
    2082              :  real(dp),intent(in) :: v(3)
    2083              :  integer,intent(in) :: time_opt
    2084              :  real(dp) :: vsum(3)
    2085              : 
    2086              : !Local variables-------------------------------
    2087              :  integer :: isym, itime, nsym_sum
    2088              :  real(dp) :: vsym(3), tsign
    2089              : ! *************************************************************************
    2090              : 
    2091        17980 :  vsum = zero; nsym_sum = 0
    2092        13485 :  do itime=1,cryst%timrev
    2093         8990 :    tsign = 1
    2094         8990 :    if (itime == cryst%timrev) then
    2095         4495 :      if (time_opt == 0) cycle
    2096            0 :      tsign = time_opt
    2097              :    end if
    2098       224750 :    do isym=1, cryst%nsym
    2099       215760 :      nsym_sum = nsym_sum + 1
    2100      5609760 :      vsym = matmul(cryst%symrel_cart(:,:,isym), v) * tsign
    2101       872030 :      vsum = vsum + vsym
    2102              :    end do
    2103              :  end do
    2104        17980 :  vsum = vsum / nsym_sum
    2105              : 
    2106         4495 : end function crystal_symmetrize_cart_vec3
    2107              : !!***
    2108              : 
    2109              : !----------------------------------------------------------------------
    2110              : 
    2111              : !!****f* m_crystal/crystal_symmetrize_cart_tens33
    2112              : !! NAME
    2113              : !!  crystal_symmetrize_cart_tens33
    2114              : !!
    2115              : !! FUNCTION
    2116              : !!  Symmetrize a cartesian 3x3 tensor
    2117              : !!  Use spatial and time-reversal symmetry (TR) to symmetrize a Cartesian 3x3 tensor of real elements.
    2118              : !!
    2119              : !! INPUTS
    2120              : !!  v(3)=Vector in Cartesian coordinates.
    2121              : !!  time_opt=Prefacator that defines how the vectors transforms under TR. Usually +1 or -1
    2122              : !!      Note that TR is used only if cryst%timrev == 2. time_opt = 0 disables TR for testing purposes.
    2123              : !!
    2124              : !! SOURCE
    2125              : 
    2126        62537 : function crystal_symmetrize_cart_tens33(cryst, t, time_opt) result(tsum)
    2127              : 
    2128              : !Arguments ------------------------------------
    2129              :  class(crystal_t),intent(in) :: cryst
    2130              :  real(dp),intent(in) :: t(3,3)
    2131              :  integer,intent(in) :: time_opt
    2132              :  real(dp) :: tsum(3,3)
    2133              : 
    2134              : !Local variables-------------------------------
    2135              :  integer :: isym, itime, nsym_sum
    2136              :  real(dp) :: tsym(3,3), tsign
    2137              : ! *************************************************************************
    2138              : 
    2139       812981 :  tsum = zero; nsym_sum = 0
    2140              : 
    2141       187611 :  do itime=1,cryst%timrev
    2142       125074 :    tsign = 1
    2143       125074 :    if (itime == cryst%timrev) then
    2144        62537 :      if (time_opt == 0) cycle
    2145            0 :      tsign = time_opt
    2146              :    end if
    2147      1991722 :    do isym=1, cryst%nsym
    2148      1866648 :      nsym_sum = nsym_sum + 1
    2149    324796752 :      tsym = tsign * matmul((cryst%symrel_cart(:,:,isym)), matmul(t, transpose(cryst%symrel_cart(:,:,isym))))
    2150     24391498 :      tsum = tsum + tsym
    2151              :    end do
    2152              :  end do
    2153              : 
    2154       812981 :  tsum = tsum / nsym_sum
    2155              : 
    2156        62537 : end function crystal_symmetrize_cart_tens33
    2157              : !!***
    2158              : 
    2159              : !----------------------------------------------------------------------
    2160              : 
    2161              : !!****f* m_crystal/get_recart_qdirs
    2162              : !! NAME
    2163              : !!  get_recart_qdirs
    2164              : !!
    2165              : !! FUNCTION
    2166              : !!  Return predefined list of 6 q-versors in reciprocal space reduced coordinates.
    2167              : !!  First 3 entries are along the recip. space lattice vectors, then along the Cartesian axis x,y,z.
    2168              : !!  The optional qlen argument, can be used to rescale the vectors. Default: 1
    2169              : !!
    2170              : !! INPUTS
    2171              : !!
    2172              : !! SOURCE
    2173              : 
    2174           29 : subroutine get_redcart_qdirs(cryst, nq, qdirs, qlen)
    2175              : 
    2176              : !Arguments ------------------------------------
    2177              :  class(crystal_t),intent(in) :: cryst
    2178              :  integer,intent(out) :: nq
    2179              :  real(dp),allocatable,intent(out) :: qdirs(:,:)
    2180              :  real(dp),optional,intent(in) :: qlen
    2181              : 
    2182              : !Local variables-------------------------------
    2183              :  integer :: iq
    2184              :  real(dp) :: qred2cart(3,3), qcart2red(3,3)
    2185              : ! *************************************************************************
    2186              : 
    2187          377 :  qred2cart = two_pi * cryst%gprimd
    2188           29 :  qcart2red = qred2cart
    2189           29 :  call matrginv(qcart2red, 3, 3)
    2190              : 
    2191           29 :  nq = 6
    2192           29 :  ABI_MALLOC(qdirs, (3, nq))
    2193          116 :  qdirs(:,1) = [one, zero, zero]  ! (100)
    2194          116 :  qdirs(:,2) = [zero, one, zero]  ! (010)
    2195          116 :  qdirs(:,3) = [zero, zero, one]  ! (001)
    2196          493 :  qdirs(:,4) = matmul(qcart2red, [one, zero, zero]) ! (x)
    2197          493 :  qdirs(:,5) = matmul(qcart2red, [zero, one, zero]) ! (y)
    2198          493 :  qdirs(:,6) = matmul(qcart2red, [zero, zero, one]) ! (z)
    2199              : 
    2200              :  ! normalization
    2201          203 :  do iq=1,nq
    2202          725 :    qdirs(:,iq) = qdirs(:,iq) / normv(qdirs(:,iq), cryst%gmet, "G")
    2203              :  end do
    2204              : 
    2205           29 :  if (present(qlen)) qdirs = qlen * qdirs
    2206              : 
    2207           29 : end subroutine get_redcart_qdirs
    2208              : !!***
    2209              : 
    2210              : !----------------------------------------------------------------------
    2211              : 
    2212              : !!****f* m_crystal/crystal_write_xsf_data
    2213              : !! NAME
    2214              : !!  crystal_write_xsf_data
    2215              : !!
    2216              : !! FUNCTION
    2217              : !!  Write array in real space in XSF format
    2218              : !!
    2219              : !! INPUTS
    2220              : !!  filepath: Path to output file.
    2221              : !!  n1, n2, n3: Dimensions of input array.
    2222              : !!  datagrid(n1,n2,n3)=Array in real space.
    2223              : !!
    2224              : !! SOURCE
    2225              : 
    2226            0 : subroutine crystal_write_xsf_data(cryst, filepath, n1, n2, n3, datagrid)
    2227              : 
    2228              : !Arguments ------------------------------------
    2229              :  class(crystal_t),intent(in) :: cryst
    2230              :  character(len=*),intent(in) :: filepath
    2231              :  integer,intent(in) :: n1, n2, n3
    2232              :  real(dp),intent(in) :: datagrid(n1*n2*n3)
    2233              : 
    2234              : !Local variables-------------------------------
    2235              :  integer,parameter :: realrecip = 0
    2236              :  real(dp),parameter :: origin(3) = zero
    2237              : ! *************************************************************************
    2238              : 
    2239              :  call write_xsf(filepath, n1, n2, n3, datagrid, cryst%rprimd, origin, &
    2240            0 :                 cryst%natom, cryst%ntypat, cryst%typat, cryst%xcart, cryst%znucl, realrecip)
    2241              : 
    2242            0 : end subroutine crystal_write_xsf_data
    2243              : !!***
    2244              : 
    2245      1868235 : end module m_crystal
    2246              : !!***
        

Generated by: LCOV version 2.3-1