10
0
mirror of https://github.com/LCPQ/QUESTDB_website.git synced 2024-12-27 06:43:47 +01:00
QUESTDB_website/tools/lib/data.py

332 lines
10 KiB
Python
Raw Normal View History

from collections import OrderedDict
2019-12-12 15:20:56 +01:00
from TexSoup import TexSoup
2020-08-02 16:24:48 +02:00
from .LaTeX import newCommand,extractMath
from .utils import getValFromCell,checkFloat
from TexSoup import TexNode,TexEnv
2019-11-25 11:47:24 +01:00
from enum import IntEnum,auto,unique,IntFlag
2020-07-03 14:51:12 +02:00
from .formats import getFormatHandlers
import re
2020-09-15 12:51:07 +02:00
import os
2019-12-12 15:20:25 +01:00
import numpy as np
import json
2019-11-25 11:55:25 +01:00
class state:
2020-09-30 14:18:34 +02:00
def __init__(self,number, multiplicity, symmetry):
self.number = number
self.multiplicity = multiplicity
2020-09-30 14:18:34 +02:00
self.symmetry = symmetry
2020-06-20 18:30:18 +02:00
@staticmethod
def fromString(string):
m=re.match(r"^(?P<number>\d)\s*\^(?P<multiplicity>\d)(?P<sym>\S*)",string)
num=m.group('number')
mul=m.group('multiplicity')
sym=m.group('sym')
return state(num,mul,sym)
@unique
2020-06-18 12:27:24 +02:00
class DataType(IntEnum):
ABS=auto()
FLUO=auto()
2020-07-03 14:51:12 +02:00
def datafileSelector(dataType):
switcher={
DataType.ABS:AbsDataFile,
DataType.FLUO:FluoDataFile,
}
return switcher[dataType]
2020-07-08 13:31:00 +02:00
def getSubtablesRange(table,firstindex=2,column=0,count=1):
subtablesRange=list()
2020-07-03 14:51:12 +02:00
i=firstindex+count
while i<np.size(table,0):
if str(table[i,column])!="":
subtablesRange.append(range(firstindex,i))
2020-07-03 14:51:12 +02:00
firstindex=i
i+=count
else:
i+=1
subtablesRange.append(range(firstindex,np.size(table,0)))
return subtablesRange
2020-07-03 14:51:12 +02:00
2020-09-20 17:53:58 +02:00
class exSet(object):
def __init__(self,name,index=0):
self.name=name
self.index=index
def __str__(self):
2020-09-23 12:08:02 +02:00
return f"{self.name},{self.index}"
2020-09-20 17:53:58 +02:00
@staticmethod
def fromString(string):
vals = string.split(",")
2020-09-23 15:21:23 +02:00
if len(vals)>1:
return exSet(vals[0],int(vals[1]))
else:
return exSet(vals[0])
2020-09-20 17:53:58 +02:00
def getDOI(self):
import yaml
from pathlib import Path
yamlpath=Path(__file__)/"../../statics/data/index.yaml"
with yamlpath.open("r") as f:
db = yaml.load(f,yaml.loader.FullLoader)
2020-09-23 12:08:02 +02:00
sets=db["sets"]
2020-09-20 17:53:58 +02:00
if self.name in db["sets"]:
2020-09-23 12:08:02 +02:00
return sets[self.name][self.index]
2020-09-20 17:53:58 +02:00
def isSameSet(self,otherSet):
2020-09-23 12:08:02 +02:00
return self.name == otherSet.name
2020-09-20 17:53:58 +02:00
def isSameArticle(self,otherSet):
if (self.name==otherSet.name and self.index==otherSet.index):
return True
else:
2021-03-27 15:51:01 +01:00
return self.getDOI() == otherSet.getDOI()
2020-09-20 17:53:58 +02:00
class dataFileBase(object):
def __init__(self):
self.molecule = ''
self.comment = ''
self.code = None
self.method = None
self.excitations = []
2020-09-20 17:53:58 +02:00
self.set = ''
2019-11-24 19:40:57 +01:00
@property
def IsTBE(self):
return self.method.name=="TBE"
2019-11-24 19:40:57 +01:00
@staticmethod
def GetFileType():
pass
@staticmethod
2020-06-25 16:46:33 +02:00
def convertState(StateTablelist,initialState,default=DataType.ABS,commands=[]):
tmplst=[]
for TexState in StateTablelist:
2020-08-02 16:24:48 +02:00
st=str(extractMath(TexState,Soup=True,commands=commands))
2020-02-04 13:05:49 +01:00
m=re.match(r"^\^(?P<multiplicity>\d)(?P<symm>[^\s\[(]*)\s*(?:\[(?:\\mathrm{)?(?P<special>\w)(?:})\])?\s*(:?\((?P<type>[^\)]*)\))?",st)
2020-02-17 15:18:08 +01:00
mul=int(m.group("multiplicity"))
symm=m.group("symm")
spgrp=m.group("special")
if spgrp is not None and spgrp=="F":
2020-06-18 12:27:24 +02:00
trsp=DataType.FLUO
2019-11-26 14:36:23 +01:00
else:
trsp=default
tygrp=m.group("type")
2020-02-17 15:18:08 +01:00
tmplst.append((mul,symm,trsp,tygrp))
lst=[]
for index,item in enumerate(tmplst):
2020-09-30 14:18:34 +02:00
unforminitialstate=(int(initialState.multiplicity),initialState.symmetry)
2020-06-25 16:46:33 +02:00
countlst=[unforminitialstate]+[(it[0],it[1]) for it in tmplst[:index+1]]
2020-02-17 15:18:08 +01:00
countitem=(item[0],item[1])
count=countlst.count(countitem)
lst.append((state(count,item[0],item[1]),item[2],item[3]))
return lst
def _OnReadMetaPair(self, key, value):
if key == "molecule":
self.molecule = value
elif key == "comment":
self.comment = value
elif key == "code":
self.code = code.fromString(value)
elif key == "method":
self.method = method.fromString(value)
2020-09-20 17:53:58 +02:00
elif key == "set":
self.set = exSet.fromString(value)
@staticmethod
2020-06-26 14:36:35 +02:00
def readFromTable(table,TexOps, commands=[]):
2020-07-06 10:28:59 +02:00
for formatName,Cls in getFormatHandlers():
2020-07-03 14:51:12 +02:00
if formatName.lower()==TexOps.format.lower():
handler=Cls(TexOps,commands)
break
else:
raise ValueError()
return handler.readFromTable(table)
def getMetadata(self):
dic=OrderedDict()
dic["Molecule"]=self.molecule
dic["Comment"]=self.comment
2019-11-12 15:20:54 +01:00
dic["code"]="" if self.code is None else self.code.toDataString()
dic["method"]="" if self.method is None else self.method.toDataString()
2020-09-20 17:53:58 +02:00
dic["set"]="" if self.set is None else self.set
return dic
def _OnReadMeta(self,line,dataType):
#get key value
match = dataFileBase._GetMetaRexEx().match(line)
# normalize key to lower
key = match.group(1).lower()
# if data has value
if match.group(2):
val = match.group(2)
self._OnReadMetaPair(key, val)
@staticmethod
def _OnReadRow(line):
vals = re.findall(r"\([^\)]+\)|\S+",line)
start = state(int(vals[0]), int(vals[1]), vals[2])
end = state(int(vals[3]), int(vals[4]), vals[5])
Type = vals[6] if (len(vals) >= 7) else None
if Type == "_":
Type = None
if Type:
m = re.match(r"^\(([^\)]*)\)$",Type)
if m:
Type = m[1]
val = vals[7] if len(vals) >= 8 else str(np.NaN)
T1 = vals[8] if len(vals) >= 9 else str(np.NaN)
oscilatorForces = vals[9] if len(vals) >= 10 else str(np.NaN)
isUnsafe = vals[10] == json.dumps(True) if len(vals) >= 11 else False
ex = excitationValue(start, end, val, Type,T1,isUnsafe,oscilatorForces)
return ex
@staticmethod
def _GetMetaRexEx():
#metadata RegExp (start with #; maybe somme spaces; : ; maybe somme space; datas)
return re.compile(r"^#\s*([A-Za-z_]+)\s*:\s*(.*)$")
@staticmethod
def readFile(stream,dataType):
lines = stream.readlines()
# for each line with metadata
ismetaArea = True
dat = datafileSelector(dataType)()
for line in lines:
#if it's not empty line
line = line.strip()
if line:
# if # may be metadata or comment
if line[0] == "#":
# if it's metadata
if ismetaArea and dataFileBase._GetMetaRexEx().match(line):
dat._OnReadMeta(line,dataType)
else: # else its row
ismetaArea = False
dat.excitations.append(dat._OnReadRow(line))
return dat
2020-06-17 13:19:44 +02:00
def toFile(self,datadir,suffix=None):
subpath=datadir/self.GetFileType().name.lower()
if not subpath.exists():
2020-09-15 12:51:07 +02:00
os.makedirs(str(subpath))
molsoup=TexSoup(self.molecule)
2021-11-09 10:37:33 +01:00
molfilename="".join(molsoup.text).replace("\\","")
molfilename=molfilename.lower()
fileNameComp=[molfilename,self.method.name]
2020-03-28 13:00:17 +01:00
if self.method.basis:
fileNameComp.append(self.method.basis)
2020-06-17 13:19:44 +02:00
if suffix:
fileNameComp.append(suffix)
fileName="_".join(fileNameComp).replace(" ","_")+".dat"
2021-03-27 15:49:53 +01:00
if os.sep in fileName:
raise ValueError(f"fileName must be a pure file name not a path: {fileName}")
2019-12-09 13:34:30 +01:00
file=subpath/fileName
if not file.exists():
with file.open("w") as f:
for key,value in self.getMetadata().items():
if value is not None:
2019-11-12 15:20:54 +01:00
f.write("# {:9s}: {}\n".format(key,value))
f.write("""
2020-10-08 18:36:03 +02:00
# Initial state Final state Transition Energies (eV) %T1 Oscillator strength unsafe
####################### ####################### ######################################## ############# ####### ##################### #############
2019-12-14 12:25:56 +01:00
# Number Spin Symm Number Spin Symm type E_{:5s} %T1 f is unsafe\n""".format(self.GetFileType().name.lower()))
for ex in self.excitations:
2020-03-27 14:35:01 +01:00
mystr=" {:7s} {:5s} {:10s} {:7s} {:5s} {:12s} {:39s} {:13s} {:14s} {:13s}{}\n".format(
2019-12-14 17:16:54 +01:00
str(ex.initial.number),
str(ex.initial.multiplicity),
2020-09-30 14:18:34 +02:00
ex.initial.symmetry,
2019-12-14 17:16:54 +01:00
str(ex.final.number),
str(ex.final.multiplicity),
2020-09-30 14:18:34 +02:00
ex.final.symmetry,"("+str(ex.type)+")" if ex.type is not None else "_",
2019-12-14 17:16:54 +01:00
str(ex.value) if ex.value is not None else "_",
str(ex.T1) if ex.T1 is not None else "_",
str(ex.oscilatorForces) if ex.oscilatorForces is not None else "_",
json.dumps(ex.isUnsafe))
f.write(mystr)
class method:
2019-11-20 20:15:53 +01:00
def __init__(self,name, *args):
self.name = name
2019-11-20 20:15:53 +01:00
self.basis=args[0] if len(args)>0 else None
@staticmethod
def fromString(string):
vals = string.split(",")
2019-11-20 20:15:53 +01:00
return method(*vals)
def __str__(self):
string = self.name
if (self.basis):
string+= '/' + self.basis
return string
def toDataString(self):
string=self.name
if (self.basis):
string+=","+self.basis
2019-12-09 13:34:30 +01:00
return string
class code:
2020-09-20 17:53:58 +02:00
def __init__(self,name, version=None):
self.name = name
self.version = version
@staticmethod
def fromString(string):
vals = string.split(",")
return code(*vals)
def toDataString(self):
string=self.name
if (self.version):
string+=","+self.version
return string
class oneStateDataFileBase(dataFileBase):
def __init__(self):
super(oneStateDataFileBase,self).__init__()
self.geometry = None
def _OnReadMetaPair(self, key, value):
if key == "geom":
self.geometry = method.fromString(value)
else:
super(oneStateDataFileBase,self)._OnReadMetaPair(key, value)
def getMetadata(self):
dic=super(oneStateDataFileBase,self).getMetadata()
2019-11-12 15:20:54 +01:00
dic["geom"]= "" if self.geometry is None else self.geometry.toDataString()
2020-09-20 17:53:58 +02:00
dic.move_to_end("set")
return dic
class AbsDataFile(oneStateDataFileBase):
def __init__(self):
super(AbsDataFile,self).__init__()
@staticmethod
def GetFileType():
2020-06-18 12:27:24 +02:00
return DataType.ABS
class FluoDataFile(oneStateDataFileBase):
def __init__(self):
super(FluoDataFile,self).__init__()
@staticmethod
def GetFileType():
2020-06-18 12:27:24 +02:00
return DataType.FLUO
class excitationBase:
def __init__(self,initial, final,type=None, T1=None,isUnsafe=False):
self.initial = initial
self.final = final
self.type = type
self.T1 = T1
self.isUnsafe = isUnsafe
class excitationValue(excitationBase):
def __init__(self,initial, final, value, type=None, T1=None,isUnsafe=False,oscilatorForces=None):
2020-08-06 18:24:42 +02:00
super(excitationValue,self).__init__(initial, final,type=type,T1=T1,isUnsafe=isUnsafe)
2019-11-24 19:40:57 +01:00
self.value = value
self.oscilatorForces = oscilatorForces