'''Reads structure files downloaded from the RRUFF database either as ASCII
text files or .rtf files that somehow are generated
'''
import sys
import numpy as np
import random as ran
from .. import GSASIIobj as G2obj
from .. import GSASIIspc as G2spc
from .. import GSASIIlattice as G2lat
[docs]
class RRUFFReader(G2obj.ImportPhase):
'''A fairly quickly-written importer to pull out the phase info from a
RRUFF database (https://rruff.info) text file.
'''
def __init__(self):
super(self.__class__,self).__init__( # fancy way to say ImportPhase.__init__
extensionlist=('.txt'),
strictExtension=True,
formatName = 'RRUFF DIF file',
longFormatName = 'RRUFF database DIF file download (*.txt)'
)
[docs]
def ContentsValidator(self, filename):
"Test if the file has CELL PARAMETERS: and SPACE GROUP: entries"
with open(filename,'r') as fp:
txt = fp.read()
status = True
for s in ('CELL PARAMETERS:','SPACE GROUP:'):
if not s in txt:
print(s,'not found')
if self.errors is None: self.errors = ''
self.errors += f'no {s} record found; not valid. '
status = False
if not ' ATOM ' in txt:
print('ATOM line not found')
if self.errors is None: self.errors = ''
self.errors += 'no ATOM record found; no structure. '
status = False
fp.close()
return status
[docs]
def Reader(self,filename,ParentFrame=None, **unused):
'Read a DIF file from RRUFF'
#self.errors = 'Error opening file'
Title = ''
atomsmode = False
fp = open(filename, 'r')
SGData = None
Atoms = []
cell = None
for line in fp.readlines():
if len(line) == 0: continue
line = line.strip()
if atomsmode:
# all DIF files appear to have atoms as element, X, Y, Z, OCCUPANCY, ISO(B)
if r'\par' in line: # some files seem to have some formatting
line = line.split('\\par')[0]
try:
Atype = line.split()[0]
x,y,z,Afrac,B = [float(i) for i in line.split()[1:]]
Uiso = B/(8*np.pi**2)
XYZ = np.array([float(x),float(y),float(z)])
XYZ = np.where(np.abs(XYZ)<0.00001,0,XYZ)
SytSym,Mult = G2spc.SytSym(XYZ,SGData)[:2]
IA = 'I'
i = 1
while f"{Atype}{i}" in [i[0] for i in Atoms]:
i += 1
if i > 999:
Aname = f"{Atype}?"
break
else:
Aname = f"{Atype}{i}"
if Atype.upper() in ['WA','OH','OW','OA','OB','OC','OD','OE','OL','OP','OO']:
Atype = 'O'
Atom = [Aname,Atype,'',x,y,z,Afrac,SytSym,Mult,IA,Uiso]
Atom += 6*[0]
Atom.append(ran.randint(0,sys.maxsize))
Atoms.append(Atom)
except:
atomsmode = False
break
if Title == '':
if '\\rtf' in line: continue
Title = line
if r'\par' in line: # some files seem to have some formatting
Title = line.split()[-1].split('\\')[0]
if 'CELL PARAMETERS:' in line:
L = line.split(':')[1]
if r'\par' in line: # some files seem to have some formatting
L = L.split('\\par')[0]
cellRec = L.split()
abc = cellRec[0:3]
angles = cellRec[3:]
cell=[float(abc[0]),float(abc[1]),float(abc[2]),
float(angles[0]),float(angles[1]),float(angles[2])]
Volume = float(G2lat.calc_V(G2lat.cell2A(cell)))
elif 'SPACE GROUP:' in line:
SGData = G2obj.P1SGData # P 1
S = line.split(':')[1].strip()
if r'\par' in S: # some files seem to have some formatting
S = S.split()[0]
Sinit = S
E,SGData = G2spc.SpcGroup(S)
if E:
SpGrpNorm = G2spc.StandardizeSpcName(S)
if SpGrpNorm:
E,SGData = G2spc.SpcGroup(SpGrpNorm)
if E and '_' in S:
S = S.replace('_','')
if E:
E,SGData = G2spc.SpcGroup(S[0]+' '+S[1:])
# some space group names that show up in RRUFF
SGfixDict = {'B2/b': 'B 2/b 1 1', 'Bb21m':'B b 21 m',
'P21/b': 'P 21/b 1 1', 'P21212': 'P 21 21 2',
'P21ca': 'P 21 c a', 'P21cn': 'P 21 c n',
'P21nb': 'P21 n b', 'P21nm': 'P21 n m',
'P63cm': 'P63 c m', 'P63mc': 'P63 m c',
'Pn21a': 'P n 21 a', 'Pn21m': 'P n 21 m'}
if E and S in SGfixDict:
E,SGData = G2spc.SpcGroup(SGfixDict[S])
if E:
self.warnings += f'ERROR in space group symbol {Sinit!r}'
self.warnings += '\nThe space group has been set to "P 1". '
self.warnings += "Change this in phase's General tab."
self.warnings += " Error msg="+G2spc.SGErrors(E)
elif SGData['SpGrp'] in G2spc.spg2origins:
self.warnings += f"WARNING space group {SGData['SpGrp']} has two Origins"
elif 'ATOM ' in line:
atomsmode = True
if SGData is None:
if self.errors is None: self.errors = ''
self.errors += 'no Space Group record found; not valid. '
return False
if cell is None:
if self.errors is None: self.errors = ''
self.errors += 'no CELL record found; not valid. '
return False
if len(Atoms) == 0:
if self.errors is None: self.errors = ''
self.errors += 'no Atoms found; not valid. '
return False
if cell[3] == cell[4] == cell[5] and cell[3] != 90:
self.warnings += f'Note: {filename!r} has rhombohedral cell, changing space group'
E,SGData = G2spc.SpcGroup(SGData['SpGrp'] + ' R')
self.MPhase = None
self.Phase = G2obj.SetNewPhase(Name=Title,SGData=SGData,cell=cell+[Volume,])
self.Phase['General']['Name'] = Title
self.Phase['General']['Type'] = 'nuclear'
self.Phase['General']['AtomPtrs'] = [3,1,7,9]
self.Phase['Atoms'] = Atoms
fp.close()
return True