feffdb 0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- feffdb-0.1/LICENSE +28 -0
- feffdb-0.1/MANIFEST.in +10 -0
- feffdb-0.1/PKG-INFO +62 -0
- feffdb-0.1/README.md +8 -0
- feffdb-0.1/feffdb/__init__.py +7 -0
- feffdb-0.1/feffdb/apps.py +77 -0
- feffdb-0.1/feffdb/feffdat.db +0 -0
- feffdb-0.1/feffdb/feffdb.py +318 -0
- feffdb-0.1/feffdb/feffpath.py +559 -0
- feffdb-0.1/feffdb/schema.py +80 -0
- feffdb-0.1/feffdb/simpledb.py +373 -0
- feffdb-0.1/feffdb/utils.py +359 -0
- feffdb-0.1/feffdb/version.py +24 -0
- feffdb-0.1/feffdb.egg-info/PKG-INFO +62 -0
- feffdb-0.1/feffdb.egg-info/SOURCES.txt +21 -0
- feffdb-0.1/feffdb.egg-info/dependency_links.txt +1 -0
- feffdb-0.1/feffdb.egg-info/entry_points.txt +2 -0
- feffdb-0.1/feffdb.egg-info/requires.txt +28 -0
- feffdb-0.1/feffdb.egg-info/scm_file_list.json +4406 -0
- feffdb-0.1/feffdb.egg-info/scm_version.json +8 -0
- feffdb-0.1/feffdb.egg-info/top_level.txt +1 -0
- feffdb-0.1/pyproject.toml +76 -0
- feffdb-0.1/setup.cfg +4 -0
feffdb-0.1/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FeffDB development team, including
|
|
4
|
+
- Samantha Liao, Cornell University
|
|
5
|
+
- Juanjuan Huang, Argonne National Laboratory
|
|
6
|
+
- Nina Andrejevic, Argonne National Laboratory
|
|
7
|
+
- Yanna Chen, Canadian Light Source
|
|
8
|
+
- Matthew Newville, The University of Chicago
|
|
9
|
+
- Shelly Kelly, Argonne National Laboratory
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
feffdb-0.1/MANIFEST.in
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
include README.md LICENSE AI_POLICY.md INSTALL MANIFEST.in setup.py pyproject.toml
|
|
2
|
+
exclude *.pyc core.* *~ *.pdf .deps .gitignore
|
|
3
|
+
recursive-include feffdb *
|
|
4
|
+
recursive-exclude feffdb/__pycache__ *
|
|
5
|
+
recursive-exclude tests *
|
|
6
|
+
recursive-exclude examples *
|
|
7
|
+
recursive-exclude doc *
|
|
8
|
+
recursive-exclude source_data *
|
|
9
|
+
recursive-exclude sandbox *
|
|
10
|
+
recursive-exclude doc/_build *
|
feffdb-0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: feffdb
|
|
3
|
+
Version: 0.1
|
|
4
|
+
Summary: Sqlite Database for Feff.dat files, especially for 1st shell EXAFS
|
|
5
|
+
Author-email: Matthew Newville <matt.newville@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/xraypy/feffdb
|
|
8
|
+
Project-URL: Documentation, https://xraypy.github.io/feffdb
|
|
9
|
+
Project-URL: Tracker, https://github.com/xraypy/feffdb/issues
|
|
10
|
+
Keywords: Feff,EXAFS
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Classifier: Operating System :: POSIX
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
19
|
+
Classifier: Programming Language :: Python
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: xraydb
|
|
30
|
+
Requires-Dist: numpy>=2.2
|
|
31
|
+
Requires-Dist: scipy
|
|
32
|
+
Requires-Dist: charset_normalizer
|
|
33
|
+
Requires-Dist: sqlalchemy>=2
|
|
34
|
+
Requires-Dist: pymatgen>=2025.6.14
|
|
35
|
+
Requires-Dist: pyshortcuts>=1.9.8
|
|
36
|
+
Requires-Dist: tabulate
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: build; extra == "dev"
|
|
39
|
+
Requires-Dist: twine; extra == "dev"
|
|
40
|
+
Provides-Extra: doc
|
|
41
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
42
|
+
Requires-Dist: sphinx-copybutton; extra == "doc"
|
|
43
|
+
Requires-Dist: sphinx-design; extra == "doc"
|
|
44
|
+
Requires-Dist: sphinxcontrib-video; extra == "doc"
|
|
45
|
+
Requires-Dist: jupyter_sphinx; extra == "doc"
|
|
46
|
+
Requires-Dist: nbsphinx; extra == "doc"
|
|
47
|
+
Provides-Extra: test
|
|
48
|
+
Requires-Dist: pytest; extra == "test"
|
|
49
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
50
|
+
Requires-Dist: coverage; extra == "test"
|
|
51
|
+
Provides-Extra: all
|
|
52
|
+
Requires-Dist: feffdb[dev,doc,test]; extra == "all"
|
|
53
|
+
Dynamic: license-file
|
|
54
|
+
|
|
55
|
+
# FeffDB
|
|
56
|
+
|
|
57
|
+
Feff DB is an SQLite3 database and Python library for the results of
|
|
58
|
+
Feff EXAFS calculations, and some support code to read and work with
|
|
59
|
+
this database and the data it contains. The initial motivation is to
|
|
60
|
+
provide "first-shell EXAFS" calculations for many common ligands or
|
|
61
|
+
atom pairs, so that these can be browsed and re-used without having to
|
|
62
|
+
setup and run Feff for many common cases.
|
feffdb-0.1/README.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# FeffDB
|
|
2
|
+
|
|
3
|
+
Feff DB is an SQLite3 database and Python library for the results of
|
|
4
|
+
Feff EXAFS calculations, and some support code to read and work with
|
|
5
|
+
this database and the data it contains. The initial motivation is to
|
|
6
|
+
provide "first-shell EXAFS" calculations for many common ligands or
|
|
7
|
+
atom pairs, so that these can be browsed and re-used without having to
|
|
8
|
+
setup and run Feff for many common cases.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from .utils import get_feffdb, is_feffdb, create_feffdb
|
|
2
|
+
from .feffdb import FeffDatabase
|
|
3
|
+
from .feffpath import feffpath, FeffDatFile
|
|
4
|
+
from .version import __version__, version_tuple
|
|
5
|
+
|
|
6
|
+
__all__ = ['get_feffdb', 'is_feffdb', 'create_feffdb', 'feffpath',
|
|
7
|
+
'FeffDatabase', 'FeffDatFile', '__version__', 'version_tuple']
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from argparse import ArgumentParser
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from tabulate import tabulate
|
|
5
|
+
import xraydb
|
|
6
|
+
from .utils import get_feffdb, create_feffdb
|
|
7
|
+
from .feffdb import FeffDatabase
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
VALID_ELEMS = [el.element for el in xraydb.get_xraydb().get_cache('elements')]
|
|
11
|
+
VALID_ELEMS.extend(['None', 'none', 'All', 'all'])
|
|
12
|
+
|
|
13
|
+
def feffdb_cli():
|
|
14
|
+
"""
|
|
15
|
+
feffdb command-line app
|
|
16
|
+
"""
|
|
17
|
+
dbname_default = get_feffdb().absolute().as_posix()
|
|
18
|
+
parser = ArgumentParser(description='Feff Database')
|
|
19
|
+
parser.add_argument('-n', '--name', dest='dbname',
|
|
20
|
+
default=None, help=f"database to use [{dbname_default}]" )
|
|
21
|
+
parser.add_argument('-c', '--create', action='store_true', default=False,
|
|
22
|
+
help="create new database")
|
|
23
|
+
parser.add_argument('--rmin', default=0,
|
|
24
|
+
help='minimum distance (Ang)')
|
|
25
|
+
parser.add_argument('--rmax', default=10,
|
|
26
|
+
help='maximum distance (Ang)')
|
|
27
|
+
parser.add_argument('absorber', nargs='?',
|
|
28
|
+
help='symbol for absorbing element (use "all" for all absorbers)')
|
|
29
|
+
parser.add_argument('scatterer', nargs='?',
|
|
30
|
+
help='symbol for scattering element')
|
|
31
|
+
|
|
32
|
+
args = parser.parse_args()
|
|
33
|
+
|
|
34
|
+
dbname = args.dbname or dbname_default
|
|
35
|
+
|
|
36
|
+
if Path(dbname).exists() and args.create:
|
|
37
|
+
print(f"database {dbname} already exists!")
|
|
38
|
+
|
|
39
|
+
if not Path(dbname).exists():
|
|
40
|
+
if args.create:
|
|
41
|
+
print("will create db ", dbname)
|
|
42
|
+
create_feffdb(name=dbname)
|
|
43
|
+
return
|
|
44
|
+
else:
|
|
45
|
+
print(f"database {dbname} does not exist, use '-c' to create")
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
feffdb = FeffDatabase(dbname, create_ok=False)
|
|
49
|
+
npaths = feffdb.list_feffdat()
|
|
50
|
+
if npaths is None or len(npaths) < 1:
|
|
51
|
+
print(f"database {dbname} exists but is empty")
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
absorber = args.absorber
|
|
57
|
+
if absorber not in VALID_ELEMS:
|
|
58
|
+
print(f"Unknown absorber: {absorber}, Must be valid atomic symbol or 'All' or 'None'")
|
|
59
|
+
|
|
60
|
+
scatterer = args.scatterer
|
|
61
|
+
if scatterer is not None and scatterer not in VALID_ELEMS:
|
|
62
|
+
print(f"Unknown scatterer: {scatterer} Must be valid atomic symbol or empty or 'All' or 'None'")
|
|
63
|
+
|
|
64
|
+
out = []
|
|
65
|
+
if absorber is not None or scatterer is not None:
|
|
66
|
+
if scatterer in ('All', 'all', 'None', 'none'):
|
|
67
|
+
scatterer = None
|
|
68
|
+
if absorber in ('All', 'all', 'None', 'none'):
|
|
69
|
+
absorber = None
|
|
70
|
+
rows = feffdb.list_feffdat(absorber=absorber, scatterer=scatterer,
|
|
71
|
+
rmin=float(args.rmin), rmax=float(args.rmax).
|
|
72
|
+
with_geometry=False)
|
|
73
|
+
out.append(row)
|
|
74
|
+
if len(out) > 0:
|
|
75
|
+
print(tabulate(out, headers='keys', tablefmt='psql'))
|
|
76
|
+
else:
|
|
77
|
+
parser.print_usage()
|
|
Binary file
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
#!/bin/env python
|
|
2
|
+
'''
|
|
3
|
+
This script creates an SQLite3 database for Feff Data
|
|
4
|
+
'''
|
|
5
|
+
import json
|
|
6
|
+
import lzma
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from pyshortcuts import hash_password, check_password_rules
|
|
9
|
+
from xraydb import atomic_number, atomic_symbol
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
from .simpledb import SimpleDB
|
|
13
|
+
from .utils import (get_feffdb, create_feffdb,
|
|
14
|
+
parse_cif, parse_feffinp, parse_feffdat)
|
|
15
|
+
|
|
16
|
+
def compress(val):
|
|
17
|
+
return lzma.compress(val.encode('utf-8'))
|
|
18
|
+
|
|
19
|
+
def decompress(val):
|
|
20
|
+
return lzma.decompress(val).decode('utf-8')
|
|
21
|
+
|
|
22
|
+
class FeffDatabase(SimpleDB):
|
|
23
|
+
def __init__(self, dbname=None, create_ok=False, read_only=False):
|
|
24
|
+
if dbname is not None:
|
|
25
|
+
dbpath = Path(dbname)
|
|
26
|
+
else:
|
|
27
|
+
try:
|
|
28
|
+
dbpath = get_feffdb()
|
|
29
|
+
except ValueError:
|
|
30
|
+
dbpath = None
|
|
31
|
+
|
|
32
|
+
if (dbpath is None or not dbpath.exists()) and create_ok:
|
|
33
|
+
create_feffdb(dbname=dbname)
|
|
34
|
+
|
|
35
|
+
self.dbname = dbpath.absolute().as_posix()
|
|
36
|
+
SimpleDB.__init__(self, dbname=self.dbname, server='sqlite',
|
|
37
|
+
read_only=read_only)
|
|
38
|
+
|
|
39
|
+
def __repr__(self):
|
|
40
|
+
return f"FeffDatabase('{self.dbname}')"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def __addrow(self, table, data):
|
|
44
|
+
"""add row to tablle, or return existing row with data"""
|
|
45
|
+
# first look if this already exists
|
|
46
|
+
row = self.get_rows(table, where=data,
|
|
47
|
+
limit_one=True, none_if_empty=True)
|
|
48
|
+
|
|
49
|
+
if row is None:
|
|
50
|
+
self.insert(table, **data)
|
|
51
|
+
row = self.get_rows(table, where=data,
|
|
52
|
+
limit_one=True, none_if_empty=True)
|
|
53
|
+
if row is None:
|
|
54
|
+
return None
|
|
55
|
+
return row.id
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def add_cif_file(self, cif_file):
|
|
59
|
+
"""add a CIF file to the database"""
|
|
60
|
+
try:
|
|
61
|
+
out = parse_cif(cif_file)
|
|
62
|
+
except ValueError:
|
|
63
|
+
print(f"error parsing {cif_file}")
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
text = compress(out.pop('text'))
|
|
67
|
+
fname = out.pop('filename')
|
|
68
|
+
dbargs = {k:v for k, v in out.items()}
|
|
69
|
+
dbargs['ciftext'] = text
|
|
70
|
+
if dbargs['source_db'] is None and fname is not None:
|
|
71
|
+
dbargs['source_db'] = fname
|
|
72
|
+
|
|
73
|
+
this_id = self.__addrow('cif', dbargs)
|
|
74
|
+
if this_id is None:
|
|
75
|
+
raise ValueError(f'could not add CIF: {cif_file}')
|
|
76
|
+
return this_id
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def add_feffinp(self, feff_inp, cif_file=None):
|
|
80
|
+
"""add a Feff input file to the database"""
|
|
81
|
+
cif_id = 0
|
|
82
|
+
if cif_file is not None:
|
|
83
|
+
cif_id = self.add_cif_file(cif_file)
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
finp = parse_feffinp(feff_inp)
|
|
87
|
+
except ValueError:
|
|
88
|
+
raise ValueError(f'error parsing feffinp : {feff_inp}')
|
|
89
|
+
|
|
90
|
+
text = compress(finp.pop('text'))
|
|
91
|
+
finp.pop('filename')
|
|
92
|
+
dbargs = {k:v for k, v in finp.items()}
|
|
93
|
+
dbargs['inptext'] = text
|
|
94
|
+
dbargs['cif_id'] = cif_id
|
|
95
|
+
|
|
96
|
+
this_id = self.__addrow('feffinp', dbargs)
|
|
97
|
+
if this_id is None:
|
|
98
|
+
raise ValueError(f'could not add feffinp : {feff_inp}')
|
|
99
|
+
return this_id
|
|
100
|
+
|
|
101
|
+
def add_feffdat(self, feffdat, feff_inp, cif_file=None,
|
|
102
|
+
label=None, description=None,
|
|
103
|
+
avoid_duplicates=True, rtoler=0.015):
|
|
104
|
+
"""add a Feff.dat file to the database"""
|
|
105
|
+
|
|
106
|
+
finp_id = self.add_feffinp(feff_inp, cif_file=cif_file)
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
dat = parse_feffdat(feffdat)
|
|
110
|
+
except ValueError:
|
|
111
|
+
raise ValueError(f'error parsing feff.dat file: {feffdat}')
|
|
112
|
+
|
|
113
|
+
text = compress(dat.pop('text'))
|
|
114
|
+
fname = dat.pop('filename')
|
|
115
|
+
|
|
116
|
+
if avoid_duplicates:
|
|
117
|
+
nearby = self.list_feffdat(absorber=dat['absorber'],
|
|
118
|
+
scatterer=dat['scatterer'],
|
|
119
|
+
edge=dat['edge'],
|
|
120
|
+
rmin=float(dat['reff'])-rtoler,
|
|
121
|
+
rmax=float(dat['reff'])+rtoler)
|
|
122
|
+
if len(nearby) > 0:
|
|
123
|
+
print("Avoiding Duplicate entries:")
|
|
124
|
+
s = nearby[0]
|
|
125
|
+
print('This: ', dat['absorber'], dat['scatterer'], dat['edge'], dat['reff'])
|
|
126
|
+
print(s['id'], s['label'], s['absorber'], s['scatterer'], s['edge'], s['reff'])
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
if description is None:
|
|
130
|
+
# default description is filenamae and a few parent folders
|
|
131
|
+
words = Path(fname).parts
|
|
132
|
+
n = min(len(words), 2)
|
|
133
|
+
description = Path(*words[-n:]).as_posix()
|
|
134
|
+
if label is None:
|
|
135
|
+
# default label combines absorber, scatterer, reff
|
|
136
|
+
words = [atomic_symbol(dat['absorber']),
|
|
137
|
+
atomic_symbol(dat['scatterer']),
|
|
138
|
+
str(round(100*dat['reff']))]
|
|
139
|
+
label = ''.join(words)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
if label is not None:
|
|
143
|
+
# check fie repeated rows
|
|
144
|
+
rows = self.get_rows('feffdat', where={'label': label},
|
|
145
|
+
none_if_empty=True)
|
|
146
|
+
if rows is not None:
|
|
147
|
+
words = [atomic_symbol(dat['absorber']),
|
|
148
|
+
atomic_symbol(dat['scatterer']),
|
|
149
|
+
str(round(100*dat['reff'])), '_', dat['edge']]
|
|
150
|
+
label = ''.join(words)
|
|
151
|
+
rows = self.get_rows('feffdat', where={'label': label},
|
|
152
|
+
none_if_empty=True)
|
|
153
|
+
|
|
154
|
+
if rows is not None:
|
|
155
|
+
olabel, i = label, 0
|
|
156
|
+
while rows is not None:
|
|
157
|
+
i += 1
|
|
158
|
+
label = f'{olabel}_{i}'
|
|
159
|
+
rows = self.get_rows('feffdat', where={'label': label},
|
|
160
|
+
none_if_empty=True)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
dbargs = {k:v for k, v in dat.items()}
|
|
164
|
+
dbargs['feffdat'] = text
|
|
165
|
+
dbargs['feffinp_id'] = finp_id
|
|
166
|
+
dbargs['label'] = label
|
|
167
|
+
dbargs['description'] = description
|
|
168
|
+
|
|
169
|
+
this_id = self.__addrow('feffdat', dbargs)
|
|
170
|
+
if this_id is None:
|
|
171
|
+
raise ValueError(f'could not add feff data: {feffdat}')
|
|
172
|
+
return this_id
|
|
173
|
+
|
|
174
|
+
def get_feffdat(self, feffid):
|
|
175
|
+
"""get text of feff.dat, either by table 'id' or
|
|
176
|
+
or by 'label' in feffdat table
|
|
177
|
+
"""
|
|
178
|
+
try:
|
|
179
|
+
where = {'id': int(feffid)}
|
|
180
|
+
except ValueError:
|
|
181
|
+
where = {'label': feffid}
|
|
182
|
+
|
|
183
|
+
row = self.get_rows('feffdat', where=where,
|
|
184
|
+
limit_one=True, none_if_empty=True)
|
|
185
|
+
if row is not None:
|
|
186
|
+
return decompress(row.feffdat)
|
|
187
|
+
|
|
188
|
+
def get_feffinp(self, feffinp_id):
|
|
189
|
+
"get text of feff.inp by id in feffinp table"
|
|
190
|
+
row = self.get_rows('feffinp', where={'id': feffinp_id},
|
|
191
|
+
limit_one=True, none_if_empty=True)
|
|
192
|
+
if row is not None:
|
|
193
|
+
return decompress(row.inptext)
|
|
194
|
+
|
|
195
|
+
def get_feffinp_for_feffdat(self, feffdat_id):
|
|
196
|
+
"get text of feff.inp for a Feff.dat file"
|
|
197
|
+
row = self.get_rows('feffdat', where={'id': feffdat_id},
|
|
198
|
+
limit_one=True, none_if_empty=True)
|
|
199
|
+
if row is not None:
|
|
200
|
+
trow = self.get_rows('feffinp', where={'id': row.feffinp_id},
|
|
201
|
+
limit_one=True, none_if_empty=True)
|
|
202
|
+
if trow is not None:
|
|
203
|
+
return decompress(trow.inptext)
|
|
204
|
+
|
|
205
|
+
def get_cifinp_for_feffinp(self, feffinp_id):
|
|
206
|
+
"get text of CIF for a feff.inp file"
|
|
207
|
+
row = self.get_rows('feffinp', where={'id': feffinp_id},
|
|
208
|
+
limit_one=True, none_if_empty=True)
|
|
209
|
+
if row is not None:
|
|
210
|
+
trow = self.get_rows('cif', where={'id': row.cif_id},
|
|
211
|
+
limit_one=True, none_if_empty=True)
|
|
212
|
+
if trow is not None:
|
|
213
|
+
return decompress(trow.ciftext)
|
|
214
|
+
|
|
215
|
+
def list_feffdat(self, absorber=None, scatterer=None, edge=None,
|
|
216
|
+
rmin=0., rmax=20.0, with_geometry=True):
|
|
217
|
+
"""get a list of feff.dat files matching on one or more criteria:
|
|
218
|
+
|
|
219
|
+
Arguments
|
|
220
|
+
------------
|
|
221
|
+
absorber (None or str) symbol for absorber [None for all]
|
|
222
|
+
scatterer (None or str) symbol for scatterer [None for all]
|
|
223
|
+
edge (None or str) string for absorption edge [None for all]
|
|
224
|
+
rmin float minimum R value [0.0]
|
|
225
|
+
rmax float maximum R value [20.0]
|
|
226
|
+
with_geometry bool whether to include 'geometry' [True]
|
|
227
|
+
Returns
|
|
228
|
+
--------
|
|
229
|
+
list of path dictionaries
|
|
230
|
+
"""
|
|
231
|
+
wargs = {}
|
|
232
|
+
if absorber is not None:
|
|
233
|
+
if isinstance(absorber, str):
|
|
234
|
+
absorber = atomic_number(absorber.title())
|
|
235
|
+
wargs['absorber'] = absorber
|
|
236
|
+
if scatterer is not None:
|
|
237
|
+
if isinstance(scatterer, str):
|
|
238
|
+
scatterer = atomic_number(scatterer.title())
|
|
239
|
+
wargs['scatterer'] = scatterer
|
|
240
|
+
if edge is not None:
|
|
241
|
+
wargs['edge'] = edge.title()
|
|
242
|
+
|
|
243
|
+
rows = self.get_rows('feffdat', where=wargs, limit_one=False)
|
|
244
|
+
out = []
|
|
245
|
+
for row in rows:
|
|
246
|
+
if row.reff > rmin and row.reff < rmax:
|
|
247
|
+
formula = '?'
|
|
248
|
+
finp = self.get_rows('feffinp', where={'id': row.feffinp_id},
|
|
249
|
+
limit_one=True, none_if_empty=True)
|
|
250
|
+
if finp is not None and finp.cif_id > 0:
|
|
251
|
+
cif = self.get_rows('cif', where={'id': finp.cif_id},
|
|
252
|
+
limit_one=True, none_if_empty=True)
|
|
253
|
+
if cif is not None:
|
|
254
|
+
formula = cif.formula
|
|
255
|
+
compound = cif.compound.lower()
|
|
256
|
+
|
|
257
|
+
rowdat = {'id': row.id,
|
|
258
|
+
'label': row.label,
|
|
259
|
+
'absorber': atomic_symbol(row.absorber),
|
|
260
|
+
'scatterer': atomic_symbol(row.scatterer),
|
|
261
|
+
'edge': row.edge,
|
|
262
|
+
'reff': row.reff,
|
|
263
|
+
'degen': row.degen,
|
|
264
|
+
'formula': formula,
|
|
265
|
+
'compound': compound,
|
|
266
|
+
'description': row.description}
|
|
267
|
+
if with_geometry:
|
|
268
|
+
rowdat['geometry'] = json.loads(row.geometry)
|
|
269
|
+
out.append(rowdat)
|
|
270
|
+
return out
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def add_person(self, email, name=None, password=''):
|
|
274
|
+
"""add a person (email, optional name) to feffdat table:
|
|
275
|
+
used for ratings and to identify added feff.dat files
|
|
276
|
+
"""
|
|
277
|
+
dbargs = {'email': email}
|
|
278
|
+
row = self.get_rows('person', where=dbargs,
|
|
279
|
+
limit_one=True, none_if_empty=True)
|
|
280
|
+
if row is not None:
|
|
281
|
+
if name is not None and name != row.name:
|
|
282
|
+
self.update('person', where=dbargs, name=name)
|
|
283
|
+
else:
|
|
284
|
+
print(f"warning person {email} already exisis")
|
|
285
|
+
else:
|
|
286
|
+
if name is not None:
|
|
287
|
+
dbargs['name'] = name
|
|
288
|
+
if password is None:
|
|
289
|
+
password = ''
|
|
290
|
+
if len(password) > 1:
|
|
291
|
+
password_ok = check_password_rules(password)
|
|
292
|
+
if not password_ok:
|
|
293
|
+
raise ValueError('Password is invalid')
|
|
294
|
+
dbargs['password'] = hash_password(password)
|
|
295
|
+
|
|
296
|
+
self.__addrow('person', dbargs)
|
|
297
|
+
|
|
298
|
+
def get_person(self, email):
|
|
299
|
+
"""get person by email"""
|
|
300
|
+
return self.get_rows('person', where={'email': email},
|
|
301
|
+
limit_one=True, none_if_empty=True)
|
|
302
|
+
|
|
303
|
+
def check_person_password(self, email, password):
|
|
304
|
+
"""check validity of a person's password"""
|
|
305
|
+
# if len(person
|
|
306
|
+
|
|
307
|
+
def get_feffdat_ratings(self, feffdat_id=None, email=None):
|
|
308
|
+
"""get all ratings for feff.dat file either by feffdat_id or by email
|
|
309
|
+
"""
|
|
310
|
+
args = {}
|
|
311
|
+
if feffdat_id is not None:
|
|
312
|
+
args['feffdat_id'] = feffdat_id
|
|
313
|
+
if email is not None:
|
|
314
|
+
person_row = self.get_person(email)
|
|
315
|
+
if person_row is not None:
|
|
316
|
+
args['person_row'] = person_row.id
|
|
317
|
+
|
|
318
|
+
return self.get_rows('feffdat_ratings', where=args)
|