PRO AmesPAHdbIDLSuite::File_WGET,Url,File
COMPILE_OPT IDL2
ON_ERROR,2
urlC = PARSE_URL(Url)
netUrl = OBJ_NEW('IDLnetUrl')
netUrl->SetProperty,URL_SCHEME=urlC.scheme
netUrl->SetProperty,URL_HOSTNAME=urlC.host
netUrl->SetProperty,URL_PORT=urlC.port
netUrl->SetProperty,URL_PATH=urlC.path
netUrl->SetProperty,URL_QUERY=urlC.query
netUrl->SetProperty,HEADER='User-Agent: ' + "IDL/" + !VERSION.RELEASE + ' (' + !VERSION.OS + '; ' + !VERSION.ARCH + ' like ' + !VERSION.OS_FAMILY + ')'
File = STRING(netUrl->Get(/BUFFER))
netUrl->CloseConnections
OBJ_DESTROY,netUrl
END
PRO AmesPAHdbIDLSuite::File_MD5,File,Hash,Err
COMPILE_OPT IDL2
ON_ERROR,2
IF !VERSION.OS_FAMILY EQ "Windows" THEN BEGIN
SPAWN,['certUtil', '-hashfile', File, 'MD5'],Hash,Err,/NOSHELL
Hash = (STRSPLIT(Hash, ':', /EXTRACT))[1]
RETURN
ENDIF
md5 = FILE_WHICH(GETENV('PATH'), 'md5')
IF MD5 NE '' THEN BEGIN
SPAWN,[md5,'-q', File],Hash,Err,/NOSHELL
RETURN
ENDIF
md5sum = FILE_WHICH(GETENV('PATH'), 'md5sum')
IF md5sum NE '' THEN BEGIN
SPAWN,[md5sum, File],Hash,Err,/NOSHELL
Hash = (STRSPLIT(Hash, /EXTRACT))[0]
RETURN
ENDIF
Err = " UNABLE TO CALCULATE MD5: COMMAND NOT FOUND "
PRINT
PRINT,"========================================================="
PRINT,Err
PRINT,"========================================================="
PRINT
END
FUNCTION AmesPAHdbIDLSuite::GetHash
COMPILE_OPT IDL2
ON_ERROR,2
RETURN,self.file_md5
END
FUNCTION AmesPAHdbIDLSuite::Cache_DIR
COMPILE_OPT IDL2, STATIC
ON_ERROR,2
DEFSYSV,'!AMESPAHCACHDIR',EXISTS=defsys
IF defsys EQ 1 THEN dir_cache = !AMESPAHCACHEDIR $
ELSE dir_cache = GETENV("AMESPAHCACHEDIR")
IF dir_cache EQ "" THEN RETURN,GETENV('IDL_TMPDIR')
IF NOT FILE_TEST(dir_cache, /DIRECTORY) THEN FILE_MKDIR,dir_cache
RETURN,dir_cache + PATH_SEP()
END
PRO AmesPAHdbIDLSuite::Cache,Hash,Clear=Clear
COMPILE_OPT IDL2, STATIC
ON_ERROR,2
PRINT
PRINT,"========================================================="
IF GETENV("AMESPAHCACHEDIR") EQ "" THEN BEGIN
PRINT," CACHING IS TEMPORARY "
PRINT,"========================================================="
PRINT
RETURN
ENDIF
dir_cache = AmesPAHdbIDLSuite->Cache_DIR()
PRINT,FORMAT='("CACHE DIR:",X,A0)',dir_cache
PRINT,"---------------------------------------------------------"
PRINT,FORMAT='(A-32,X,A-7,8X,A0)',"HASH","SIZE","CLEARED"
PRINT,"---------------------------------------------------------"
files = FILE_SEARCH(dir_cache + PATH_SEP() + "*.sav", COUNT=nfiles)
FOR i = 0L, nfiles - 1L DO BEGIN
info = FILE_INFO(files[i])
basename = STRUPCASE(FILE_BASENAME(files[i],".sav"))
cleared = 0
IF KEYWORD_SET(Clear) THEN BEGIN
IF N_PARAMS() EQ 0 OR (N_PARAMS() EQ 1 AND $
(basename EQ Hash OR $
basename EQ Hash + "_JOINED")) THEN BEGIN
FILE_DELETE,files[i]
cleared = 1
ENDIF
ENDIF
PRINT,FORMAT='(A-32,X,F7.2,X,"MiB",4X,I1)', basename, $
info.size / 1024.0 / 1024.0,cleared
ENDFOR
PRINT,"========================================================="
PRINT
END
FUNCTION AmesPAHdbIDLSuite::GetUIDsCompleteChargeSet,UIDs,Count,Two=Two
COMPILE_OPT IDL2
ON_ERROR,2
pahs = self->GetTagByUID('species', UIDs)
tags = STRLOWCASE(TAG_NAMES(pahs))
tags = tags[WHERE(tags NE 'uid' AND tags NE 'charge' AND tags NE 'energy' AND tags NE 'formula' AND tags NE 'symm' AND tags NE 'method' AND tags NE 'zeropoint' AND tags NE 'formula')]
anions = WHERE(pahs.charge EQ -1, nanions)
cations = WHERE(pahs.charge EQ 1, ncations)
neutrals = WHERE(pahs.charge EQ 0)
IF NOT KEYWORD_SET(Two) THEN BEGIN
set = [0L, 0L, 0L]
FOR i = 0, nanions - 1 DO BEGIN
cmd = "sel1 = WHERE(" + STRJOIN("pahs[cations]." + tags + " EQ pahs[anions[i]]." + tags, " AND ") + ", ncation)"
ret = EXECUTE(cmd)
IF ncation EQ 0 THEN CONTINUE
geometries = self->getGeometryByUID([pahs[anions[i]].uid, pahs[cations[sel1]].uid])
geometries->Diagonalize,Full=0
geo = geometries->get()
norms = DBLARR(ncation)
sel2 = WHERE(geo.data.uid EQ pahs[anions[i]].uid)
x = geo.data[sel2].x & y = geo.data[sel2].y & z = geo.data[sel2].z
FOR j = 0, ncation - 1 DO BEGIN
sel2 = WHERE(geo.data.uid EQ pahs[cations[sel1[j]]].uid)
norms[j] = NORM((x - geo.data[sel2].x)^2 + (y - geo.data[sel2].y)^2 + (z - geo.data[sel2].z)^2)
ENDFOR
min = MIN(norms, imin)
IF min LT 1 THEN BEGIN
sel1 = sel1[imin]
ncation = 1L
ENDIF ELSE ncation = 0L
OBJ_DESTROY,geometries
IF ncation EQ 1 THEN BEGIN
ret = EXECUTE("sel2 = WHERE(" + STRJOIN("pahs[neutrals]." + tags + " EQ pahs[anions[i]]." + tags, " AND ") + ", nneutral)")
IF nneutral EQ 0 THEN CONTINUE
geometries = self->getGeometryByUID([pahs[anions[i]].uid, pahs[neutrals[sel2]].uid])
geometries->Diagonalize
geo = geometries->get()
norms = DBLARR(nneutral)
sel3 = WHERE(geo.data.uid EQ pahs[anions[i]].uid)
x = geo.data[sel3].x & y = geo.data[sel3].y & z = geo.data[sel3].z
FOR j = 0, nneutral - 1 DO BEGIN
sel3 = WHERE(geo.data.uid EQ pahs[neutrals[sel2[j]]].uid)
norms[j] = SQRT(TOTAL((x - geo.data[sel3].x)^2 + (y - geo.data[sel3].y)^2 + (z - geo.data[sel3].z)^2))
ENDFOR
min = MIN(norms, imin)
IF min LT 1 THEN BEGIN
sel2 = sel2[imin]
nneutral = 1
ENDIF ELSE nneutral = 0
OBJ_DESTROY,geometries
IF nneutral EQ 1 THEN BEGIN
set = [[set], [pahs[anions[i]].uid, pahs[neutrals[sel2]].uid, pahs[cations[sel1]].uid]]
keep = WHERE(cations NE cations[sel1[0]], nkeep)
cations = nkeep GT 0 ? cations[keep] : !NULL
keep = WHERE(neutrals NE neutrals[sel2[0]], nkeep)
neutrals = nkeep GT 0 ? neutrals[keep] : !NULL
ENDIF
ENDIF
ENDFOR
ENDIF ELSE BEGIN
set = [0L, 0L]
FOR i = 0, ncations - 1 DO BEGIN
cmd = "sel1 = WHERE(" + STRJOIN("pahs[neutrals]." + tags + " EQ pahs[cations[i]]." + tags, " AND ") + ", nneutral)"
ret = EXECUTE(cmd)
IF nneutral EQ 0 THEN CONTINUE
geometries = self->getGeometryByUID([pahs[cations[i]].uid, pahs[neutrals[sel1]].uid])
geometries->Diagonalize,Full=0
geo = geometries->get()
norms = DBLARR(nneutral)
sel2 = WHERE(geo.data.uid EQ pahs[cations[i]].uid)
x = geo.data[sel2].x & y = geo.data[sel2].y & z = geo.data[sel2].z
FOR j = 0, nneutral - 1 DO BEGIN
sel2 = WHERE(geo.data.uid EQ pahs[neutrals[sel1[j]]].uid)
norms[j] = SQRT(TOTAL((x - geo.data[sel2].x)^2 + (y - geo.data[sel2].y)^2 + (z - geo.data[sel2].z)^2))
ENDFOR
min = MIN(norms, imin)
print,[pahs[neutrals[sel1[imin]]].uid, pahs[cations[i]].uid],min
IF min LT 1 THEN BEGIN
sel1 = sel1[imin]
nneutral = 1
ENDIF ELSE nneutral = 0
OBJ_DESTROY,geometries
IF nneutral EQ 1 THEN BEGIN
set = [[set], [pahs[neutrals[sel1]].uid, pahs[cations[i]].uid]]
keep = WHERE(neutrals NE neutrals[sel1[0]], nkeep)
neutrals = nkeep GT 0 ? neutrals[keep] : !NULL
ENDIF
ENDFOR
ENDELSE
set = set[*, 1:*]
Count = N_ELEMENTS(set[0, *])
RETURN,set
END
FUNCTION AmesPAHdbIDLSuite::GetSpeciesByUID,UIDs,Count
COMPILE_OPT IDL2
ON_ERROR,2
RETURN,OBJ_NEW('AmesPAHdbIDLSuite_Species', $
Type=(*self.pahdb).type ,$
Version=(*self.pahdb).version, $
Data=self->GetTagByUID('species', UIDs, Count), $
PAHdb=self.pahdb, $
Uids=[UIDs])
END
FUNCTION AmesPAHdbIDLSuite::GetTransitionsByUID,UIDs,Count
COMPILE_OPT IDL2
ON_ERROR,2
RETURN,OBJ_NEW('AmesPAHdbIDLSuite_Transitions', $
Type=(*self.pahdb).type ,$
Version=(*self.pahdb).version, $
Data=self->GetTagByUID('transitions', UIDs, Count), $
PAHdb=self.pahdb, $
Uids=[UIDs], $
Model={type:'AMESPAHDBIDLSUITE_MODEL_ZEROKELVIN_S',$
Temperature:0D, $
description:STRING(FORMAT='(A-12,":",X,A-0)', "model", "ZeroKelvin")}, $
Units={AmesPAHdb_Data_Units_S, $
abscissa:{AmesPAHdb_Unit_S, $
unit:1, $
str:'frequency [cm!U-1!N]'}, $
ordinate:{AmesPAHdb_Unit_S, $
unit:2, $
str:'integrated cross-section [km/mol]'}})
END
FUNCTION AmesPAHdbIDLSuite::GetLaboratoryByUID,UIDs,Count
COMPILE_OPT IDL2
ON_ERROR,2
IF (*self.pahdb).type NE 'experimental' THEN BEGIN
PRINT
PRINT,"========================================================="
PRINT," EXPERIMENTAL DATABASE REQUIRED "
PRINT,"========================================================="
PRINT
RETURN, OBJ_NEW()
ENDIF
RETURN,OBJ_NEW('AmesPAHdbIDLSuite_Laboratory_Spectrum', $
Type=(*self.pahdb).type ,$
Version=(*self.pahdb).version, $
Data=self->GetTagByUID('laboratory', UIDs, Count), $
PAHdb=self.pahdb, $
Model={type:'AMESPAHDBIDLSUITE_RAW_LABORATORY_S',$
Temperature:0D, $
description:STRING(FORMAT='(A-12,":",X,A-0)', "model", "Laboratory")}, $
Uids=[UIDs], $
Units={AmesPAHdb_Data_Units_S, $
abscissa:{AmesPAHdb_Unit_S, $
unit:1, $
str:'frequency [cm!U-1!N]'}, $
ordinate:{AmesPAHdb_Unit_S, $
unit:1, $
str:'absorbance [-log(I/I!L0!N)]'}})
END
FUNCTION AmesPAHdbIDLSuite::GetGeometryByUID,UIDs,Count
COMPILE_OPT IDL2
ON_ERROR,2
RETURN,OBJ_NEW('AmesPAHdbIDLSuite_Geometry', $
Data=self->GetTagByUID('geometries', UIDs, Count), $
Uids=[UIDs])
END
FUNCTION AmesPAHdbIDLSuite::GetTagByUID,Tag,UIDs,Count
COMPILE_OPT IDL2
ON_ERROR,2
Count = 0L
itag = WHERE(STRLOWCASE(TAG_NAMES((*self.pahdb).data)) EQ Tag, ntag)
IF ntag NE 1 THEN RETURN,-1
IF SIZE(UIDs, /DIMENSIONS) EQ 0 AND UIDs EQ -1 THEN BEGIN
Count = N_ELEMENTS((*self.pahdb).data.(itag))
UIDs = (*self.pahdb).data.(itag)[UNIQ((*self.pahdb).data.(itag).uid)].uid
RETURN,(*self.pahdb).data.(itag)
ENDIF
UIDs = UIDs[SORT(UIDs)]
nuids = N_ELEMENTS(UIDs)
h = HISTOGRAM((*self.pahdb).data.(itag).uid, MIN=0, REVERSE_INDICES=ri)
FOR i = 0L, nuids - 1L DO BEGIN
n = h[UIDs[i]]
IF n GT 0 THEN BEGIN
IF Count EQ 0 THEN BEGIN
nbuf = 2L * n
select = LONARR(nbuf, /NOZERO)
ENDIF
s = ri[ri[UIDs[i]]:ri[UIDS[i]+1]-1]
IF Count + n GT nbuf THEN BEGIN
WHILE Count + n GE nbuf DO nbuf *= 2L
new = LONARR(nbuf, /NOZERO)
new[0:Count-1L] = select[0:Count-1L]
select = new
ENDIF
select[Count:Count+n-1L] = s
Count += n
ENDIF
ENDFOR
IF Count EQ 0 THEN RETURN,-1
select = select[0:Count-1L]
UIDs = (*self.pahdb).data.(itag)[select[UNIQ((*self.pahdb).data.(itag)[select].uid)]].uid
RETURN,(*self.pahdb).data.(itag)[select]
END
FUNCTION AmesPAHdbIDLSuite::Pointer
COMPILE_OPT IDL2
ON_ERROR,2
RETURN,self.pahdb
END
FUNCTION AmesPAHdbIDLSuite::TokenizeWords,Word
COMPILE_OPT IDL2
ON_ERROR,2
token = {word:Word, $
translation:'', $
type:'None', $
valid:1}
word = STRUPCASE(Word)
charge = [{word:'anion', $
translation:'(*self.joined).charge LT 0'}, $
{word:'cation', $
translation:'(*self.joined).charge GT 0'}, $
{word:'neutral', $
translation:'(*self.joined).charge EQ 0'}, $
{word:'positive', $
translation:'(*self.joined).charge GT 0'}, $
{word:'negative', $
translation:'(*self.joined).charge LT 0'}, $
{word:'-', $
translation:'(*self.joined).charge EQ -1'}, $
{word:'+', $
translation:'(*self.joined).charge EQ 1'}, $
{word:'++', $
translation:'(*self.joined).charge EQ 2'}, $
{word:'+++', $
translation:'(*self.joined).charge EQ 3'}, $
{word:'---', $
translation:'(*self.joined).charge EQ -3'}]
icharge = WHERE(STRCMP(charge.word, Word, /FOLD_CASE), ncharge)
identities = [{word:'uid', $
translation:'(*self.joined).uid'}, $
{word:'identifier', $
translation:'(*self.joined).uid'}, $
{word:'carbon', $
translation:'(*self.joined).nc'}, $
{word:'hydrogen', $
translation:'(*self.joined).nh'}, $
{word:'nitrogen', $
translation:'(*self.joined).nn'}, $
{word:'oxygen', $
translation:'(*self.joined).no'}, $
{word:'magnesium', $
translation:'(*self.joined).nmg'}, $
{word:'silicium', $
translation:'(*self.joined).nsi'}, $
{word:'iron', $
translation:'(*self.joined).nfe'}, $
{word:'c', $
translation:'(*self.joined).nc'}, $
{word:'h', $
translation:'(*self.joined).nh'}, $
{word:'n', $
translation:'(*self.joined).nn'}, $
{word:'o', $
translation:'(*self.joined).no'}, $
{word:'mg', $
translation:'(*self.joined).nmg'}, $
{word:'si', $
translation:'(*self.joined).nsi'}, $
{word:'fe', $
translation:'(*self.joined).nfe'}, $
{word:'wavenumber', $
translation:'(*self.joined).frequency'}, $
{word:'absorbance', $
translation:'(*self.joined).intensity'}, $
{word:'frequency', $
translation:'(*self.joined).frequency'}, $
{word:'scale', $
translation:'(*self.joined).scale'}, $
{word:'intensity', $
translation:'(*self.joined).intensity'}, $
{word:'ch', $
translation:'(*self.joined).nch'}, $
{word:'ch2', $
translation:'(*self.joined).nch2'}, $
{word:'ch3', $
translation:'(*self.joined).nch3'}, $
{word:'chx', $
translation:'(*self.joined).nchx'}, $
{word:'solo', $
translation:'(*self.joined).nsolo'}, $
{word:'duo', $
translation:'(*self.joined).nduo'}, $
{word:'trio', $
translation:'(*self.joined).ntrio'}, $
{word:'quartet', $
translation:'(*self.joined).nquartet'}, $
{word:'quintet', $
translation:'(*self.joined).nquintet'}, $
{word:'charge', $
translation:'(*self.joined).charge'}, $
{word:'symmetry', $
translation:'(*self.joined).symmetry'}, $
{word:'weight', $
translation:'(*self.joined).weight'}, $
{word:'energy', $
translation:'(*self.joined).total_e'}, $
{word:'zeropoint', $
translation:'(*self.joined).vib_e'}, $
{word:'experiment', $
translation:'(*self.joined).exp'}]
iidentity = WHERE(STRCMP(identities.word, Word, /FOLD_CASE), nidentity)
logical = [{word:'and', $
translation:'AND'}, $
{word:'or', $
translation:'OR'}, $
{word:'|', $
translation: 'OR'}, $
{word:'&', $
translation: 'AND'}]
ilogical = WHERE(STRCMP(logical.word, Word, /FOLD_CASE), nlogical)
comparison = [{word:'<', $
translation:'LT'}, $
{word:'lt', $
translation:'LT'}, $
{word:'>', $
translation:'GT'}, $
{word:'gt', $
translation:'GT'}, $
{word:'=', $
translation:'EQ'}, $
{word:'eq', $
translation:'EQ'}, $
{word:'<=', $
translation:'LE'}, $
{word:'le', $
translation:'LE'}, $
{word:'>=', $
translation:'GE'}, $
{word:'ge', $
translation:'GE'}, $
{word:'with', $
translation:'AND'}, $
{word:'ne', $
translation:'ne'}, $
{word:'!=', $
translation:'ne'}]
icomparison = WHERE(STRCMP(comparison.word, Word, /FOLD_CASE), ncomparison)
transfer = [{word:'(', $
translation:'('}, $
{word:')', $
translation:')'}]
itransfer = WHERE(STRCMP(transfer.word, Word, /FOLD_CASE), ntransfer)
IF STREGEX(Word, '(^[+-]?[0-9]+)|([A-Z][0-9][A-Z])', /FOLD_CASE, /BOOLEAN) THEN BEGIN
token.type = "NUMERIC"
token.translation = Word
ENDIF ELSE IF ncharge THEN BEGIN
token.type = "CHARGE"
token.translation = charge[icharge].translation
ENDIF ELSE IF nidentity THEN BEGIN
token.type = "IDENTITY"
token.translation = identities[iidentity].translation
ENDIF ELSE IF nlogical THEN BEGIN
token.type = "LOGICAL"
token.translation = logical[ilogical].translation
ENDIF ELSE IF ncomparison THEN BEGIN
token.type = "COMPARISON"
token.translation = comparison[icomparison].translation
ENDIF ELSE IF ntransfer THEN BEGIN
token.type = "TRANSFER"
token.translation = transfer[itransfer].translation
ENDIF ELSE IF STREGEX(Word,'(MG+|SI+|FE+|[CHNO]+)([0-9]*)(MG+|SI+|FE+|[CHNO]+)([0-9]*)(MG+|SI+|FE+|[CHNO]*)([0-9]*)', /FOLD_CASE, /BOOLEAN) THEN BEGIN
token.type = "FORMULA"
token.translation = Word
ENDIF ELSE BEGIN
token.type = "IGNORE"
token.translation = Word
ENDELSE
RETURN,token
END
FUNCTION AmesPAHdbIDLSuite::ParseTokens,Tokens
COMPILE_OPT IDL2
ON_ERROR,2
ntokens = N_ELEMENTS(Tokens)
prev = -1 & current = 0
IF ntokens GT 1 THEN next = 1 ELSE next = -1
parsed = ''
WHILE current NE -1 DO BEGIN
CASE Tokens[current].type OF
'FORMULA': BEGIN
IF prev NE -1 THEN BEGIN
IF NOT (Tokens[prev].type NE 'LOGICAL' AND Tokens[prev].valid EQ 1) THEN parsed += ' OR '
ENDIF
parsed += ' STRMATCH(joined.formula, "' + Tokens[current].translation + '*", /FOLD_CASE)'
END
'IDENTITY': BEGIN
IF prev NE -1 THEN BEGIN
IF NOT (Tokens[prev].type EQ 'LOGICAL' OR Tokens[prev].type EQ 'TRANSFER' OR Tokens[prev].type EQ 'TRANSFER' AND Tokens[prev].valid EQ 1) THEN parsed += ' AND '
ENDIF
IF next NE -1 THEN BEGIN
IF Tokens[next].type EQ 'COMPARISON' THEN parsed += ' ' + Tokens[current].translation ELSE parsed += ' ' + Tokens[current].translation + ' GT 0'
ENDIF
END
'NUMERIC': BEGIN
IF prev NE -1 THEN BEGIN
IF Tokens[prev].type EQ 'COMPARISON' AND Tokens[prev].valid EQ 1 THEN parsed += ' ' + Tokens[current].translation ELSE Tokens[current].valid = -1
ENDIF
END
'LOGICAL': BEGIN
IF prev NE -1 THEN BEGIN
IF (Tokens[prev].type EQ 'IDENTITY' OR Tokens[prev].type EQ 'NUMERIC' OR Tokens[prev].type EQ 'FORMULA' OR Tokens[prev].type EQ 'CHARGE' AND Tokens[prev].valid EQ 1) THEN BEGIN
IF next NE -1 THEN BEGIN
IF (Tokens[next].type EQ 'TRANSFER') THEN parsed += Tokens[current].translation $
ELSE IF (Tokens[next].type EQ 'IDENTITY' OR Tokens[next].type EQ 'NUMERIC' OR Tokens[next].type EQ 'FORMULA' OR Tokens[next].type EQ 'CHARGE') THEN parsed += ' ' + Tokens[current].translation ELSE Tokens[current].valid = -1
ENDIF
ENDIF
ENDIF
END
'COMPARISON': BEGIN
IF prev NE -1 THEN BEGIN
IF Tokens[prev].type EQ 'IDENTITY' AND Tokens[prev].valid EQ 1 THEN BEGIN
IF next NE -1 THEN BEGIN
IF Tokens[next].type EQ 'NUMERIC' THEN parsed += ' ' + Tokens[current].translation ELSE Tokens[current].valid = -1
ENDIF
ENDIF
ENDIF
END
'CHARGE': BEGIN
IF prev NE -1 THEN BEGIN
IF NOT (Tokens[prev].type EQ 'LOGICAL' AND Tokens[prev].valid EQ 1) THEN parsed += ' AND '
ENDIF
parsed += ' ' + Tokens[current].translation
END
'TRANSFER': BEGIN
parsed += Tokens[current].translation
END
'NAME': BEGIN
IF prev NE -1 THEN BEGIN
IF NOT (Tokens[prev].type EQ 'LOGICAL' AND Tokens[prev].valid EQ 1) THEN parsed += ' AND '
ENDIF
END
'IGNORE': BEGIN
MESSAGE,Tokens[current].word+' NOT UNDERSTOOD',/INFORMATIONAL
RETURN, ''
END
ENDCASE
prev = current & current = next
IF next++ GE ntokens - 1 THEN next = -1
ENDWHILE
RETURN,parsed
END
FUNCTION AmesPAHdbIDLSuite::Search,Str,Count,Query=Query
COMPILE_OPT IDL2
ON_ERROR,2
Count = 0
IF STRLEN(Str) EQ 0 THEN RETURN,-1
IF NOT PTR_VALID(self.joined) THEN BEGIN
file_cache = self->Cache_DIR()+self.file_md5+'_joined.sav'
IF FILE_TEST(file_cache, /READ) THEN BEGIN
PRINT
PRINT,"========================================================="
PRINT," RESTORING INDEX FROM CACHE "
PRINT,"========================================================="
PRINT
RESTORE,FILENAME=file_cache,/RELAXED_STRUCTURE_ASSIGNMENT
ENDIF ELSE BEGIN
PRINT
PRINT,"========================================================="
PRINT," BUILDING INDEX: THIS MAY TAKE A FEW MINUTES "
PRINT,"========================================================="
PRINT
tags = TAG_NAMES((*self.pahdb).data.species)
ntags = N_TAGS((*self.pahdb).data.species)
command = 'template = CREATE_STRUCT((*self.pahdb).data.transitions[0]'
FOR i = 0, ntags - 1 DO BEGIN
IF tags[i] EQ 'UID' THEN CONTINUE
CASE SIZE((*self.pahdb).data.species.(i), /TYPE) OF
2: command += ",'"+tags[i]+"'"+',0'
3: command += ",'"+tags[i]+"'"+',0L'
4: command += ",'"+tags[i]+"'"+',0E'
5: command += ",'"+tags[i]+"'"+',0D'
7: command += ",'"+tags[i]+"'"+',""'
ELSE:
ENDCASE
ENDFOR
command += ')'
result = EXECUTE(command)
ntransitions = N_ELEMENTS((*self.pahdb).data.transitions)
joined = REPLICATE(template, ntransitions)
STRUCT_ASSIGN,(*self.pahdb).data.transitions,joined,/NOZERO
nids = N_ELEMENTS((*self.pahdb).data.species)
jtags = TAG_NAMES(joined)
FOR i = 0, nids - 1 DO BEGIN
select = WHERE(joined.uid EQ (*self.pahdb).data.species[i].uid, nselect)
FOR j = 0, ntags - 1 DO BEGIN
k = WHERE(jtags EQ tags[j])
IF tags[j] EQ 'UID' THEN CONTINUE
joined[select].(k) = (*self.pahdb).data.species[i].(j)
ENDFOR
ENDFOR
PRINT
PRINT,"========================================================="
PRINT,"STORING INDEX IN CACHE : "+file_cache
PRINT,"========================================================="
PRINT
SAVE,joined,FILENAME=file_cache
ENDELSE
self.joined = PTR_NEW(TEMPORARY(joined))
ENDIF
words = ''
len = STRLEN(Str)
i = 0
WHILE 1 DO BEGIN
IF i EQ len THEN BREAK
WHILE STRMID(Str, i, 1) EQ " " DO ++i
token = STRMID(Str, i, 1)
IF SIZE(WHERE(["=", "<", ">", "(", ")"] EQ token), /DIMENSIONS) NE 0 THEN BEGIN
IF ++i LT len AND STRMID(Str, i, 1) EQ "=" THEN token += STRMID(Str, i++, 1)
ENDIF ELSE IF token EQ "&" THEN BEGIN
IF ++i LT len AND STRMID(Str, i, 1) EQ "&" THEN token += STRMID(Str, i++, 1)
ENDIF ELSE IF token EQ "|" THEN BEGIN
IF ++i LT len AND STRMID(Str, i, 1) EQ "|" THEN token += STRMID(Str, i++, 1)
ENDIF ELSE IF token EQ "!" THEN BEGIN
IF ++i LT len AND STRMID(Str, i, 1) EQ "=" THEN token += STRMID(Str, i++, 1)
ENDIF ELSE BEGIN
++i
WHILE i LT len AND SIZE(WHERE([" ", "=", "<", ">", "&", "|", "(", ")", "!"] EQ STRMID(Str, i, 1)), /DIMENSIONS) EQ 0 DO token += STRMID(Str, i++, 1)
ENDELSE
words = [words, token]
ENDWHILE
words = words[1:*]
nwords = N_ELEMENTS(words)
tokens = {word:'', $
translation:'', $
type:'', $
valid:0}
FOR i = 0, nwords - 1 DO tokens = [tokens, self->TokenizeWords(words[i])]
tokens = tokens[1:*]
QUERY = self->ParseTokens(tokens)
IF QUERY EQ '' THEN RETURN,-1
res = EXECUTE('select = WHERE(' + QUERY + ', Count)')
IF Count EQ 0 THEN RETURN,-1
u = (*self.joined)[select[UNIQ((*self.joined)[select].uid)]].uid
Count = N_ELEMENTS(u)
RETURN,u
END
FUNCTION AmesPAHdbIDLSuite::CheckVersion,Version
COMPILE_OPT IDL2
ON_ERROR,2
RETURN,STRCMP((*self.pahdb).version, Version)
END
FUNCTION AmesPAHdbIDLSuite::GetVersion,String=String
COMPILE_OPT IDL2
ON_ERROR,2
IF KEYWORD_SET(String) THEN RETURN,STRING(FORMAT='("PAHdb,",X,A0,", version",X,A0,X,"(",A0,",",X,A0,")")', (*self.pahdb).type, (*self.pahdb).version, (*self.pahdb).date, (*self.pahdb).full ? "complete" : "partial")
RETURN,{AmesPAHdbIDLSuite_Version_S, $
type:(*self.pahdb).type, $
number:(*self.pahdb).version, $
date:(*self.pahdb).date, $
full:(*self.pahdb).full}
END
PRO AmesPAHdbIDLSuite::ExtendDatabase,Species=Species,Comments=Comments,References=References,Transitions=Transitions,Geometries=Geometries,Laboratory=Laboratory
COMPILE_OPT IDL2
ON_ERROR,2
IF NOT PTR_VALID(self.pahdb) THEN BEGIN
PRINT
PRINT,"========================================================="
PRINT," NO VALID DATABASE "
PRINT,"========================================================="
PRINT
RETURN
ENDIF
s = (*self.pahdb).data.species
IF KEYWORD_SET(Species) THEN s = [s, Species]
c = (*self.pahdb).data.comments
IF KEYWORD_SET(Comments) THEN c = [c, Comments]
r = (*self.pahdb).data.references
IF KEYWORD_SET(References) THEN r = [r, References]
t = (*self.pahdb).data.transitions
IF KEYWORD_SET(Transitions) THEN t = [t, Transitions]
g = (*self.pahdb).data.geometries
IF KEYWORD_SET(Geometries) THEN g = [g, Geometries]
l = (*self.pahdb).data.laboratory
IF KEYWORD_SET(Laboratory) THEN l = [l, Laboratory]
(*self.pahdb) = {filename:(*self.pahdb).filename, $
type:(*self.pahdb).type, $
version:(*self.pahdb).version, $
date:(*self.pahdb).date,$
full:(*self.pahdb).full, $
comment:(*self.pahdb).comment, $
sizes:(*self.pahdb).sizes, $
data:{species:s, $
comments:c, $
references:r, $
transitions:t, $
geometries:g, $
laboratory:l}}
(*self.pahdb).sizes = {nspecies:N_ELEMENTS(s), ncomments:N_ELEMENTS(c), nreferences:N_ELEMENTS(r), ntransitions:N_ELEMENTS(t), ngeometries:N_ELEMENTS(g), nlaboratory:N_ELEMENTS(l)}
END
PRO AmesPAHdbIDLSuite::ReadFile,File,Check=Check,Cache=Cache
COMPILE_OPT IDL2
ON_ERROR,2
self->File_MD5,File,hash,err
IF err NE '' THEN hash = FILE_BASENAME(File, '.xml')
self.file_md5 = hash[0]
file_cache = self->Cache_DIR()+self.file_md5+'.sav'
IF SIZE(Cache, /TYPE) EQ 0 THEN Cache = 1
IF NOT Cache THEN FILE_DELETE,file_cache,/ALLOW_NONEXISTENT
IF Cache AND FILE_TEST(file_cache, /READ) THEN BEGIN
PRINT
PRINT,"========================================================="
PRINT," NASA Ames PAH IR SPECTROSCOPIC DATABASE "
PRINT,"========================================================="
PRINT
PRINT
PRINT,"========================================================="
PRINT," RESTORING DATABASE FROM CACHE "
PRINT,"========================================================="
PRINT
timer = SYSTIME(/SECONDS)
RESTORE,FILENAME=file_cache,/RELAXED_STRUCTURE_ASSIGNMENT
PRINT,"========================================================="
PRINT,FORMAT='(A-30, ": ", A0)',"FILENAME",""+file_cache
PRINT,FORMAT='(A-30, ": ", A0)',"ORIGINAL FILE",""+pahdb.filename
PRINT,FORMAT='(A-30, ": ", A0)',"DATABASE",""+pahdb.type+" ("+(pahdb.full ? "complete" : "partial")+")"
timer = SYSTIME(/SECONDS) - timer
IF timer LT 1 THEN PRINT,FORMAT='(A-30, ": ", A0)',"RESTORE TIME",STRING(FORMAT='(I-3)', timer*1D3)+" MILLISECONDS" $
ELSE IF timer LT 60 THEN PRINT,FORMAT='(A-30, ": ", A0)',"RESTORE TIME",STRING(FORMAT='(I02)',timer)+" SECONDS" $
ELSE IF timer LT 3600 THEN PRINT,FORMAT='(A-30, ": ", A0)',"RESTORE TIME",STRING(FORMAT='(I02,":",I02)',timer/60,timer MOD 60)+" MINUTES" $
ELSE IF timer LT 86400 THEN PRINT,FORMAT='(A-30, ": ", A0)',"RESTORE TIME",STRING(FORMAT='(I02,":",I02,":",I02)',timer/3600,(timer MOD 3600)/60,(timer MOD 3600) MOD 60)+" HOURS" $
ELSE PRINT,FORMAT='(A-30, ": ", A0)',"RESTORE TIME",STRING(FORMAT='(I03)',timer/86400E)+" DAYS"
PRINT,FORMAT='(A-30, ": ", A0)',"VERSION (DATE)",""+pahdb.version+" ("+pahdb.date+")"
PRINT,FORMAT='(A-30, ": ", I-0)',"TOTAL NUMBER OF SPECIES",N_ELEMENTS(pahdb.data.species)
PRINT,FORMAT='(A-30, ": ", I-0)',"TOTAL NUMBER OF TRANSITIONS",N_ELEMENTS(pahdb.data.transitions)
PRINT,FORMAT='(A-30,": ", A0)',"COMMENT",pahdb.comment
PRINT,"========================================================="
PRINT
ENDIF ELSE BEGIN
PRINT
PRINT,"========================================================="
PRINT," PARSING DATABASE: THIS MAY TAKE A FEW MINUTES "
PRINT,"========================================================="
PRINT
IF SIZE(Check, /TYPE) EQ 0 THEN Check = 2
XML = OBJ_NEW('AmesPAHdbIDLSuite_XMLParser', SCHEMA_CHECKING=Check)
XML->ParseFile,File
IF XML->Status() EQ 0 THEN BEGIN
pahdb = CREATE_STRUCT('file_md5', self.file_md5, XML->GetDatabase())
PRINT
PRINT,"========================================================="
PRINT,"STORING DATABASE IN CACHE : "+file_cache
PRINT,"========================================================="
PRINT
SAVE,pahdb,FILENAME=file_cache
ENDIF
ENDELSE
self.pahdb = PTR_NEW(TEMPORARY(pahdb))
END
PRO AmesPAHdbIDLSuite::Cleanup
COMPILE_OPT IDL2
ON_ERROR,2
IF PTR_VALID(self.pahdb) THEN PTR_FREE,self.pahdb
IF PTR_VALID(self.joined) THEN PTR_FREE,self.joined
END
FUNCTION AmesPAHdbIDLSuite::Init,Filename=Filename,Check=Check,Cache=Cache,UpdateCheck=UpdateCheck
COMPILE_OPT IDL2
ON_ERROR,2
PRINT
PRINT,"========================================================="
PRINT
PRINT," AmesPAHdbIDLSuite "
PRINT
PRINT," by "
PRINT
PRINT," Dr. Christiaan Boersma "
PRINT
PRINT,"========================================================="
PRINT
version_file = FILE_DIRNAME(ROUTINE_FILEPATH("amespahdbidlsuite__define", /EITHER)) + '/VERSION'
IF FILE_TEST(version_file, /READ) THEN BEGIN
OPENR,funit,version_file,/GET_LUN
v = ''
READF,funit,v
self.version = v
CLOSE,funit
FREE_LUN,funit
PRINT
PRINT,"========================================================="
PRINT," SUITE DATED: "+STRUPCASE(self.version)
PRINT,"========================================================="
PRINT
IF KEYWORD_SET(UpdateCheck) THEN BEGIN
self->File_WGET,'https://www.astrochemistry.org/pahdb/theoretical/2.00/ajax/amespahdbidlsuite/versioncheck',remote_version
IF remote_version EQ '' THEN BEGIN
PRINT
PRINT,"========================================================="
PRINT," CHECKING FOR UPDATES FAILED "
PRINT,"========================================================="
PRINT
ENDIF ELSE BEGIN
IF self.version EQ remote_version THEN BEGIN
PRINT
PRINT,"========================================================="
PRINT," NO UPDATES AVAILABLE "
PRINT,"========================================================="
PRINT
ENDIF ELSE BEGIN
PRINT
PRINT,"========================================================="
PRINT," UPDATE AVAILABLE: "+STRUPCASE(remote_version)
PRINT,"========================================================="
PRINT
ENDELSE
ENDELSE
ENDIF
ENDIF
PRINT
PRINT,"========================================================="
PRINT," WEBSITE: HTTP://WWW.ASTROCHEMISTRY.ORG/PAHDB/ "
PRINT,"========================================================="
PRINT
PRINT
PRINT,"========================================================="
PRINT," CONTACT: CHRISTIAAN.BOERSMA@NASA.GOV "
PRINT,"========================================================="
PRINT
DEFSYSV,'!GDL',EXISTS=isgdl
IF isgdl THEN BEGIN
PRINT
PRINT,"========================================================="
PRINT," THE AMESPAHDBIDLSUITE IS NOT COMPATIBLE WITH GDL "
PRINT,"========================================================="
PRINT
self.state = 0
RETURN,0
ENDIF
IF NOT KEYWORD_SET(Filename) THEN BEGIN
DEFSYSV,'!AMESPAHDEFAULTDB',EXISTS=defsys
IF defsys EQ 1 THEN Filename = !AMESPAHDEFAULTDB $
ELSE IF GETENV('AMESPAHDEFAULTDB') NE '' THEN Filename = GETENV('AMESPAHDEFAULTDB') $
ELSE BEGIN
PRINT
PRINT,"========================================================="
PRINT," DATABASE NOT FOUND: SET IDL OR SYSTEM AMESPAHDEFAULTDB ENVIRONMENT VARIABLE"
PRINT,"========================================================="
PRINT
self.state = 0
RETURN,self.state
ENDELSE
ENDIF
IF NOT FILE_TEST(Filename, /READ) THEN BEGIN
IF (alt = FILE_WHICH(FILE_BASENAME(Filename), /INCLUDE_CURRENT_DIR)) NE '' THEN Filename = alt $
ELSE BEGIN
PRINT
PRINT,"========================================================="
PRINT," UNABLE TO READ: "+Filename
PRINT,"========================================================="
PRINT
RETURN,0
ENDELSE
ENDIF
self->ReadFile,Filename,Check=Check,Cache=Cache
RETURN,1
END
PRO AmesPAHdbIDLSuite__DEFINE
COMPILE_OPT IDL2
ON_ERROR,2
void = {AmesPAHdbIDLSuite, $
state:0, $
file_md5:'', $
version:'', $
pahdb:PTR_NEW(), $
joined:PTR_NEW()}
END