Add support for SPRKKR potential.

This is a first version for this option. Some work has still to be
done...
This commit is contained in:
Sylvain Tricot 2020-04-10 17:36:25 +02:00
parent 81459cfcfc
commit 8ebfd624e1
13 changed files with 1278 additions and 1259 deletions

View File

@ -1,302 +0,0 @@
INFO:msspec:Getting the TMatrix...
_________________________________________________________________
PHAGEN
_________________________________________________________________
parameters for this xpd calculation:
-----------------------------------------------------------------
edge= k
potype= hedin norman= stdcrm absorber= 1
coor= angs emin= 13.52 Ry emax= 13.52 Ry
delta= 0.300 Ry gamma= 0.03 Ry eftri= 0.000 Ry
ionization state : neutral
final state potential generated internally
Computes the T-matrix and radial matrix elements
coordinates in angstroms Radii
-----------------------------------------------------------------
Cu 29 0.0000 0.0000 -3.6000 0.0000 0.0000
Cu 29 -1.8000 -1.8000 0.0000 0.0000 0.0000
Cu 29 -1.8000 0.0000 -1.8000 0.0000 0.0000
Cu 29 -3.6000 0.0000 0.0000 0.0000 0.0000
Cu 29 -1.8000 1.8000 0.0000 0.0000 0.0000
Cu 29 0.0000 -1.8000 -1.8000 0.0000 0.0000
Cu 29 0.0000 -3.6000 0.0000 0.0000 0.0000
Cu 29 1.8000 -1.8000 0.0000 0.0000 0.0000
Cu 29 0.0000 1.8000 -1.8000 0.0000 0.0000
Cu 29 1.8000 0.0000 -1.8000 0.0000 0.0000
Cu 29 0.0000 0.0000 0.0000 0.0000 0.0000
Cu 29 1.8000 1.8000 0.0000 0.0000 0.0000
Cu 29 0.0000 3.6000 0.0000 0.0000 0.0000
Cu 29 3.6000 0.0000 0.0000 0.0000 0.0000
-----------------------------------------------------------------
** enter calphas **
---
total energy for atom in ground state
total energy for atom with a hole in k edge
calculated ionization energy for edge k = 8994.86914 eV
---
calculated ionization potential (ryd) = 661.387451
---
symmetrizing coordinates...
symmetrized atomic coordinates of cluster
position
atom no. x y z eq
1 osph 0 0.0000 0.0000 0.0000 0
2 Cu 29 0.0000 0.0000 -5.3452 0
3 Cu 29 -3.4015 -3.4015 1.4578 0
4 Cu 29 -3.4015 0.0000 -1.9437 0
5 Cu 29 -6.8030 0.0000 1.4578 0
6 Cu 29 0.0000 0.0000 1.4578 0
7 Cu 29 -3.4015 3.4015 1.4578 3
8 Cu 29 3.4015 -3.4015 1.4578 3
9 Cu 29 3.4015 3.4015 1.4578 3
10 Cu 29 0.0000 -3.4015 -1.9437 4
11 Cu 29 0.0000 3.4015 -1.9437 4
12 Cu 29 3.4015 0.0000 -1.9437 4
13 Cu 29 0.0000 -6.8030 1.4578 5
14 Cu 29 0.0000 6.8030 1.4578 5
15 Cu 29 6.8030 0.0000 1.4578 5
computing muffin tin potential and phase shifts
generating core state wavefunction
generating final potential (complex hedin-lundqvist exchange)
MT radii for Hydrogen atoms determined by stdcrm unless other options are specified
-----------------------------------------------------------------
i rs(i) i=1,natoms
1 9.28 2 2.50 3 2.46 4 2.35 5 2.48 6 2.33 7 2.46 8 2.46
9 2.46 10 2.35 11 2.35 12 2.35 13 2.48 14 2.48 15 2.48
N.B.: Order of atoms as reshuffled by symmetry routines
-----------------------------------------------------------------
input value for coulomb interst. potential = -0.699999988
and interstitial rs = 3.00000000
lower bound for coulomb interst. potential = -0.290025890
and for interst. rs = 2.54297900
lmax assignment based on l_max = r_mt * k_e + 2
where e is the running energy
optimal lmax chosen according to the running energy e for each atom
number of centers= 14
starting potentials and/or charge densities written to file 13
symmetry information generated internally
symmetry information written to file 14
core initial state of type: 1s1/2
fermi level = -0.17690
generating t_l (for030) and atomic cross section (for050)
gamma = 0.030000 rsint = 3.944844
check in subroutine cont
order of neighb. -- symb. -- dist. from absorber
3 Cu 4.81045771
5 Cu 6.80301476
2 Cu 8.33195782
4 Cu 9.62091541
-----------------------------------------------------------------
1 Cu 0.000000
3 Cu 4.810458
5 Cu 6.803015
2 Cu 8.331958
4 Cu 9.620915
1 Cu 0.000000
3 Cu 4.810458
5 Cu 6.803015
2 Cu 8.331958
4 Cu 9.620915
irho = 2 entering vxc to calculate energy dependent exchange
energy dependent vcon = (-0.181322575,0.183172509) at energy 13.5235996
calculating atomic t-matrix elements atm(n)
check orthogonality between core and continuum state
scalar product between core and continuum state = (0.215178907,-7.336383685E-03)
sqrt(xe/pi) = (1.08555424,-3.627028549E-03)
check ionization potential: 661.387451
value of the mean free path:
-----------------------------------------------------------------
average mean free path due to finite gamma: mfp = 8.81667 angstrom at energy 13.52360
average mean free path in the cluster : mfp = 8.71420 angstrom at energy 13.52360
total mean free path due to Im V and gamma: mfp = 4.38257 angstrom at energy 13.52360
-----------------------------------------------------------------
** phagen terminated normally **
INFO:msspec:Getting the TMatrix...
_________________________________________________________________
PHAGEN
_________________________________________________________________
parameters for this xpd calculation:
-----------------------------------------------------------------
edge= k
potype= hedin norman= stdcrm absorber= 1
coor= angs emin= 13.52 Ry emax= 13.52 Ry
delta= 0.300 Ry gamma= 0.03 Ry eftri= 0.000 Ry
ionization state : neutral
final state potential generated internally
Computes the T-matrix and radial matrix elements
coordinates in angstroms Radii
-----------------------------------------------------------------
Cu 29 0.0000 0.0000 -3.8000 0.0000 0.0000
Cu 29 -1.9000 -1.9000 0.0000 0.0000 0.0000
Cu 29 -1.9000 0.0000 -1.9000 0.0000 0.0000
Cu 29 -3.8000 0.0000 0.0000 0.0000 0.0000
Cu 29 -1.9000 1.9000 0.0000 0.0000 0.0000
Cu 29 0.0000 -1.9000 -1.9000 0.0000 0.0000
Cu 29 0.0000 -3.8000 0.0000 0.0000 0.0000
Cu 29 1.9000 -1.9000 0.0000 0.0000 0.0000
Cu 29 0.0000 1.9000 -1.9000 0.0000 0.0000
Cu 29 1.9000 0.0000 -1.9000 0.0000 0.0000
Cu 29 0.0000 0.0000 0.0000 0.0000 0.0000
Cu 29 1.9000 1.9000 0.0000 0.0000 0.0000
Cu 29 0.0000 3.8000 0.0000 0.0000 0.0000
Cu 29 3.8000 0.0000 0.0000 0.0000 0.0000
-----------------------------------------------------------------
** enter calphas **
---
total energy for atom in ground state
total energy for atom with a hole in k edge
calculated ionization energy for edge k = 8994.86914 eV
---
calculated ionization potential (ryd) = 661.387451
---
symmetrizing coordinates...
symmetrized atomic coordinates of cluster
position
atom no. x y z eq
1 osph 0 0.0000 0.0000 0.0000 0
2 Cu 29 0.0000 0.0000 -5.6422 0
3 Cu 29 -3.5905 -3.5905 1.5388 0
4 Cu 29 -3.5905 0.0000 -2.0517 0
5 Cu 29 -7.1810 0.0000 1.5388 0
6 Cu 29 0.0000 0.0000 1.5388 0
7 Cu 29 -3.5905 3.5905 1.5388 3
8 Cu 29 3.5905 -3.5905 1.5388 3
9 Cu 29 3.5905 3.5905 1.5388 3
10 Cu 29 0.0000 -3.5905 -2.0517 4
11 Cu 29 0.0000 3.5905 -2.0517 4
12 Cu 29 3.5905 0.0000 -2.0517 4
13 Cu 29 0.0000 -7.1810 1.5388 5
14 Cu 29 0.0000 7.1810 1.5388 5
15 Cu 29 7.1810 0.0000 1.5388 5
computing muffin tin potential and phase shifts
generating core state wavefunction
generating final potential (complex hedin-lundqvist exchange)
MT radii for Hydrogen atoms determined by stdcrm unless other options are specified
-----------------------------------------------------------------
i rs(i) i=1,natoms
1 9.80 2 2.64 3 2.60 4 2.44 5 2.61 6 2.46 7 2.60 8 2.60
9 2.60 10 2.44 11 2.44 12 2.44 13 2.61 14 2.61 15 2.61
N.B.: Order of atoms as reshuffled by symmetry routines
-----------------------------------------------------------------
input value for coulomb interst. potential = -0.699999988
and interstitial rs = 3.00000000
lower bound for coulomb interst. potential = -0.232031077
and for interst. rs = 2.76609278
lmax assignment based on l_max = r_mt * k_e + 2
where e is the running energy
optimal lmax chosen according to the running energy e for each atom
number of centers= 14
starting potentials and/or charge densities written to file 13
symmetry information generated internally
symmetry information written to file 14
core initial state of type: 1s1/2
fermi level = -0.16924
generating t_l (for030) and atomic cross section (for050)
gamma = 0.030000 rsint = 4.292365
check in subroutine cont
order of neighb. -- symb. -- dist. from absorber
3 Cu 5.07770586
5 Cu 7.18096018
2 Cu 8.79484367
4 Cu 10.1554117
-----------------------------------------------------------------
1 Cu 0.000000
3 Cu 5.077706
5 Cu 7.180960
2 Cu 8.794844
4 Cu 10.155412
1 Cu 0.000000
3 Cu 5.077706
5 Cu 7.180960
2 Cu 8.794844
4 Cu 10.155412
irho = 2 entering vxc to calculate energy dependent exchange
energy dependent vcon = (-0.151319593,0.168841615) at energy 13.5235996
calculating atomic t-matrix elements atm(n)
check orthogonality between core and continuum state
scalar product between core and continuum state = (0.217915282,-9.193832986E-03)
sqrt(xe/pi) = (1.08495688,-3.348779166E-03)
check ionization potential: 661.387451
value of the mean free path:
-----------------------------------------------------------------
average mean free path due to finite gamma: mfp = 8.81667 angstrom at energy 13.52360
average mean free path in the cluster : mfp = 9.13179 angstrom at energy 13.52360
total mean free path due to Im V and gamma: mfp = 4.48573 angstrom at energy 13.52360
-----------------------------------------------------------------
** phagen terminated normally **

View File

@ -1,8 +1,30 @@
import ase
from .version import __version__
from .misc import LOGGER
#!/usr/bin/env python
#
# Copyright © 2016-2020 - Rennes Physics Institute
#
# This file is part of msspec.
#
# msspec is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# msspec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this msspec. If not, see <http://www.gnu.org/licenses/>.
#
# Source file : src/msspec/__init__.py
# Last modified: ven. 10 avril 2020 17:22:12
# Committed by : "Sylvain Tricot <sylvain.tricot@univ-rennes1.fr>"
import ase
from msspec.misc import LOGGER
from msspec.version import __version__
__sha__ = "$Id$"
def init_msspec():
LOGGER.debug('Initialization of the msspec module')

View File

@ -1,4 +1,5 @@
# coding: utf-8
# vim: set et ts=4 sw=4 fdm=indent mouse=a cc=+1 tw=80:
"""
Module calcio
@ -6,13 +7,16 @@ Module calcio
"""
import numpy as np
from datetime import datetime
import ase
import re
import numpy as np
import ase
from ase import Atom, Atoms
from ase.data import chemical_symbols
from msspec.misc import UREG, LOGGER
class PhagenIO(object):
def __init__(self, phagen_parameters, malloc_parameters):
self.parameters = phagen_parameters
@ -27,8 +31,9 @@ class PhagenIO(object):
self.nlmax = None
self.energies = None
def write_input_file(self, filename='input.ms'):
def write_input_file(self, filename='input.ms'): # noqa: C901
# in input folder
LOGGER.debug("Writing Phagen input file")
atoms = self.parameters.atoms
if not atoms.has('mt_radii'):
for a in atoms:
@ -58,7 +63,7 @@ class PhagenIO(object):
# other sections
continue
value = parameter.value
if isinstance(value, str) and not re.match('\..*\.', value):
if isinstance(value, str) and not re.match(r'\..*\.', value):
s = ' {}=\'{:s}\''.format(name, str(parameter))
else:
s = ' {}={:s}'.format(name, str(parameter))
@ -167,7 +172,8 @@ class PhagenIO(object):
lines = pattern.split(content)
# get the number of atoms (nat) and the number of energy points (ne)
nat, ne, _, ipot, lmax_mode = list(map(int, content.split('\n')[0].split()))
nat, ne, _, ipot, lmax_mode = list(map(int,
content.split('\n')[0].split()))
self.nat = nat
self.ne = ne
self.ipot = ipot
@ -181,7 +187,7 @@ class PhagenIO(object):
if not re.match(r'^\d+$', n):
numbers.append(float(n))
if len(numbers) > 0:
array = np.array(numbers).reshape((-1, 4)) # pylint: disable=no-member
array = np.array(numbers).reshape((-1, 4))
atom_data.append(array)
# construct the data array
@ -265,8 +271,27 @@ class PhagenIO(object):
proto_index = int(data[i, -1])
proto_indices.append(proto_index)
atoms.set_array('proto_indices', np.array(proto_indices))
self.nateqm = int(np.max([len(np.where(data[:,-1]==i)[0]) for i in range(
1, self.nat + 1)]))
self.nateqm = int(np.max([
len(np.where(data[:, -1] == i)[0]) for i in range(1, self.nat + 1)
]))
def load_prototypical_atoms(self, filename='molinpot3.out'):
with open(filename, 'r') as fd:
content = fd.readlines()
content = content[-len(self.parameters.atoms):]
cluster = Atoms()
for line in content:
datatxt = np.array(re.split(r'\s+', line.strip(' \n')))
neq = int(datatxt[-1])
if neq == 0:
Z = int(datatxt[1])
xyz = (datatxt[[2, 3, 4]].astype(float) * UREG.a0).to(
'angstrom').magnitude
sym = chemical_symbols[Z]
cluster += Atom(sym, position=xyz)
self.prototypical_atoms = cluster
return cluster
def load_potential_file(self, filename='plot_vc.dat'):
a_index = 0
@ -279,11 +304,13 @@ class PhagenIO(object):
a_index += 1
d = d.split()
a = {'Symbol': d[1], 'distance': float(d[4]),
'coord': np.array([float(d[7]), float(d[8]), float(d[9])]),
'coord': np.array([float(d[7]), float(d[8]),
float(d[9])]),
'index': int(a_index), 'values': []}
pot_data.append(a)
else:
pot_data[a_index - 1]['values'].append(tuple(float(_) for _ in d.split()))
pot_data[a_index - 1]['values'].append(
tuple(float(_) for _ in d.split()))
# convert the values list to a numpy array
for _pot_data in pot_data:
@ -292,27 +319,30 @@ class PhagenIO(object):
return pot_data
class SpecIO(object):
def __init__(self, parameters, malloc_parameters, phagenio):
self.parameters = parameters
self.malloc_parameters = malloc_parameters
self.phagenio = phagenio
def write_input_file(self, filename='spec.dat'):
def write_input_file(self, filename='spec.dat'): # noqa: C901
def title(t, shift=4, width=79, center=True):
if center:
s = ('{}*{:^%ds}*\n' % (width - shift - 2)).format(' ' * shift, t)
s = ('{}*{:^%ds}*\n' % (width - shift - 2)
).format(' ' * shift, t)
else:
s = ('{}*{:%ds}*\n' % (width - shift - 2)).format(' ' * shift, t)
s = ('{}*{:%ds}*\n' % (width - shift - 2)
).format(' ' * shift, t)
return s
def rule(tabs=(5, 10, 10, 10, 10), symbol='=', shift=4, width=79):
s = ' ' * shift + '*' + symbol * (width - shift - 2) + '*\n'
t = np.cumsum(tabs) + shift
l = list(s)
sep = list(s)
for i in t:
l[i] = '+'
return ''.join(l)
sep[i] = '+'
return ''.join(sep)
def fillstr(a, b, index, justify='left'):
alist = list(a)
@ -426,7 +456,8 @@ class SpecIO(object):
content += rule()
line = create_line("SPECTRO,ISPIN,IDICHR,IPOL")
line = fillstr(line, str(p.calctype_spectro), 9, 'left')
line = fillstr(line, str(p.get_parameter('calctype_ispin')), 19, 'left')
line = fillstr(line,
str(p.get_parameter('calctype_ispin')), 19, 'left')
line = fillstr(line, str(p.calctype_idichr), 29, 'left')
line = fillstr(line, str(p.calctype_ipol), 39, 'left')
content += line
@ -476,11 +507,13 @@ class SpecIO(object):
line = fillstr(line, str(p.get_parameter('ped_imod')), 9, 'decimal')
line = fillstr(line, str(p.get_parameter('ped_imoy')), 19, 'decimal')
line = fillstr(line, str(p.get_parameter('ped_accept')), 29, 'decimal')
line = fillstr(line, str(p.get_parameter('ped_ichkdir')), 39, 'decimal')
line = fillstr(line,
str(p.get_parameter('ped_ichkdir')), 39, 'decimal')
content += line
content += rule()
content += title(' ' * 22 + 'LEED EXPERIMENTAL PARAMETERS :', center=False)
content += title(' ' * 22 + 'LEED EXPERIMENTAL PARAMETERS :',
center=False)
content += rule()
line = create_line("IPHI,ITHETA,IE,IFTHET")
line = fillstr(line, str(p.get_parameter('leed_iphi')), 9, 'left')
@ -496,48 +529,57 @@ class SpecIO(object):
content += line
line = create_line("PHI0,THETA0,E0,R0")
line = fillstr(line, str(p.get_parameter('leed_phi0')), 9, 'decimal')
line = fillstr(line, str(p.get_parameter('leed_theta0')), 19, 'decimal')
line = fillstr(line,
str(p.get_parameter('leed_theta0')), 19, 'decimal')
line = fillstr(line, str(p.get_parameter('leed_e0')), 29, 'decimal')
line = fillstr(line, str(p.get_parameter('leed_r0')), 39, 'decimal')
content += line
line = create_line("PHI1,THETA1,E1,R1")
line = fillstr(line, str(p.get_parameter('leed_phi1')), 9, 'decimal')
line = fillstr(line, str(p.get_parameter('leed_theta1')), 19, 'decimal')
line = fillstr(line,
str(p.get_parameter('leed_theta1')), 19, 'decimal')
line = fillstr(line, str(p.get_parameter('leed_e1')), 29, 'decimal')
line = fillstr(line, str(p.get_parameter('leed_r1')), 39, 'decimal')
content += line
line = create_line("TH_INI,PHI_INI")
line = fillstr(line, str(p.get_parameter('leed_thini')), 9, 'decimal')
line = fillstr(line, str(p.get_parameter('leed_phiini')), 19, 'decimal')
line = fillstr(line,
str(p.get_parameter('leed_phiini')), 19, 'decimal')
content += line
line = create_line("IMOD,IMOY,ACCEPT,ICHKDIR")
line = fillstr(line, str(p.get_parameter('leed_imod')), 9, 'decimal')
line = fillstr(line, str(p.get_parameter('leed_imoy')), 19, 'decimal')
line = fillstr(line, str(p.get_parameter('leed_accept')), 29, 'decimal')
line = fillstr(line,
str(p.get_parameter('leed_accept')), 29, 'decimal')
line = fillstr(line, str(p.get_parameter('leed_ichkdir')), 39,
'decimal')
content += line
content += rule()
content += title(' ' * 21 + 'EXAFS EXPERIMENTAL PARAMETERS :', center=False)
content += title(' ' * 21 + 'EXAFS EXPERIMENTAL PARAMETERS :',
center=False)
content += rule()
line = create_line("EDGE,INITL,THLUM,PHILUM")
line = fillstr(line, str(p.get_parameter('exafs_edge')), 9, 'left')
line = fillstr(line, str(p.get_parameter('exafs_initl')), 19, 'left')
line = fillstr(line, str(p.get_parameter('exafs_thlum')), 29, 'decimal')
line = fillstr(line,
str(p.get_parameter('exafs_thlum')), 29, 'decimal')
line = fillstr(line, str(p.get_parameter('exafs_philum')), 39,
'decimal')
content += line
line = create_line("NE,EK_INI,EK_FIN,EPH_INI")
line = fillstr(line, str(p.get_parameter('exafs_ne')), 9, 'left')
line = fillstr(line, str(p.get_parameter('exafs_ekini')), 19, 'decimal')
line = fillstr(line, str(p.get_parameter('exafs_ekfin')), 29, 'decimal')
line = fillstr(line,
str(p.get_parameter('exafs_ekini')), 19, 'decimal')
line = fillstr(line,
str(p.get_parameter('exafs_ekfin')), 29, 'decimal')
line = fillstr(line, str(p.get_parameter('exafs_ephini')), 39,
'decimal')
content += line
content += rule()
content += title(' ' * 22 + 'AED EXPERIMENTAL PARAMETERS :', center=False)
content += title(' ' * 22 + 'AED EXPERIMENTAL PARAMETERS :',
center=False)
content += rule()
line = create_line("EDGE_C,EDGE_I,EDGE_A")
line = fillstr(line, str(p.get_parameter('aed_edgec')), 9, 'left')
@ -605,7 +647,8 @@ class SpecIO(object):
line = fillstr(line, str(p.get_parameter('eigval_ipwm')), 9, 'left')
line = fillstr(line, str(p.get_parameter('eigval_method')), 19, 'left')
line = fillstr(line, str(p.get_parameter('eigval_acc')), 29, 'decimal')
line = fillstr(line, str(p.get_parameter('eigval_expo')), 39, 'decimal')
line = fillstr(line,
str(p.get_parameter('eigval_expo')), 39, 'decimal')
content += line
line = create_line("N_MAX,N_ITER,N_TABLE,SHIFT")
line = fillstr(line, str(p.get_parameter('eigval_nmax')), 9, 'left')
@ -673,7 +716,8 @@ class SpecIO(object):
thfwd_arr = np.ones((nat))
path_filtering = p.extra_parameters['calculation'].get_parameter(
'path_filtering').value
if path_filtering != None and 'backward_scattering' in path_filtering:
if (path_filtering is not None and
'backward_scattering' in path_filtering):
ibwd_arr = np.ones((nat), dtype=np.int)
else:
ibwd_arr = np.zeros((nat), dtype=np.int)
@ -694,7 +738,8 @@ class SpecIO(object):
line = create_line("IPW,NCUT,PCTINT,IPP")
line = fillstr(line, str(p.get_parameter('calc_ipw')), 9, 'left')
line = fillstr(line, str(p.get_parameter('calc_ncut')), 19, 'left')
line = fillstr(line, str(p.get_parameter('calc_pctint')), 29, 'decimal')
line = fillstr(line,
str(p.get_parameter('calc_pctint')), 29, 'decimal')
line = fillstr(line, str(p.get_parameter('calc_ipp')), 39, 'left')
content += line
line = create_line("ILENGTH,RLENGTH,UNLENGTH")
@ -713,7 +758,8 @@ class SpecIO(object):
idcm = format(2, 'd')
temp = format(0., '.2f')
td = format(500., '.2f')
LOGGER.warning('Vibrational damping is disabled for this calculation.')
LOGGER.warning('Vibrational damping is disabled for this '
'calculation.')
else:
idwsph = str(p.get_parameter('calc_idwsph'))
idcm = str(p.get_parameter('calc_idcm'))
@ -757,8 +803,9 @@ class SpecIO(object):
content += title(' ' * 17 + 'INPUT FILES (PHD, EXAFS, LEED, AED, '
'APECS) :', center=False)
content += rule(tabs=(), symbol='-')
content += title(' ' * 8 + 'NAME' + ' ' * 20 + 'UNIT' + ' ' * 16 + 'TYPE',
center=False)
content += title(
' ' * 8 + 'NAME' + ' ' * 20 + 'UNIT' + ' ' * 16 + 'TYPE',
center=False)
content += rule(tabs=(5, 23, 7, 10))
line = create_line("DATA FILE,UNIT")
line = fillstr(line, str(p.get_parameter('input_data')), 9, 'right')
@ -791,8 +838,9 @@ class SpecIO(object):
center=False)
content += title(' ' * 28 + '(AUGER ELECTRON)', center=False)
content += rule(tabs=(), symbol='-')
content += title(' ' * 8 + 'NAME' + ' ' * 20 + 'UNIT' + ' ' * 16 + 'TYPE',
center=False)
content += title(
' ' * 8 + 'NAME' + ' ' * 20 + 'UNIT' + ' ' * 16 + 'TYPE',
center=False)
content += rule(tabs=(5, 23, 7, 10))
line = create_line("PHASE SHIFTS/TL FILE,UNIT")
line = fillstr(line, str(p.get_parameter('input2_tl')), 9, 'right')
@ -810,8 +858,9 @@ class SpecIO(object):
content += title(' ' * 29 + 'OUTPUT FILES :', center=False)
content += rule(tabs=(), symbol='-')
content += title(' ' * 8 + 'NAME' + ' ' * 20 + 'UNIT' + ' ' * 16 + 'TYPE',
center=False)
content += title(
' ' * 8 + 'NAME' + ' ' * 20 + 'UNIT' + ' ' * 16 + 'TYPE',
center=False)
content += rule(tabs=(5, 23, 7, 10))
line = create_line("CONTROL FILE,UNIT")
line = fillstr(line, str(p.get_parameter('output_log')), 9, 'right')
@ -826,7 +875,8 @@ class SpecIO(object):
line = fillstr(line, str(p.get_parameter('output_unit11')), 39, 'left')
content += line
line = create_line("AUGMENTED CLUSTER FILE,UNIT")
line = fillstr(line, str(p.get_parameter('output_augclus')), 9, 'right')
line = fillstr(line,
str(p.get_parameter('output_augclus')), 9, 'right')
line = fillstr(line, str(p.get_parameter('output_unit12')), 39, 'left')
content += line
content += rule(tabs=(5, 23, 7, 10))
@ -874,15 +924,13 @@ class SpecIO(object):
# backup the content in memory
old_content = content
"""
for key in ('NATP_M', 'NATCLU_M', 'NE_M', 'NEMET_M', 'LI_M', 'NL_M',
'NO_ST_M'):
required = requirements[key]
limit = self.malloc_parameters.get_parameter(key).value
value = required if required > limit else limit
content = re.sub(r'({:s}\s*=\s*)\d+'.format(key),
r'\g<1>{:d}'.format(value), content)
"""
# for key in ('NATP_M', 'NATCLU_M', 'NE_M', 'NEMET_M', 'LI_M', 'NL_M',
# 'NO_ST_M'):
# required = requirements[key]
# limit = self.malloc_parameters.get_parameter(key).value
# value = required if required > limit else limit
# content = re.sub(r'({:s}\s*=\s*)\d+'.format(key),
# r'\g<1>{:d}'.format(value), content)
for key in ('NAT_EQ_M', 'N_CL_N_M', 'NDIF_M', 'NSO_M', 'NTEMP_M',
'NODES_EX_M', 'NSPIN_M', 'NTH_M', 'NPH_M', 'NDIM_M',
@ -895,7 +943,6 @@ class SpecIO(object):
content = re.sub(r'({:s}\s*=\s*)\d+'.format(key),
r'\g<1>{:d}'.format(value), content)
modified = False
if content != old_content:
with open(filename, 'w') as fd:
@ -945,7 +992,7 @@ class SpecIO(object):
data = np.loadtxt(filename, skiprows=skip, unpack=True)
if len(data.shape) <= 1:
data = data.reshape((2,-1))
data = data.reshape((2, -1))
return data
def load_facdif(self, filename='facdif1.dat'):
@ -956,8 +1003,4 @@ class SpecIO(object):
pat = re.compile(r'ORDER\s+(\d+)\s+TOTAL NUMBER OF PATHS\s+:\s+(\d+)')
with open(filename, 'r') as fd:
content = fd.read()
#return pat.findall(content.replace('\n', '__cr__'))
return pat.findall(content)

View File

@ -1,5 +1,25 @@
# coding: utf-8
# vim: set et sw=4 ts=4 sts=4 nu ai cc=+0 fdm=indent mouse=a tw=80:
#!/usr/bin/env python
#
# Copyright © 2016-2020 - Rennes Physics Institute
#
# This file is part of msspec.
#
# msspec is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# msspec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this msspec. If not, see <http://www.gnu.org/licenses/>.
#
# Source file : src/msspec/calculator.py
# Last modified: ven. 10 avril 2020 17:19:24
# Committed by : "Sylvain Tricot <sylvain.tricot@univ-rennes1.fr>"
"""
Module calculator
=================
@ -21,54 +41,58 @@ For more information on MsSpec, follow this
"""
import inspect
import os
import re
import shutil
import sys
import re
import inspect
from subprocess import Popen, PIPE
from shutil import copyfile, rmtree
from datetime import datetime
import time
from io import StringIO
from collections import OrderedDict
from datetime import datetime
from io import StringIO
from shutil import copyfile
from shutil import rmtree
from subprocess import PIPE
from subprocess import Popen
from ase.calculators.calculator import Calculator
import ase.data
import ase.atom
import ase.atoms
import ase.data
import numpy as np
from ase.calculators.calculator import Calculator
from terminaltables.ascii_table import AsciiTable
from msspec import iodata
from msspec.data import electron_be
from msspec.calcio import PhagenIO
from msspec.calcio import SpecIO
from msspec.config import Config
from msspec.misc import (UREG, LOGGER, get_call_info,
get_level_from_electron_configuration,
XRaySource, set_log_output, log_process_output)
from msspec.utils import get_atom_index
from msspec.parameters import (PhagenParameters, PhagenMallocParameters,
SpecParameters, SpecMallocParameters,
GlobalParameters, MuffintinParameters,
TMatrixParameters, SourceParameters,
DetectorParameters, ScanParameters,
CalculationParameters,
PEDParameters, EIGParameters)
from msspec.calcio import PhagenIO, SpecIO
from msspec.data import electron_be
from msspec.misc import get_call_info
from msspec.misc import get_level_from_electron_configuration
from msspec.misc import log_process_output
from msspec.misc import LOGGER
from msspec.misc import set_log_output
from msspec.misc import UREG
from msspec.misc import XRaySource
from msspec.parameters import CalculationParameters
from msspec.parameters import DetectorParameters
from msspec.parameters import EIGParameters
from msspec.parameters import GlobalParameters
from msspec.parameters import MuffintinParameters
from msspec.parameters import PEDParameters
from msspec.parameters import PhagenMallocParameters
from msspec.parameters import PhagenParameters
from msspec.parameters import ScanParameters
from msspec.parameters import SourceParameters
from msspec.parameters import SpecMallocParameters
from msspec.parameters import SpecParameters
from msspec.parameters import TMatrixParameters
from msspec.phagen.fortran.libphagen import main as do_phagen
from msspec.spec.fortran import _phd_se_noso_nosp_nosym, _phd_mi_noso_nosp_nosym
from msspec.spec.fortran import _eig_mi
from msspec.spec.fortran import _eig_pw
from terminaltables.ascii_table import AsciiTable
from msspec.spec.fortran import _phd_mi_noso_nosp_nosym
from msspec.spec.fortran import _phd_se_noso_nosp_nosym
from msspec.utils import get_atom_index
class _MSCALCULATOR(Calculator):
@ -277,34 +301,33 @@ class _MSCALCULATOR(Calculator):
def run_phagen(self):
#include_fname = os.path.join(self.tmp_folder, 'src/msxas3.inc')
input_fname = os.path.join(self.tmp_folder, 'input/input.ms')
modified = self.phagenio.write_input_file(filename=input_fname)
#mod0 = self.phagenio.write_include_file(filename=include_fname)
mod1 = self.phagenio.write_input_file(filename=input_fname)
# Write the external potential file
pot = self.tmatrix_parameters.potential
if pot != 'muffin_tin':
inpot_fname = os.path.join(self.tmp_folder, 'output/fort.2')
mflag = pot.write(inpot_fname, self.phagenio.prototypical_atoms)
modified = modified or mflag
# Make a copy of the input potential file
dest = os.path.join(self.tmp_folder, 'input/extpot.dat')
shutil.copy(inpot_fname, dest)
self.modified = self.modified or mod1 #or mod0 or mod1
#if self.modified:
if mod1:
# run phagen
#self._make('tmatrix')
# Run if input files changed
if modified:
# Run phagen
os.chdir(os.path.join(self.tmp_folder, 'output'))
# copy external potential file to the workspace
if self.tmatrix_parameters.potential in ('lmto', 'spkkr', 'msf'):
fname = os.path.join(self.init_folder,
self.tmatrix_parameters.potential_file)
shutil.copy(fname, 'fort.2')
do_phagen()
# rename some output files to be more explicit
#os.rename('fort.10', 'cluster.clu')
#os.rename('fort.35', 'tmatrix.tl')
#os.rename('fort.55', 'tmatrix.rad')
#shutil.copy('fort.10', 'cluster.clu')
# Copy some output files to be more explicit
shutil.copy('clus/clus.out', 'cluster.clu')
shutil.copy('fort.35', 'tmatrix.tl')
shutil.copy('fort.55', 'tmatrix.rad')
# Load data
self.phagenio.load_tl_file('tmatrix.tl')
self.phagenio.load_cluster_file('cluster.clu')
self.phagenio.load_prototypical_atoms('div/molinpot3.out')
# Change back to the init_folder
os.chdir(self.init_folder)
@ -425,15 +448,19 @@ class _MSCALCULATOR(Calculator):
LOGGER.info("Getting the TMatrix...")
LOGGER.debug(get_call_info(inspect.currentframe()))
# If using an external potential, Phagen should be run twice,
# the first time with the internal MT potential.
pot = self.tmatrix_parameters.potential
if pot != 'muffin_tin':
LOGGER.info("Phagen is running first with MuffinTin potential...")
self.tmatrix_parameters.potential = "muffin_tin"
self.tmatrix_parameters.exchange_correlation = "hedin_lundqvist_complex"
self.run_phagen()
self.tmatrix_parameters.potential = pot
self.run_phagen()
filename = os.path.join(self.tmp_folder, 'output/tmatrix.tl')
tl = self.phagenio.load_tl_file(filename)
filename = os.path.join(self.tmp_folder, 'output/cluster.clu')
self.phagenio.load_cluster_file(filename)
tl = self.phagenio.tl
tl_threshold = self.tmatrix_parameters.get_parameter('tl_threshold')
if tl_threshold.value != None:
LOGGER.debug(" applying tl_threshold to %s...",

View File

@ -1,118 +0,0 @@
# coding: utf-8
"""
Module config
=============
"""
from configparser import NoSectionError
from configparser import SafeConfigParser as ConfigParser
import os
import sys
import fnmatch
from msspec.misc import LOGGER
class NoConfigFile(Exception): pass
class Config(object):
def __init__(self, **kwargs):
self.fname = os.path.join(os.environ['HOME'], '.config/msspec/pymsspec.cfg')
self.version = sys.modules['msspec'].__version__
self.config = ConfigParser()
self.defaults = {'path': 'None'}
self.defaults.update(kwargs)
# try to load the config file, create one with defaults if none is found
try:
self.options = self.read()
self.options.update(kwargs)
self.set(**self.options)
self.write()
except NoConfigFile:
# write a file with default options
self.write(defaults=True)
except NoSectionError:
# the file exists but has no options for this version of pymsspec
self.config.add_section(self.version)
self.set(**self.defaults)
self.write()
def read(self):
fp = self.config.read(self.fname)
if len(fp) == 0:
raise NoConfigFile
self.version = self.config.get('general', 'version')
return dict(self.config.items(self.version))
def set(self, **kwargs):
if not(self.config.has_section(self.version)):
self.config.add_section(self.version)
for k, v in list(kwargs.items()):
self.config.set(self.version, k, v)
def get(self, key):
return self.config.get(self.version, key)
def choose_msspec_folder(self, *folders):
print("Several folders containing the appropriate version of MsSpec were found.")
print("Please choose one tu use:")
s = ""
for i, f in enumerate(folders):
s += '{:d}) {:s}\n'.format(i, f)
print(s)
return(folders[int(input('Your choice: '))])
def find_msspec_folders(self):
version = sys.modules['msspec'].__version__
folders = []
i = 0
prompt = 'Please wait while scanning the filesystem (%3d found) '
sys.stdout.write(prompt % len(folders))
sys.stdout.write('\033[s')
for root, dirnames, filenames in os.walk('/home/stricot'):
sys.stdout.write('\033[u\033[k')
sys.stdout.write('%d folders scanned' % i)
i += 1
for fn in fnmatch.filter(filenames, 'VERSION'):
with open(os.path.join(root, fn), 'r') as fd:
try:
line = fd.readline()
if line.strip() == version:
folders.append(root)
sys.stdout.write('\033[2000D\033[k')
sys.stdout.write(prompt % len(folders))
except:
pass
sys.stdout.write('\033[u\033[k\n')
print('Done.')
return(folders)
def write(self, defaults=False):
if defaults:
self.set(**self.defaults)
with open(self.fname, 'w') as fd:
self.config.write(fd)
LOGGER.info("{} file written".format(self.fname))
def set_mode(self, mode="pymsspec"):
if not(self.config.has_section("general")):
self.config.add_section("general")
self.config.set("general", "mode", str(mode))
def get_mode(self):
return self.config.get("general", "mode")
def set_version(self, version=""):
if not(self.config.has_section("general")):
self.config.add_section("general")
self.config.set("general", "version", version)
def remove_version(self, version):
pass

View File

@ -1,2 +1,28 @@
#!/usr/bin/env python
#
# Copyright © 2016-2020 - Rennes Physics Institute
#
# This file is part of msspec.
#
# msspec is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# msspec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this msspec. If not, see <http://www.gnu.org/licenses/>.
#
# Source file : src/msspec/create_tests_results.py
# Last modified: ven. 10 avril 2020 17:29:16
# Committed by : "Sylvain Tricot <sylvain.tricot@univ-rennes1.fr>"
from msspec.tests import create_tests_results
create_tests_results()

View File

@ -1,4 +1,25 @@
# coding: utf-8
#!/usr/bin/env python
#
# Copyright © 2016-2020 - Rennes Physics Institute
#
# This file is part of msspec.
#
# msspec is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# msspec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this msspec. If not, see <http://www.gnu.org/licenses/>.
#
# Source file : src/msspec/iodata.py
# Last modified: ven. 10 avril 2020 17:23:11
# Committed by : "Sylvain Tricot <sylvain.tricot@univ-rennes1.fr>"
"""
Module iodata
=============
@ -47,29 +68,25 @@ Here is an example of how to store values in a Data object:
import os
import numpy as np
import h5py
from lxml import etree
import msspec
from msspec.misc import LOGGER
import ase.io
import sys
from distutils.version import LooseVersion
from distutils.version import StrictVersion
from io import StringIO
import wx
import ase.io
import h5py
import numpy as np
import wx.grid
from lxml import etree
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg
#from matplotlib.backends.backend_wxcairo import FigureCanvasWxCairo as FigureCanvas
#from matplotlib.backends.backend_wxcairo import NavigationToolbar2WxCairo
from matplotlib.figure import Figure
from terminaltables import AsciiTable
from distutils.version import StrictVersion, LooseVersion
import sys
#sys.path.append('../../MsSpecGui/msspecgui/msspec/gui')
import msspec
from msspec.msspecgui.msspec.gui.clusterviewer import ClusterViewer
from msspec.misc import LOGGER
def cols2matrix(x, y, z, nx=88*1+1, ny=360*1+1):
# mix the values of existing theta and new theta and return the
@ -1186,7 +1203,3 @@ if __name__ == "__main__":
import sys
data = Data.load(sys.argv[1])
data.view()

View File

@ -1,10 +1,34 @@
# coding: utf-8
# vim: set fdm=indent ts=4 sw=4 sts=4 et tw=80 ai cc=+0 mouse=a nu : #
#!/usr/bin/env python
#
# Copyright © 2016-2020 - Rennes Physics Institute
#
# This file is part of msspec.
#
# msspec is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# msspec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this msspec. If not, see <http://www.gnu.org/licenses/>.
#
# Source file : src/msspec/misc.py
# Last modified: ven. 10 avril 2020 17:30:42
# Committed by : "Sylvain Tricot <sylvain.tricot@univ-rennes1.fr>"
"""
Module misc
===========
"""
import logging
from pint import UnitRegistry
import numpy as np
@ -12,6 +36,7 @@ import inspect
import re
import os
class XRaySource(object):
MG_KALPHA = 1253.6
AL_KALPHA = 1486.6
@ -19,10 +44,10 @@ class XRaySource(object):
pass
UREG = UnitRegistry()
UREG.define('rydberg = c * h * rydberg_constant = Ry')
UREG.define('bohr_radius = 4 * pi * epsilon_0 * hbar**2 / electron_mass / e**2 = a0')
#UREG.define('rydberg = c * h * rydberg_constant = Ry')
#UREG.define('bohr_radius = 4 * pi * epsilon_0 * hbar**2 / electron_mass / e**2 = a0')
logging.basicConfig(level=logging.INFO)
#logging.basicConfig(level=logging.INFO)
LOGGER = logging.getLogger('msspec')
np.set_printoptions(formatter={'float': lambda x:'%.2f' % x}, threshold=5)

View File

@ -1,16 +1,47 @@
# coding: utf-8
# vim: set et ts=4 sw=4 nu fdm=indent:
#!/usr/bin/env python
#
# Copyright © 2016-2020 - Rennes Physics Institute
#
# This file is part of msspec.
#
# msspec is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# msspec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this msspec. If not, see <http://www.gnu.org/licenses/>.
#
# Source file : src/msspec/parameters.py
# Last modified: ven. 10 avril 2020 17:31:50
# Committed by : "Sylvain Tricot <sylvain.tricot@univ-rennes1.fr>"
"""
Module parameters
=================
"""
import textwrap
import numpy as np
import re
from terminaltables import AsciiTable
from msspec.misc import LOGGER, UREG, XRaySource, get_level_from_electron_configuration
import textwrap
import ase
import numpy as np
from terminaltables import AsciiTable
from msspec.misc import get_level_from_electron_configuration
from msspec.misc import LOGGER
from msspec.misc import UREG
from msspec.misc import XRaySource
from msspec.utils import ForeignPotential
from msspec.utils import SPRKKRPotential
class Parameter(object):
def __init__(self, name, types=None, limits=(None, None),
@ -31,7 +62,7 @@ class Parameter(object):
self.fmt = fmt
self.binding = binding
self.private = private
self.docstring = doc
self.docstring = textwrap.dedent(doc)
self._value = None
self.value = default
@ -59,41 +90,41 @@ class Parameter(object):
return value.to(self.unit).magnitude
return value
def assert_message(self, msg, *args):
s = '\'{}\': {}'.format(self.name, msg)
s = s.format(*args)
try:
allowed_types = '\n'.join(
['- ' + str(_) for _ in self.allowed_types])
except TypeError:
allowed_types = self.allowed_types
try:
allowed_values = '\n'.join(
['- ' + str(_) for _ in self.allowed_values])
except TypeError:
allowed_values = self.allowed_values
data = [
['PROPERTY', 'VALUE'],
['Name', '\'{}\''.format(self.name)],
['Allowed types', '{}'.format(allowed_types)],
['Limits', '{} <= value <= {}'.format(self.low_limit,
self.high_limit)],
['Unit', '{}'.format(self.unit)],
['Allowed values', '{}'.format(allowed_values)],
['Default', '{}'.format(self.default)]
]
t = AsciiTable(data)
table = '\n'.join(['\t' * 2 + _ for _ in t.table.split('\n')])
s = "{}\n\n{}\n{}".format(s, table, self.docstring)
return s
def check(self, value):
def assert_message(msg, *args):
s = '\'{}\': {}'.format(self.name, msg)
s = s.format(*args)
try:
allowed_types = '\n'.join(
['- ' + str(_) for _ in self.allowed_types])
except TypeError:
allowed_types = self.allowed_types
try:
allowed_values = '\n'.join(
['- ' + str(_) for _ in self.allowed_values])
except TypeError:
allowed_values = self.allowed_values
data = [
['PROPERTY', 'VALUE'],
['Name', '\'{}\''.format(self.name)],
['Allowed types', '{}'.format(allowed_types)],
['Limits', '{} <= value <= {}'.format(self.low_limit,
self.high_limit)],
['Unit', '{}'.format(self.unit)],
['Allowed values', '{}'.format(allowed_values)],
['Default', '{}'.format(self.default)]
]
t = AsciiTable(data)
table = '\n'.join(['\t' * 2 + _ for _ in t.table.split('\n')])
s = "{}\n\n{}\n{}".format(s, table, self.docstring)
return s
# convert if a unit was given
_value = self.convert(value)
@ -106,7 +137,7 @@ class Parameter(object):
assert bool in self.allowed_types
assert isinstance(_value, self.allowed_types)
except AssertionError:
raise AssertionError(assert_message(
raise AssertionError(self.assert_message(
'Type {} is not an allowed type for this option '
'({} allowed)',
str(type(_value)), str(self.allowed_types)))
@ -120,22 +151,22 @@ class Parameter(object):
# for i, val in enumerate(_values):
for val in np.array(_value).flatten():
if self.low_limit != None:
assert val >= self.low_limit, assert_message(
assert val >= self.low_limit, self.assert_message(
'Value must be >= {:s}',
str(self.low_limit))
if self.high_limit != None:
assert val <= self.high_limit, assert_message(
assert val <= self.high_limit, self.assert_message(
'Value must be <= {:s}',
str(self.high_limit))
if self.allowed_values != None and isinstance(val, tuple(type(x) for x in self.allowed_values)):
assert val in self.allowed_values, assert_message(
if self.allowed_values != None: # and isinstance(val, tuple(type(x) for x in self.allowed_values)):
assert val in self.allowed_values, self.assert_message(
'This value is not allowed. Please choose between '
'one of {:s}',
str(self.allowed_values))
if self.pattern != None:
p = re.compile(self.pattern)
m = p.match(val)
assert m != None, assert_message(
assert m != None, self.assert_message(
'Wrong string format')
# _value[i] = val
@ -157,8 +188,8 @@ class Parameter(object):
new_value = None
try:
new_value = self.binding(self)
except AttributeError:
pass
except AttributeError as err:
LOGGER.warning(err)
if new_value is not None:
self._value = new_value
# LOGGER.debug('{:s} = {:s}'.format(self.name, str(self.value)))
@ -716,7 +747,7 @@ class GlobalParameters(BaseParameters):
parameters = (
Parameter('spectroscopy', types=str, allowed_values=(
'PED', 'AED', 'LEED', 'EXAFS', 'EIG'), default='PED',
doc=textwrap.dedent("""
doc="""
There are 4 choices for the spectroscopy option:
- '**PED**', for Photo Electron Diffraction
@ -729,12 +760,12 @@ class GlobalParameters(BaseParameters):
matrix.
The value is case insensitive.
""")),
"""),
Parameter('algorithm', types=str, allowed_values=('expansion',
'inversion',
'correlation',
'power'),
default='expansion', doc=textwrap.dedent("""
default='expansion', doc="""
You can choose the algorithm used for the computation of the scattering path operator.
- '**inversion**', for the classical matrix inversion method
@ -745,10 +776,10 @@ class GlobalParameters(BaseParameters):
The series expansion algorithm is well suited for high energy since the number of terms
required decreases as the energy increases. The exact solution is obtained by the matrix inversion
method but should be preferably used for lower energy.
""")),
"""),
Parameter('polarization', types=(type(None), str),
allowed_values=(None, 'linear_qOz', 'linear_xOy',
'circular'), default=None, doc=textwrap.dedent("""
'circular'), default=None, doc="""
Specify the polarization of the incident light.
- **None**, for unpolarized light
@ -756,16 +787,16 @@ class GlobalParameters(BaseParameters):
- '**linear_xOy**' for a polarization vector in the :math:`(x0y)` plane
- '**circular**' for circular dichroism
""")),
"""),
Parameter('dichroism', types=(type(None), str),
allowed_values=(None, 'natural', 'sum_over_spin',
'spin_resolved'), default=None, doc=textwrap.dedent("""
'spin_resolved'), default=None, doc="""
Used to perform dichroic calculations. The default (None) is to disable this.
""")),
Parameter('spinpol', types=bool, default=False, doc=textwrap.dedent("""
"""),
Parameter('spinpol', types=bool, default=False, doc="""
Enable or disbale spin-resolved calculations.
""")),
Parameter('folder', types=str, default='./calc', doc=textwrap.dedent("""
"""),
Parameter('folder', types=str, default='./calc', doc="""
This parameter is the path to the temporary folder used for the calculations. If you do not change this
parameter between calculations, all the content will be overridden. This is usually not a problem, since the
whole bunch of data created during a computation is not meant to be saved. But you may want to anyway by
@ -781,7 +812,7 @@ class GlobalParameters(BaseParameters):
calc.shutdown() # the folder is removed
"""))
""")
)
BaseParameters.__init__(self)
self.add_parameters(*parameters)
@ -816,11 +847,11 @@ class GlobalParameters(BaseParameters):
class MuffintinParameters(BaseParameters):
def __init__(self, phagen_parameters, spec_parameters):
parameters = (
Parameter('charge_relaxation', types=bool, default=True, doc=textwrap.dedent("""
Parameter('charge_relaxation', types=bool, default=True, doc="""
Used to specify wether the charge density of the photoabsorbing atom, which is used
to construct the potential, is allowaed to relax around the core hole or not.
""")),
Parameter('ionicity', types=dict, default={}, doc=textwrap.dedent("""
"""),
Parameter('ionicity', types=dict, default={}, doc="""
A dictionary to specify the ionicity of each kind of atoms. If empty, the atoms are considered to be
neutral. Otherwise, each key must be a chemical symbol and the corresponding value should be the fraction
of electrons added (negative) or substracted (positive) with respect to neutrality.
@ -831,28 +862,28 @@ class MuffintinParameters(BaseParameters):
means that 0.15 electrons have been substracted from La, likewise from Fe. Neutrality implies that 0.3
electrons have to be added to oxygen atoms.
""")),
"""),
Parameter('relativistic_mode', types=str,
allowed_values=('non_relativistic', 'scalar_relativistic',
'spin_orbit_resolved'),
default='non_relativistic', doc=textwrap.dedent("""
default='non_relativistic', doc="""
To tell whether to use the scalar relativistic approximation or not.
""")),
"""),
Parameter('radius_overlapping', types=float, limits=(0., 1.),
default=0., doc=textwrap.dedent("""
default=0., doc="""
to allow atomic spheres to overlapp with each other. The value is a percentage, 1. means 100%.
""")),
"""),
Parameter('interstitial_potential', types=(int, float),
unit=UREG.eV, default=0., doc=textwrap.dedent("""
unit=UREG.eV, default=0., doc="""
The average interstitial potential (or inner potential) expressed in eV. It is used to compute
the refraction at the surface.
""")),
"""),
Parameter('hydrogen_radius', types=(int, float), default=0.9,
limits=(0., None), unit=UREG.angstroms, doc=textwrap.dedent("""
limits=(0., None), unit=UREG.angstroms, doc="""
The program can have difficulties to find the radius of the hydrogen atom (small atom). You can
specify here a value for the radius. If you set it to 'None', the calculation of the muffin-tin
radius of H atoms will be left to the program.
"""))
""")
)
BaseParameters.__init__(self)
self.add_parameters(*parameters)
@ -884,28 +915,28 @@ class MuffintinParameters(BaseParameters):
class TMatrixParameters(BaseParameters):
def __init__(self, phagen_parameters):
parameters = (
Parameter('potential', types=str,
allowed_values=('muffin_tin', 'lmto', 'spkkr', 'msf'),
default='muffin_tin', doc=textwrap.dedent("""
This option allows to choose which kind of potential is used to compute the T-Matrix. For now,
only the internal *Muffin-Tin* potential is supported.
""")),
Parameter('potential_file', types=(str,type(None)), default=None),
Parameter('potential', types=(str, ForeignPotential),
default='muffin_tin',
doc="""
This option allows to choose which kind of potential is
used to compute the T-Matrix. For now, only the internal
*Muffin-Tin* potential is supported.""",
),
Parameter('exchange_correlation', types=str,
allowed_values=('hedin_lundqvist_real',
'hedin_lundqvist_complex',
'x_alpha_real',
'dirac_hara_real', 'dirac_hara_complex'),
default='hedin_lundqvist_complex', doc=textwrap.dedent("""
default='hedin_lundqvist_complex', doc="""
Set the type of exchange and correlation potential that will be used.
""")),
Parameter('imaginery_part', types=(int, float), default=0., doc=textwrap.dedent("""
"""),
Parameter('imaginery_part', types=(int, float), default=0., doc="""
This value is added to complex potentials to account for core-hole lifetime and experimental resolution
broadening effects.
""")),
"""),
Parameter('lmax_mode', types=str,
allowed_values=('max_ke', 'true_ke', 'imposed'),
default='true_ke', doc=textwrap.dedent("""
default='true_ke', doc="""
This allows to control the number of basis functions used to expand the wave function on each
atom. It can be:
@ -919,11 +950,11 @@ class TMatrixParameters(BaseParameters):
:math:`l_{max} = kr_{at} + 1` where :math:`k=E^{1/2}_k` with :math:`E_k` being the kinetic
energy. In this case :math:`l_{max}` depends both on the energy and the atom number.
""")),
Parameter('lmaxt', types=int, limits=(1, None), default=19, doc=textwrap.dedent("""
"""),
Parameter('lmaxt', types=int, limits=(1, None), default=19, doc="""
The value of :math:`l_{max}` if *lmax_mode = 'imposed'*
""")),
Parameter('tl_threshold', types=(type(None), float), default=None, doc=textwrap.dedent("""
"""),
Parameter('tl_threshold', types=(type(None), float), default=None, doc="""
This option allows to control the number of basis function by defining a threshold value for the *tl*.
For example::
@ -934,8 +965,8 @@ class TMatrixParameters(BaseParameters):
.. note::
This option is compatible with any modes of the *lmax_mode* option.
""")),
Parameter('max_tl', types=(type(None), dict), default=None, doc=textwrap.dedent("""
"""),
Parameter('max_tl', types=(type(None), dict), default=None, doc="""
*max_tl* is used to sepcify a maximum number of basis functions to use for each kind of atoms. For example,
in the case of an MgO cluster, you could write::
@ -948,7 +979,7 @@ class TMatrixParameters(BaseParameters):
.. note::
This option is compatible with any modes of the *lmax_mode* option.
"""))
""")
)
BaseParameters.__init__(self)
self.add_parameters(*parameters)
@ -956,12 +987,17 @@ class TMatrixParameters(BaseParameters):
self.freeze()
def bind_potential(self, p):
mapping = {'muffin_tin': 'in', 'lmto': 'ex', 'spkkr': 'ex', 'msf': 'ex'}
if p.value.lower() in ('muffin_tin'):
mapping = {SPRKKRPotential: 'spkkr'}
if isinstance(p.value, str):
assert p.value.lower() in ('muffin_tin'), p.assert_message(
"\"{}\" is not an known potential type", p.value)
self.phagen_parameters.potgen = 'in'
elif p.value.lower() in ('spkkr', 'lmto', 'msf'):
elif isinstance(p.value, ForeignPotential):
self.phagen_parameters.potgen = 'ex'
self.phagen_parameters.potype = p.value.lower()
potype = mapping[p.value.__class__]
self.phagen_parameters.potype = potype
def bind_exchange_correlation(self, p):
potential = self.get_parameter('potential').value
@ -975,7 +1011,8 @@ class TMatrixParameters(BaseParameters):
}
self.phagen_parameters.potype = mapping[p.value]
else:
self.phagen_parameters.potype = potential
mapping = {SPRKKRPotential: 'spkkr'}
self.phagen_parameters.potype = mapping[potential.value.__class__]
def bind_potential_file(self, p):
pass
@ -1009,7 +1046,7 @@ class SourceParameters(BaseParameters):
def __init__(self, global_parameters=None, phagen_parameters=None, spec_parameters=None):
parameters = (
Parameter('energy', types=(list, tuple, int, float),
limits=(0, None), unit=UREG.eV, doc=textwrap.dedent("""
limits=(0, None), unit=UREG.eV, doc="""
The photon energy in eV.
Common laboratories X-ray source Mg |kalpha| and Al |kalpha| lines are
@ -1026,20 +1063,20 @@ class SourceParameters(BaseParameters):
1253.6
"""),
""",
default=XRaySource.MG_KALPHA),
Parameter('theta', types=(int, float), limits=(-180., 180.),
unit=UREG.degree, default=-55., doc=textwrap.dedent("""
unit=UREG.degree, default=-55., doc="""
The polar angle of the photon incidence (in degrees). Please refer to
:ref:`this figure <ped_full_picture>` for questions regarding the proper
orientation.
""")),
"""),
Parameter('phi', types=(int, float), limits=(-180., 180.),
unit=UREG.degree, default=0., doc=textwrap.dedent("""
unit=UREG.degree, default=0., doc="""
The azimuthal angle of the photon incidence (in degrees). Please refer to
:ref:`this figure <ped_full_picture>` for questions regarding the proper
orientation.
""")),
"""),
)
BaseParameters.__init__(self)
self.add_parameters(*parameters)
@ -1091,13 +1128,13 @@ class DetectorParameters(BaseParameters):
parameters = (
Parameter('angular_acceptance', types=(int, float),
unit=UREG.degree, limits=(0., None), default=0.,
doc=textwrap.dedent("""
doc="""
The angular acceptance of the detector in degrees used
when the *average_sampling* option is enabled below.
""")),
"""),
Parameter('average_sampling', types=(type(None), str),
allowed_values=(None, 'low', 'medium', 'high'),
default=None, doc=textwrap.dedent("""
default=None, doc="""
Used to averaged the signal over directions lying in the
cone of half-angle *angular_acceptance*. The number of
directions to take into account depends on the choosen
@ -1107,11 +1144,11 @@ class DetectorParameters(BaseParameters):
- '**low**', to average over 5 directions
- '**medium**', to average over 13 directions
- '**high**', to average over 49 directions
""")),
Parameter('rotate', types=bool, default=False, doc=textwrap.dedent("""
"""),
Parameter('rotate', types=bool, default=False, doc="""
When False, the sample is rotated when doing a scan (the
usual way). Otherwise, the detector is rotated.
"""))
""")
)
BaseParameters.__init__(self)
self.add_parameters(*parameters)
@ -1172,7 +1209,7 @@ class ScanParameters(BaseParameters):
default=np.array([0.])),
Parameter('kinetic_energy', types=(list, tuple, int, float),
unit=UREG.eV, limits=(0., None),
default=200., doc=textwrap.dedent("""
default=200., doc="""
if given as a list or tuple:
* with 2 elements, 10 points of energy will be generated
with the first element as the starting energy and the
@ -1183,7 +1220,7 @@ class ScanParameters(BaseParameters):
if given as a float or integer, there will be one point
for the kinetic energy.
""")),
"""),
Parameter('ke_array', types=np.ndarray, unit=UREG.eV,
default=np.array([200., ]), private=True)
)
@ -1380,48 +1417,48 @@ class CalculationParameters(BaseParameters):
def __init__(self, global_parameters, phagen_parameters, spec_parameters):
parameters = (
Parameter('RA_cutoff', types=int, limits=(0, 8), default=1,
doc=textwrap.dedent("""
doc="""
The Rehr-Albers cut-off parameter which controls the degree of
sphericity introduced in the description of the basis functions
used to expand the wave function around each atomic center.
It is only meaningful for the series expansion algorithm.
Its value is limited to 8 but it is rarely necessary to go beyond
2 or 3.""")),
2 or 3."""),
Parameter('scattering_order', types=int, limits=(1, 10), default=3,
doc=textwrap.dedent("""
doc="""
The scattering order. Only meaningful for the 'expansion' algorithm.
Its value is limited to 10.""")),
Its value is limited to 10."""),
Parameter('renormalization_mode', allowed_values=(None, 'G_n', 'Sigma_n',
'Z_n', 'Pi_1', 'Lowdin'),
types=(type(None), str), default=None,
doc=textwrap.dedent("""
doc="""
Enable the calculation of the coefficients for the renormalization of
the multiple scattering series.
You can choose to renormalize in terms of the :math:`G_n`, the
:math:`\\Sigma_n`, the :math:`Z_n`, the :math:`\\Pi_1` or the Lowdin
:math:`K^2` matrices""")),
:math:`K^2` matrices"""),
Parameter('renormalization_omega', types=(int,float,complex),
default=1.+0j,
doc=textwrap.dedent("""
doc="""
The :math:`\\omega` coefficient used to initialize the
renormalization alogorithm.""")),
renormalization alogorithm."""),
Parameter('RA_cutoff_damping', types=int, limits=(0, None),
default=0, doc=textwrap.dedent("""
default=0, doc="""
The Rehr-Albers truncation order. If > 0, the *RA_cutoff* is
decreased by 1 every *i*\ :sup:`th` scatterer until 0, where
*i* = *RA_cutoff_damping*.""")),
*i* = *RA_cutoff_damping*."""),
Parameter('spin_flip', types=bool, default=False,
doc=textwrap.dedent("""
doc="""
This parameter tells if spin-flip is authorized or not in the
scattering process.
:Note:
This option works only if the spin polarization is
enabled in your calculator object (see spinpol_).""")),
enabled in your calculator object (see spinpol_)."""),
Parameter('integrals', types=str, allowed_values=('all',
'diagonal'),
default='all', doc=textwrap.dedent("""
default='all', doc="""
This option allows to take into account all four radial integrals
(R++, R+-, R-+ and R--) in the calculation or only the diagonal
radial integrals (R++ and R--) which are generally much larger.
@ -1431,7 +1468,7 @@ class CalculationParameters(BaseParameters):
This option works only if the spin polarization is
enabled in your calculator object.
""")),
"""),
Parameter('path_filtering', types=(type(None), str, tuple, list),
allowed_values=(None,
'forward_scattering',
@ -1439,66 +1476,66 @@ class CalculationParameters(BaseParameters):
'distance_cutoff',
'plane_wave_normal',
'plane_wave_spin_averaged'),
default=None, doc=textwrap.dedent("""
default=None, doc="""
Used to activate some filters. It is possible to specify several
of them by grouping them in a tuple or a list. For example::
>>> my_filters = ('forward_scattering', 'backward_scattering')
>>> calc.calculation_parameters.path_filtering = my_filters
""")),
"""),
Parameter('off_cone_events', types=int, limits=(0, None), default=1,
doc=textwrap.dedent("""
doc="""
Used in conjunction with the '*forward_scattering*' filter.
If the number of scattering processes outside the forward (or
backward) scattering cone is greater than this number, then the
path is rejected and its contribution to the scattering path
operator wont be computed.
""")),
"""),
Parameter('scattering_order_cutoff', types=int, limits=(0, 10),
default=2, doc=textwrap.dedent("""
default=2, doc="""
Used in conjunction with the *plane_wave_normal* filter. It states
to activate the plane wave approximation (which is fast but
less accurate) to compute the contribution when the scattering order
is greater than this value.""")),
is greater than this value."""),
Parameter('distance', types=(int, float), limits=(0, None),
unit=UREG.angstroms, default=10., doc=textwrap.dedent("""
unit=UREG.angstroms, default=10., doc="""
Used with the '*distance_cut_off*' filter. Paths whose length is
larger than this value are simply rejected.""")),
larger than this value are simply rejected."""),
Parameter('vibrational_damping', types=(type(None), str),
allowed_values=(None, 'debye_waller', 'averaged_tl'),
default='debye_waller', doc=textwrap.dedent("""
default='debye_waller', doc="""
Tells how to compute the effect of atomic vibrations. It can be:
- '**debye_waller**' for using the Debye Waller model.
- '**averaged_tl**' to use the more correct averaging over T-matrix elements.""")),
- '**averaged_tl**' to use the more correct averaging over T-matrix elements."""),
Parameter('temperature', types=(int, float), limits=(0, None),
unit=UREG.degK, default=293., doc=textwrap.dedent("""
unit=UREG.degK, default=293., doc="""
The temperature of the cluster. Used when *use_debye_model* = True
""")),
"""),
Parameter('debye_temperature', types=(int, float), limits=(0, None),
unit=UREG.degK, default=420., doc=textwrap.dedent("""
unit=UREG.degK, default=420., doc="""
The Debye temperature used for the calculation of the mean square
displacements if *use_debye_model* = True""")),
displacements if *use_debye_model* = True"""),
Parameter('use_debye_model', types=bool, default=False,
doc=textwrap.dedent("""
doc="""
No matter the way you compute the effect of atomic vibrations,
you need the mean square displacements of atoms. It can be computed
internally following the Debye model if you set this option to True.
""")),
"""),
Parameter('vibration_scaling', types=(int, float),
limits=(0., None), default=1.2, doc=textwrap.dedent("""
limits=(0., None), default=1.2, doc="""
Used to simulate the fact that surface atoms vibrate more than
bulk ones. It is a factor applied to the mean square displacements.
""")),
"""),
Parameter('basis_functions', types=str, allowed_values=(
'plane_wave', 'spherical'), default='spherical', private=True),
Parameter('cutoff_factor', types=(int, float),
limits=(1e-4, 999.9999), default=0.01, private=True),
Parameter('mean_free_path', types=(int, float, str),
default='SeahDench', allowed_values=('mono', 'SeahDench'),
doc=textwrap.dedent("""
doc="""
The electron mean free path value. You can either:
- Enter a value (in Angströms), in this case any value <=0 will disable the damping
- Enter the keyword 'mono' to use a formula valid only for monoelemental samples
@ -1510,7 +1547,7 @@ class CalculationParameters(BaseParameters):
to a real potential as, when the potential is complex, this damping is taken care
of by the imaginery part othe potential.
""")),
"""),
)
BaseParameters.__init__(self)
@ -1728,7 +1765,7 @@ class PEDParameters(BaseParameters):
def __init__(self, phagen_parameters, spec_parameters):
parameters = (
Parameter('level', types=str, pattern=r'\d+[spdfgSPDFG](\d/2)?$',
default='1s', doc=textwrap.dedent("""
default='1s', doc="""
The level is the electronic level where the electron comes from.
It is written: *nlJ*
where:
@ -1742,7 +1779,7 @@ class PEDParameters(BaseParameters):
>>> calc.spectroscopy_parameters.level = '2p3/2'
>>> calc.spectroscopy_parameters.level = '2p' # is equivalent to '2p1/2'
""")),
"""),
Parameter('final_state', types=int, limits=(-1, 2), default=2),
Parameter('spin_orbit', types=(type(None), str),
allowed_values=(None, 'single', 'both'), default=None),
@ -1779,7 +1816,7 @@ class EIGParameters(BaseParameters):
def __init__(self, phagen_parameters, spec_parameters):
parameters = (
Parameter('level', types=str, pattern=r'\d+[spdfgSPDFG](\d/2)?$',
default='1s', doc=textwrap.dedent("""
default='1s', doc="""
The level is the electronic level where the electron comes from.
It is written: *nlJ*
where:
@ -1793,21 +1830,21 @@ class EIGParameters(BaseParameters):
>>> calc.spectroscopy_parameters.level = '2p3/2'
>>> calc.spectroscopy_parameters.level = '2p' # is equivalent to '2p1/2'
""")),
"""),
Parameter('final_state', types=int, limits=(-1, 2), default=2),
Parameter('spin_orbit', types=(type(None), str),
allowed_values=(None, 'single', 'both'), default=None),
Parameter('kernel_matrix_spectrum', types=(bool,), default=False, doc=textwrap.dedent("""
Parameter('kernel_matrix_spectrum', types=(bool,), default=False, doc="""
Whether to output the kernel matrix spectrum for each energy point.
""")),
"""),
Parameter('method', types=(str,), default='EPSI',
allowed_values=['AITK', 'RICH', 'SALZ', 'EPSI', 'EPSG',
'RHOA', 'THET', 'LEGE', 'CHEB', 'OVER',
'DURB', 'DLEV', 'TLEV', 'ULEV', 'VLEV',
'ELEV', 'EULE', 'GBWT', 'VARI', 'ITHE',
'EALG'],
doc=textwrap.dedent("""The convergence acceleration scheme to be used.
""")),
doc="""The convergence acceleration scheme to be used.
"""),
)
BaseParameters.__init__(self)
self.add_parameters(*parameters)
@ -1832,5 +1869,3 @@ class EIGParameters(BaseParameters):
def bind_kernel_matrix_spectrum(self, p):
value = int(p.value)
self.spec_parameters.eigval_ispectrum_ne = value

View File

@ -1,21 +1,41 @@
# coding: utf-8
#!/usr/bin/env python
#
# Copyright © 2016-2020 - Rennes Physics Institute
#
# This file is part of msspec.
#
# msspec is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# msspec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this msspec. If not, see <http://www.gnu.org/licenses/>.
#
# Source file : src/msspec/tests.py
# Last modified: ven. 10 avril 2020 17:33:28
# Committed by : "Sylvain Tricot <sylvain.tricot@univ-rennes1.fr>"
from msspec.calculator import MSSPEC
from msspec.utils import *
from msspec.misc import set_log_level
from ase.build import bulk
import os
import sys
import unittest
from hashlib import md5
from pickle import dumps
import unittest
import sys
import os
from ase.build import bulk
from msspec.calculator import MSSPEC
from msspec.misc import set_log_level
from msspec.utils import *
set_log_level('error')
RESULTS_FILENAME = os.path.join(os.path.dirname(__file__), 'results.txt')
def perform_test(obj, funcname, filename=RESULTS_FILENAME):
f = getattr(obj, '_' + funcname)
output = md5(dumps(f())).hexdigest()

View File

@ -1,5 +1,26 @@
# -*- encoding: utf-8 -*-
# vim: set fdm=indent ts=4 sw=4 sts=4 et tw=80 ai cc=+0 mouse=a nu : #
#!/usr/bin/env python
#
# Copyright © 2016-2020 - Rennes Physics Institute
#
# This file is part of msspec.
#
# msspec is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# msspec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this msspec. If not, see <http://www.gnu.org/licenses/>.
#
# Source file : src/msspec/utils.py
# Last modified: ven. 10 avril 2020 15:49:35
# Committed by : "Sylvain Tricot <sylvain.tricot@univ-rennes1.fr>"
"""
Module utils
@ -8,20 +29,159 @@ Module utils
"""
import re
import numpy as np
from ase import Atoms, Atom
from ase.visualize import view
from ase import Atom
from ase import Atoms
class MsSpecAtoms(Atoms):
def __init__(self, *args, **kwargs):
Atoms.__init__(self, *args, **kwargs)
self.__absorber_index = None
from msspec.iodata import Data
from msspec.misc import LOGGER
def set_absorber(self, index):
self.__absorber_index = index
def get_absorber(self):
return self.__absorber_index
class ForeignPotential(object):
def __init__(self):
self.data = Data(title='Foreign Potential')
# Load exported potentials
# phagen_data is a dictionary with:
# self.phagen_data = {
# 'VintTotal' : <float>,
# 'VintCoulomb': <float>,
# 'RHOint' : <float>,
# 'types': [
# {
# 'Z' : <int>,
# 'RWS' : <float>,
# 'data': <np.array(..., 4, dtype=float)>
# },
# ...
# ...
# ...
# ]
# }
self.phagen_data = {'types': []}
def write(self, filename, prototypical_atoms):
LOGGER.debug(f"Writing Phagen input potential file: {filename}")
def append_atom_potential(atom):
Z = atom.number
# Find the right type (Z) in the phagen_data
itypes = []
for i, t in enumerate(self.phagen_data['types']):
if t['Z'] == Z:
itypes.append(i)
# Check now that we have only one type in the list
# otherwise we do not know yet how to deal with this.
assert len(itypes) > 0, f"Cannot find the data for atom with Z={Z}"
assert len(itypes) == 1, f"Too many datasets for atom with Z={Z}"
# So far so good, let's write the block
t = self.phagen_data['types'][itypes[0]]
s = "{:<7d}{:<10d}{:1.4f}\n".format(
t['Z'], len(t['data']), t['RWS'])
line_fmt = "{:+1.8e} " * 4 + "\n"
for row in t['data']:
s += line_fmt.format(*row)
return s
content = ""
# Start by writing the header line
content += "{:.2f} {:.4f} {:.2f}\n".format(
self.phagen_data['VintCoulomb'],
self.phagen_data['RHOint'],
self.phagen_data['VintTotal'])
# Then for each atom in the given prototypical cluster,
# write the data block
for atom in prototypical_atoms:
content += append_atom_potential(atom)
# Write the content to filename
try:
with open(filename, 'r') as fd:
old_content = fd.read()
except IOError:
old_content = ''
modified = False
if content != old_content:
with open(filename, 'w') as fd:
fd.write(content)
modified = True
return modified
class SPRKKRPotential(ForeignPotential):
def __init__(self, atoms, potfile, *exported_files):
super().__init__()
def read(content, pattern, types):
# compile the pattern for regex matching
pat = re.compile(pattern, re.MULTILINE)
# get the keys and data as list of strings
keys = re.split(r'\s+',
pat.search(content).group('KEYS').strip(' \n'))
txt = pat.search(content).group('DATA').strip('\n').split('\n')
data = []
for line in txt:
# Unpacking values
values_txt = re.split(r'\s+', line.strip())
data_dict = {}
for i, _ in enumerate(values_txt):
# Type casting
value = types[i].__call__(_)
data_dict[keys[i]] = value
# push to the list
data.append(data_dict)
return data
# load info in *.pot file
with open(potfile, 'r') as fd:
content = fd.read()
self.sites_data = read(content,
(r'^\s*SITES\s*\n((.*\n)+?\s*(?P<KEYS>IQ.*)\n'
r'(?P<DATA>(.*\n)+?))\*+'),
[int] + [float] * 3)
self.types_data = read(content,
(r'^\s*TYPES\s*\n(\s*(?P<KEYS>IT.*)\n'
r'(?P<DATA>(.*\n)+?))\*+'),
[int, str] + [int] * 4)
self.occ_data = read(content,
(r'^\s*OCCUPATION\s*\n(\s*(?P<KEYS>IQ.*)\n'
r'(?P<DATA>(.*\n)+?))\*+'),
[int] * 5 + [float])
for f in exported_files:
# get the IT from the filename
# m=re.match('SPRKKR-IT_(?P<IT>\d+)-PHAGEN.*', os.path.basename(f))
# it = int(m.group('IT'))
# load the content of the header (2 lines)
with open(f, 'r') as fd:
first_line = fd.readline().strip('\n')
second_line = fd.readline().strip('\n')
# load Coulomb and Total interstitial potential
pattern = (r'#\s*VMTZ_TOTAL\s*=\s*(?P<TOTAL>.*?)\s+'
r'VMTZ_Coulomb\s*=\s*(?P<COULOMB>.*?)\s+.*$')
m = re.match(pattern, first_line)
self.phagen_data.update(VintCoulomb=float(m.group('COULOMB')),
VintTotal=float(m.group('TOTAL')),
RHOint=0.)
# load Z, Wigner-Seitz radius from 2nd line of header
type_data = {}
_ = re.split(r'\s+', second_line.strip("# "))
type_data.update(Z=int(_[0]), RWS=float(_[3]))
# load the data
data = np.loadtxt(f, comments='#')
type_data.update(data=data)
self.phagen_data['types'].append(type_data)
class EmptySphere(Atom):
def __init__(self, *args, **kwargs):
@ -30,135 +190,117 @@ class EmptySphere(Atom):
def get_atom_index(atoms, x, y, z):
""" Return the index of the atom that is the closest to the coordiantes
given as parameters.
""" Return the index of the atom that is the closest to the coordiantes
given as parameters.
:param ase.Atoms atoms: an ASE Atoms object
:param float x: the x position in angstroms
:param float y: the y position in angstroms
:param float z: the z position in angstroms
:param ase.Atoms atoms: an ASE Atoms object
:param float x: the x position in angstroms
:param float y: the y position in angstroms
:param float z: the z position in angstroms
:return: the index of the atom as an integer
:rtype: int
"""
# get all distances
d = np.linalg.norm(atoms.get_positions() - np.array([x, y, z]), axis = 1)
# get the index of the min distance
i = np.argmin(d)
# return the index and the corresponding distance
return i
:return: the index of the atom as an integer
:rtype: int
"""
# get all distances
d = np.linalg.norm(atoms.get_positions() - np.array([x, y, z]), axis=1)
# get the index of the min distance
i = np.argmin(d)
# return the index and the corresponding distance
return i
def center_cluster(atoms, invert=False):
""" Centers an Atoms object by translating it so the origin is roughly
at the center of the cluster.
The function supposes that the cluster is wrapped inside the unit cell,
with the origin being at the corner of the cell.
It is used in combination with the cut functions, which work only if the
origin is at the center of the cluster
:param ase.Atoms atoms: an ASE Atoms object
:param bool invert: if True, performs the opposite translation (uncentering the cluster)
"""
for i, cell_vector in enumerate(atoms.get_cell()):
if invert:
atoms.translate(0.5*cell_vector)
else:
atoms.translate(-0.5*cell_vector)
""" Centers an Atoms object by translating it so the origin is roughly
at the center of the cluster.
The function supposes that the cluster is wrapped inside the unit cell,
with the origin being at the corner of the cell.
It is used in combination with the cut functions, which work only if the
origin is at the center of the cluster
:param ase.Atoms atoms: an ASE Atoms object
:param bool invert: if True, performs the opposite translation
(uncentering the cluster)
"""
for i, cell_vector in enumerate(atoms.get_cell()):
if invert:
atoms.translate(0.5*cell_vector)
else:
atoms.translate(-0.5*cell_vector)
def cut_sphere(atoms, radius, center=(0, 0, 0)):
""" Removes all the atoms of an Atoms object outside a sphere with a
given radius
:param ase.Atoms atoms: an ASE Atoms object
:param float radius: the radius of the sphere
:return: The modified atom cluster
:rtype: ase.Atoms
"""
assert radius >= 0, "Please give a positive radius value"
radii = np.linalg.norm(atoms.positions - center, axis=1)
indices = np.where(radii <= radius)[0]
return atoms[indices]
def _cut_sphere(atoms, radius=None):
""" Removes all the atoms of an Atoms object outside a sphere with a
given radius
:param ase.Atoms atoms: an ASE Atoms object
:param float radius: the radius of the sphere
:return: The modified atom cluster
:rtype: ase.Atoms
"""
if radius is None:
raise ValueError("radius not set")
new_atoms = atoms.copy()
del_list = []
for index, position in enumerate(new_atoms.positions):
if np.linalg.norm(position) > radius:
del_list.append(index)
del_list.reverse()
for index in del_list:
del new_atoms[index]
return new_atoms
def cut_cylinder(atoms, axis="z", radius=None):
""" Removes all the atoms of an Atoms object outside a cylinder with a
given axis and radius
""" Removes all the atoms of an Atoms object outside a cylinder with a
given axis and radius
:param ase.Atoms atoms: an ASE Atoms object
:param str axis: string "x", "y", or "z". The axis of the cylinder, "z" by default
:param float radius: the radius of the cylinder
:param ase.Atoms atoms: an ASE Atoms object
:param str axis: string "x", "y", or "z". The axis of the cylinder,
"z" by default
:param float radius: the radius of the cylinder
:return: The modified atom cluster
:rtype: ase.Atoms
"""
if radius is None:
raise ValueError("radius not set")
:return: The modified atom cluster
:rtype: ase.Atoms
"""
if radius is None:
raise ValueError("radius not set")
new_atoms = atoms.copy()
new_atoms = atoms.copy()
dims = {"x": 0, "y": 1, "z": 2}
if axis in dims:
axis = dims[axis]
else:
raise ValueError("axis not valid, must be 'x','y', or 'z'")
dims = {"x": 0, "y": 1, "z": 2}
if axis in dims:
axis = dims[axis]
else:
raise ValueError("axis not valid, must be 'x','y', or 'z'")
del_list = []
for index, position in enumerate(new_atoms.positions):
# calculating the distance of the atom to the given axis
r = 0
for dim in range(3):
if dim != axis:
r = r + position[dim]**2
r = np.sqrt(r)
del_list = []
for index, position in enumerate(new_atoms.positions):
# calculating the distance of the atom to the given axis
r = 0
for dim in range(3):
if dim != axis:
r = r + position[dim]**2
r = np.sqrt(r)
if r > radius:
del_list.append(index)
if r > radius:
del_list.append(index)
del_list.reverse()
for index in del_list:
del new_atoms[index]
del_list.reverse()
for index in del_list:
del new_atoms[index]
return new_atoms
return new_atoms
def cut_cone(atoms, radius, z = 0):
def cut_cone(atoms, radius, z=0):
"""Shapes the cluster as a cone.
Keeps all the atoms of the input Atoms object inside a cone of based radius *radius* and of height *z*.
Keeps all the atoms of the input Atoms object inside a cone of based
radius *radius* and of height *z*.
:param atoms: The cluster to modify.
:type atoms: :py:class:`ase.Atoms`
:param radius: The base cone radius in :math:`\mathring{A}`.
:param radius: The base cone radius in :math:`\mathring{A}`. # noqa: W605
:type radius: float
:param z: The height of the cone in :math:`\mathring{A}`.
:param z: The height of the cone in :math:`\mathring{A}`. # noqa: W605
:type z: float
:return: A new cluster.
:rtype: :py:class:`ase.Atoms`
"""
new_atoms = atoms.copy()
origin = np.array((0, 0, 0))
max_theta = np.arctan(radius/(-z))
u = np.array((0, 0, -z))
@ -176,12 +318,12 @@ def cut_cone(atoms, radius, z = 0):
if theta <= max_theta:
indices.append(i)
new_atoms = new_atoms[indices]
new_atoms.translate(-u) # pylint: disable=invalid-unary-operand-type
new_atoms.translate(-u)
return new_atoms
def cut_plane(atoms, x=None, y=None, z=None):
""" Removes the atoms whose coordinates are higher (or lower, for a
negative cutoff value) than the coordinates given for every dimension.
@ -191,9 +333,9 @@ def cut_plane(atoms, x=None, y=None, z=None):
.. code-block:: python
cut_plane(atoms, x=[-5,5], y=3.6, z=0)
#every atom whose x-coordinate is higher than 5 or lower than -5, and/or
#y-coordinate is higher than 3.6, and/or z-coordinate is higher than 0
#is deleted.
# every atom whose x-coordinate is higher than 5 or lower than -5,
# and/or y-coordinate is higher than 3.6, and/or z-coordinate is higher
# than 0 is deleted.
:param ase.Atoms atoms: an ASE Atoms object
:param int x: x cutoff value
@ -206,9 +348,11 @@ def cut_plane(atoms, x=None, y=None, z=None):
dim_names = ('x', 'y', 'z')
dim_values = [x, y, z]
for i, (name, value) in enumerate(zip(dim_names, dim_values)):
assert isinstance(value, (int, float, list, tuple, type(None))), "Wrong type"
assert isinstance(value, (int, float, list, tuple, type(None))), \
"Wrong type"
if isinstance(value, (tuple, list)):
assert len(value) == 2 and np.all([isinstance(el, (int, float, type(None))) for el in value]), \
assert len(value) == 2 and np.all(
[isinstance(el, (int, float, type(None))) for el in value]), \
"Wrong length"
else:
try:
@ -216,7 +360,7 @@ def cut_plane(atoms, x=None, y=None, z=None):
dim_values[i] = [-np.inf, value]
else:
dim_values[i] = [value, np.inf]
except:
except Exception:
dim_values[i] = [value, value]
if dim_values[i][0] is None:
@ -227,15 +371,18 @@ def cut_plane(atoms, x=None, y=None, z=None):
dim_values = np.array(dim_values)
def constraint(coordinates):
return np.all(np.logical_and(coordinates >= dim_values[:,0], coordinates <= dim_values[:,1]))
return np.all(np.logical_and(coordinates >= dim_values[:, 0],
coordinates <= dim_values[:, 1]))
indices = np.where(list(map(constraint, atoms.positions)))[0]
return atoms[indices]
def hemispherical_cluster(cluster, emitter_tag=0, emitter_plane=0, diameter=0,
planes=0, shape='spherical'):
"""Creates and returns a cluster based on an Atoms object and some parameters.
"""Creates and returns a cluster based on an Atoms object and some
parameters.
:param cluster: the Atoms object used to create the cluster
:type cluster: Atoms object
@ -245,7 +392,8 @@ def hemispherical_cluster(cluster, emitter_tag=0, emitter_plane=0, diameter=0,
:type diameter: float
:param planes: the number of planes of your cluster
:type planes: integer
:param emitter_plane: the plane where your emitter will be starting by 0 for the first plane
:param emitter_plane: the plane where your emitter will be starting by 0
for the first plane
:type emitter_plane: integer
See :ref:`hemispherical_cluster_faq` for more informations.
@ -255,7 +403,8 @@ def hemispherical_cluster(cluster, emitter_tag=0, emitter_plane=0, diameter=0,
nmin = np.inf
for atom in cluster:
if ze - eps < atom.z < ze + eps and (atom.symbol == symbol or symbol == None):
if ze - eps < atom.z < ze + eps and (atom.symbol == symbol or
symbol is None):
n = np.sqrt(atom.x**2 + atom.y**2)
if (n < nmin):
nmin = n
@ -270,68 +419,115 @@ def hemispherical_cluster(cluster, emitter_tag=0, emitter_plane=0, diameter=0,
eps = 0.01 # a useful small value
c = cell[:, 2].max() # a lattice parameter
a = cell[:, 0].max() # a lattice parameter
p = np.alen(np.unique(np.round(cluster.get_positions()[:, 2], 4))) # the number of planes in the cluster
symbol = cluster[np.where(cluster.get_tags() == emitter_tag)[0][0]].symbol # the symbol of your emitter
assert (diameter != 0 or planes != 0), "At least one of diameter or planes parameter must be use."
# the number of planes in the cluster
p = np.alen(np.unique(np.round(cluster.get_positions()[:, 2], 4)))
# the symbol of your emitter
symbol = cluster[np.where(cluster.get_tags() == emitter_tag)[0][0]].symbol
assert (diameter != 0 or planes != 0), \
"At least one of diameter or planes parameter must be use."
if diameter == 0:
l = 1+2*(planes*c/p+1) # calculate the minimal diameter according to the number of planes
# calculate the minimal diameter according to the number of planes
min_diameter = 1+2*(planes*c/p+1)
else:
l = diameter
min_diameter = diameter
rep = int(2*l/min(a,c)) # number of repetition in each direction
cluster = cluster.repeat((rep, rep, rep)) # repeat the cluster
# number of repetition in each direction
rep = int(3*min_diameter/min(a, c))
center_cluster(cluster) # center the cluster
cluster.set_cell(cell) # reset the cell
cluster = cut_plane(cluster, z=eps) # cut the cluster so that we have a centered surface
# repeat the cluster
cluster = cluster.repeat((rep, rep, rep))
i = np.where(cluster.get_tags() == emitter_tag) # positions where atoms have the tag of the emitter_tag
all_ze = np.sort(np.unique(np.round(cluster.get_positions()[:, 2][i], 4))) # an array of all unique z corresponding to where we have the right atom's tag
all_z = np.sort(np.unique(np.round(cluster.get_positions()[:, 2], 4))) # an array of all unique z
# center the cluster
center_cluster(cluster)
n = np.where(all_z == all_z.max())[0][0] - np.where(all_z == all_ze.max())[0][0] # calculate the number of planes above the emitter's plane
ze = all_ze.max() # the height of the emitter's plane
# reset the cell
cluster.set_cell(cell)
# cut the cluster so that we have a centered surface
cluster = cut_plane(cluster, z=eps)
# if the number of planes above the emitter's plane is smaller than it must be, recalculate n and ze
# positions where atoms have the tag of the emitter_tag
i = np.where(cluster.get_tags() == emitter_tag)
# an array of all unique z corresponding to where we have the right
# atom's tag
all_ze = np.sort(np.unique(np.round(cluster.get_positions()[:, 2][i], 4)))
# an array of all unique z
all_z = np.sort(np.unique(np.round(cluster.get_positions()[:, 2], 4)))
# calculate the number of planes above the emitter's plane
n = np.where(all_z == all_z.max())[0][0] - np.where(
all_z == all_ze.max())[0][0]
# the height of the emitter's plane
ze = all_ze.max()
# if the number of planes above the emitter's plane is smaller than it must
# be, recalculate n and ze
while n < emitter_plane:
all_ze = all_ze[:-1]
n = np.where(all_z == all_z.max())[0][0] - np.where(all_z == all_ze.max())[0][0]
n = np.where(all_z == all_z.max())[0][0] - np.where(
all_z == all_ze.max())[0][0]
ze = all_ze.max()
# values of x and y of the emitter
tx, ty = get_xypos(cluster, ze, symbol)
tx, ty = get_xypos(cluster, ze, symbol) # values of x and y of the emitter
Atoms.translate(cluster, [-tx, -ty, 0]) # center the cluster on the emitter
# center the cluster on the emitter
Atoms.translate(cluster, [-tx, -ty, 0])
z_cut = all_z[np.where(all_z == all_ze.max())[0][0] + emitter_plane] # calculate where to cut to get the right number of planes above the emitter
Atoms.translate(cluster, [0, 0, -z_cut]) # translate the surface at z=0
cluster = cut_plane(cluster, z=eps) # cut the planes above those we want to keep
# calculate where to cut to get the right number of planes above the
# emitter
z_cut = all_z[np.where(all_z == all_ze.max())[0][0] + emitter_plane]
# translate the surface at z=0
Atoms.translate(cluster, [0, 0, -z_cut])
# cut the planes above those we want to keep
cluster = cut_plane(cluster, z=eps)
radius = diameter/2
if planes!=0:
all_z = np.sort(np.unique(np.round(cluster.get_positions()[:, 2], 4))) # an array of all unique remaining z
if planes != 0:
# an array of all unique remaining z
all_z = np.sort(np.unique(np.round(cluster.get_positions()[:, 2], 4)))
zplan = all_z[-planes]
xplan, yplan = get_xypos(cluster, zplan)
radius = np.sqrt(xplan**2 + yplan**2 + zplan**2)
if diameter!=0:
assert (radius <= diameter/2), "The number of planes is too high compared to the diameter."
if diameter != 0:
assert (radius <= diameter/2), ("The number of planes is too high "
"compared to the diameter.")
radius = max(radius, diameter/2)
if shape in ('spherical'):
cluster = cut_sphere(cluster, radius=radius + eps) # cut a sphere in our cluster with the diameter which is indicate in the parameters
# cut a sphere in our cluster with the diameter which is indicate in
# the parameters
cluster = cut_sphere(cluster, radius=radius + eps)
elif shape in ('cylindrical'):
cluster = cut_cylinder(cluster, radius=radius + eps) # cut a sphere in our cluster with the diameter which is indicate in the parameters
# cut a sphere in our cluster with the diameter which is indicate in
# the parameters
cluster = cut_cylinder(cluster, radius=radius + eps)
else:
raise NameError('Unkknown shape specifier: \"{}\"'.format(shape))
if planes!=0:
zcut = np.sort(np.unique(np.round(cluster.get_positions()[:, 2], 4)))[::-1][planes-1] - eps # calculate where to cut to get the right number of planes
cluster = cut_plane(cluster, z=zcut) # cut the right number of planes
if planes != 0:
# calculate where to cut to get the right number of planes
positions = np.unique(np.round(cluster.get_positions()[:, 2], 4))
zcut = np.sort(positions)[::-1][planes-1] - eps
all_z = np.sort(np.unique(np.round(cluster.get_positions()[:, 2], 4))) # an array of all unique remaining z
assert emitter_plane < np.alen(all_z), "There are not enough existing plans."
# cut the right number of planes
cluster = cut_plane(cluster, z=zcut)
# an array of all unique remaining z
all_z = np.sort(np.unique(np.round(cluster.get_positions()[:, 2], 4)))
assert emitter_plane < np.alen(all_z), ("There are not enough existing "
"plans.")
ze = all_z[- emitter_plane - 1] # the z-coordinate of the emitter
Atoms.translate(cluster, [0, 0, -ze]) # put the emitter in (0,0,0)

View File

@ -1,10 +1,33 @@
# coding: utf-8
# vim: set et sw=4 ts=4 sts=4 nu ai cc=+0 fdm=indent mouse=a:
#!/usr/bin/env python
#
# Copyright © 2016-2020 - Rennes Physics Institute
#
# This file is part of msspec.
#
# msspec is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# msspec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this msspec. If not, see <http://www.gnu.org/licenses/>.
#
# Source file : src/msspec/version.py
# Last modified: ven. 10 avril 2020 17:34:38
# Committed by : "Sylvain Tricot <sylvain.tricot@univ-rennes1.fr>"
from setuptools_scm import get_version
from pkg_resources import parse_version, DistributionNotFound, get_distribution
import os
from pkg_resources import DistributionNotFound
from pkg_resources import get_distribution
from pkg_resources import parse_version
from setuptools_scm import get_version
# find the version number
# 1- Try to read it from the git info
# 2- If it fails, try to read it from the distribution file

View File

@ -1,22 +1,31 @@
# coding: utf-8
# vim: set fdm=indent ts=4 sw=4 sts=4 et tw=80 ai cc=+0 mouse=a nu :
#!/usr/bin/env python
#
# Copyright © 2016-2020 - Rennes Physics Institute
#
# This file is part of msspec.
#
# msspec is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
from setuptools import setup, Extension, find_packages
from distutils.file_util import copy_file
# msspec is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
from distutils.command.build import build as _build
from setuptools.command.build_ext import build_ext as _build_ext
from setuptools.command.install import install as _install
from distutils.command.clean import clean as _clean
# You should have received a copy of the GNU General Public License
# along with this msspec. If not, see <http://www.gnu.org/licenses/>.
#
# Source file : src/setup.py
# Last modified: mar. 07 avril 2020 17:01:42
# Committed by : "Sylvain Tricot <sylvain.tricot@univ-rennes1.fr>"
import subprocess
import traceback
import os
from setuptools import setup, find_packages
from version import __version__
import sys
import glob
sys.path.insert(0, "msspec")
from version import __version__
with open('setup_requirements.txt', 'r') as fd:
SETUP_REQUIREMENTS = fd.read().strip().split('\n')
@ -26,46 +35,46 @@ with open('requirements.txt', 'r') as fd:
if __name__ == "__main__":
setup(name='msspec',
version=__version__,
include_package_data=True,
packages=find_packages(include='msspec.*'),
setup_requires=SETUP_REQUIREMENTS,
install_requires=REQUIREMENTS,
version=__version__,
include_package_data=True,
packages=find_packages(include='msspec.*'),
setup_requires=SETUP_REQUIREMENTS,
install_requires=REQUIREMENTS,
author='Didier Sébilleau, Sylvain Tricot',
author_email='sylvain.tricot@univ-rennes1.fr',
maintainer='Sylvain Tricot',
maintainer_email='sylvain.tricot@univ-rennes1.fr',
url='https://msspec.cnrs.fr',
description=('A multiple scattering package for sepectroscopies using '
'electrons to probe materials'),
long_description="""MsSpec is a Fortran package to compute the
cross-section of several spectroscopies involving one (or more)
electron(s) as the probe. This package provides a python interface to
control all the steps of the calculation.
author='Didier Sébilleau, Sylvain Tricot',
author_email='sylvain.tricot@univ-rennes1.fr',
maintainer='Sylvain Tricot',
maintainer_email='sylvain.tricot@univ-rennes1.fr',
url='https://msspec.cnrs.fr',
description=('A multiple scattering package for sepectroscopies '
'using electrons to probe materials'),
long_description="""MsSpec is a Fortran package to compute the
cross-section of several spectroscopies involving one (or more)
electron(s) as the probe. This package provides a python interface to
control all the steps of the calculation.
Available spectroscopies:
* Photoelectron diffraction
* Auger electron diffraction
* Low energy electron diffraction
* X-Ray absorption spectroscopy
* Auger Photoelectron coincidence spectroscopy
* Computation of the spectral radius""",
download_url='https://msspec.cnrs.fr/downloads.html',
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Console',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: GNU General Public License (GPL)',
'Natural Language :: English',
'Operating System :: Microsoft :: Windows :: Windows 10',
'Operating System :: POSIX :: Linux',
'Operating System :: MacOS :: MacOS X',
'Programming Language :: Fortran',
'Programming Language :: Python :: 3 :: Only',
'Topic :: Scientific/Engineering :: Physics',
Available spectroscopies:
* Photoelectron diffraction
* Auger electron diffraction
* Low energy electron diffraction
* X-Ray absorption spectroscopy
* Auger Photoelectron coincidence spectroscopy
* Computation of the spectral radius""",
download_url='https://msspec.cnrs.fr/downloads.html',
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Console',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: GNU General Public License (GPL)',
'Natural Language :: English',
'Operating System :: Microsoft :: Windows :: Windows 10',
'Operating System :: POSIX :: Linux',
'Operating System :: MacOS :: MacOS X',
'Programming Language :: Fortran',
'Programming Language :: Python :: 3 :: Only',
'Topic :: Scientific/Engineering :: Physics',
],
keywords='spectroscopy atom electron photon multiple scattering',
license='GPL',
keywords='spectroscopy atom electron photon multiple scattering',
license='GPL',
)