-
Notifications
You must be signed in to change notification settings - Fork 0
/
generate_cfg.py
258 lines (234 loc) · 10.3 KB
/
generate_cfg.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
import random
import sys
import re
import os
'''
The goal of this code is to generate config files with any type of waveset
Part of the reference config file will be taken to form the preamble of the output
config file. This preamble will contain the dataset names, fit name, scales, etc
For each wave we want to include we need to do the following
1. Initialize the wave
2. Constrain the wave
3. Scale the waves
'''
verbose=False
delimiterForOutFileName="_" # The output config file would have a name like 000__045__090
cfgFileLoops=True # DO NOT MODIFY THIS ON YOUR OWN
reactionName="LOOPREAC" # DO NOT MODIFY THIS ON YOUR OWN
reactionAngle="LOOPPOLANG" # DO NOT MODIFY THIS ON YOUR OWN
reactionPol="LOOPSCALE" # DO NOT MODIFY THIS ON YOUR OWN
def constructWave(l,m,e):
'''
constructs the wave in the typical notation
'''
mapSpinToSpectroscopic={0:"S",1:"P",2:"D"}
waveString=mapSpinToSpectroscopic[l]+str(m)
if e=="+":
waveString+="+"
else:
waveString+="-"
return waveString
def constructWaveString(l,m,e,c,prefix):
'''
l = Spin {0, 1, 2 ...}
m = Spin projection {..., -2, -1, 0, 1+, 2+, ... }
e = reflectivity {+/-}
c = component (Re)al or (Im)aginary part
prefix = string containing the dataset name
'''
assert l <= 2 and l >= 0 # Just do up to D waves for now
assert abs(m) <= l
assert e in ["+","-"]
waveString=prefix+"::"
if e=="+":
waveString+="Positive"
else:
waveString+="Negative"
waveString+=c+"::"
waveString+=constructWave(l,m,e)
return waveString
def defineWave(l,m,e):
'''
l = Spin {0, 1, 2 ...}
m = Spin projection {..., -2, -1, 0, 1+, 2+, ... }
e = reflectivity {+/-}
'''
assert l <= 2 and l >= 0 # Just do up to D waves for now
assert abs(m) <= l
assert e in ["+","-"]
prefix="amplitude "
outputStrs=[]
for c in ["Re","Im"]:
outputStr = prefix
outputStr += constructWaveString(l,m,e,c,reactionName)
outputStr+=" Zlm "
waveValues=[str(l), str(m)]
if e=="+" and c=="Re":
waveValues+=["+1","+1"]
if e=="+" and c=="Im":
waveValues+=["-1","-1"]
if e=="-" and c=="Re":
waveValues+=["+1","-1"]
if e=="-" and c=="Im":
waveValues+=["-1","+1"]
outputStr += " ".join(waveValues)
outputStr += " "+reactionAngle+" "+reactionPol
outputStrs.append(outputStr)
return "\n".join(outputStrs)
def initializeWave(l,m,e,anchor):
'''
l = Spin {0, 1, 2 ...}
m = Spin projection {..., -2, -1, 0, 1+, 2+, ... }
e = reflectivity {+/-}
anchor = boolean to set this wave as the anchor, anchor wave requires wave to be positive
'''
if verbose:
print("initializing wave lme={0}{1}{2}".format(l,m,e))
prefix="initialize "
c="Re" # since we constrain the (Re)al and (Im)aginary parts of the waves to be the same we only need to initialize one part
outputStr = prefix
outputStr += constructWaveString(l,m,e,c,reactionName)
outputStr += " cartesian "
if anchor:
outputStr += str(random.uniform(-100,100)) + " 0.0 real"
else:
outputStr += str(random.uniform(-100,100)) + " " + str(random.uniform(-100,100));
return outputStr
def constrainWave(l,m,e,preamble):
'''
l = Spin {0, 1, 2 ...}
m = Spin projection {..., -2, -1, 0, 1+, 2+, ... }
e = reflectivity {+/-}
preamble = data copied over from the reference config, will be used to the fit name
'''
if verbose:
print("constraining wave lme={0}{1}{2}".format(l,m,e))
prefix="constrain "
outputStr = prefix
# First we constrain the Re and Im parts of a given wave
if cfgFileLoops:
outputStr += constructWaveString(l,m,e,"Re","LOOPREAC") + " " + constructWaveString(l,m,e,"Im","LOOPREAC")
outputStr += "\n"
dataset_name = [line for line in preamble.split("\n") if line.startswith("loop LOOPREAC")]
dataset_name = dataset_name[0].split(" ")[2]
# Second we constrain the Re/Im parts of a given wave for a given dataset to the Re/Im parts of the same wave for a different waveset
outputStr += "constrain " + constructWaveString(l,m,e,"Re",dataset_name) + " " + constructWaveString(l,m,e,"Re","LOOPREAC")
outputStr += "\n"
outputStr += "constrain " + constructWaveString(l,m,e,"Im",dataset_name) + " " + constructWaveString(l,m,e,"Im","LOOPREAC")
else:
outputStr += constructWaveString(l,m,e,"Re",reactionName) + " " + constructWaveString(l,m,e,"Im",reactionName)
return outputStr
def scaleWave(l,m,e):
'''
l = Spin {0, 1, 2 ...}
m = Spin projection {..., -2, -1, 0, 1+, 2+, ... }
e = reflectivity {+/-}
'''
if verbose:
print("scaling wave lme={0}{1}{2}".format(l,m,e))
if cfgFileLoops:
prefix="scale "
outputStrs=[]
for c in ["Re","Im"]:
outputStr = prefix
outputStr += constructWaveString(l,m,e,c,"LOOPREAC") + " LOOPSCALE"
outputStrs.append(outputStr)
return "\n".join(outputStrs)
else:
return ""
def writeWave(l,m,e,anchor,preamble):
'''
l = Spin {0, 1, 2 ...}
m = Spin projection {..., -2, -1, 0, 1+, 2+, ... }
e = reflectivity {+/-}
anchor = boolean to set this wave as the anchor, anchor wave requires wave to be positive
'''
if verbose:
print("writing wave lme={0}{1}{2}".format(l,m,e))
outputList=[
defineWave(l,m,e),
initializeWave(l,m,e,anchor),
constrainWave(l,m,e,preamble),
scaleWave(l,m,e)
]
return "\n".join(outputList)
def constructOutputFileName(lmes,i=-1):
mapLtoSpect={0:"S",1:"P",2:"D"};
names=[mapLtoSpect[lme[0]]+str(lme[1])+lme[2] for lme in lmes]
cfgFileName=delimiterForOutFileName.join(names)
if i==-1:
return cfgFileName
else:
return cfgFileName+"("+str(i)+").cfg"
def writeCfg(lmes,reference_file,seed,i):
'''
lmes: List of lists. Each sublist is in the [l,m,e,anchor] format
reference_file: we will get our preamble from here
seed: set the random seed we will sample from to initialize our waveset
i: iteration number, we should set this when doing multiple fits with random initializations
'''
# First need to update the global variables otherwise we are creating local versions
global cfgFileLoops
global reactionAngle
global reactionPol
global reactionName
with open(reference_file,"r") as ref:
'''
We will be very specific on what we write to the new config file. We will
remove all commented lines and remove all lines that deal with setting up
the partial waves. We will also remove repeated new lines
'''
preamble=ref.readlines()
preamble=[line for line in preamble if not line.startswith("#")]
preamble=[line for line in preamble if not line.startswith("amplitude")]
preamble=[line for line in preamble if not line.startswith("initialize")]
preamble=[line for line in preamble if not line.startswith("constrain")]
preamble=[line for line in preamble if not line.startswith("scale")]
preamble=[line.rstrip().lstrip()+"-"+str(i)+"\n" if line.startswith("fit") else line for line in preamble]
reactionLine=[line for line in preamble if line.startswith("reaction")]
assert len(reactionLine)==1
fitName=reactionLine[0].split(" ")[1].rstrip().lstrip()
cfgFileLoops = any([line.startswith("loop") for line in preamble])
if cfgFileLoops:
loopLines=[line for line in preamble if line.startswith("loop")]
loopLineKeys=[line.split(" ")[1] for line in loopLines]
if "LOOPREAC" not in loopLineKeys or "LOOPPOLANG" not in loopLineKeys or "LOOPPOLVAL" not in loopLineKeys:
raise ValueError("LOOPREAC or LOOPPOLANG or LOOPPOLVAL not defined/found. Make sure you use something like: loop LOOPREAC reac1 reac2 ...\n in your reference config file or else the program becomes unsure what the name of the parameter should be")
reactionName="LOOPREAC"
reactionAngle="LOOPPOLANG"
reactionPol="LOOPPOLVAL"
pols = [line for line in preamble if line.startswith("loop LOOPREAC")]
pols = pols[0].rstrip().lstrip().split(" ")[2:]
pols = [pol.split("_")[1] for pol in pols]
pols = "_".join(pols)
else:
defineLines=[line for line in preamble if line.startswith("define")]
defineLineKeys=[line.split(" ")[1] for line in defineLines]
if "polAngle" not in defineLineKeys or "polVal" not in defineLineKeys:
raise ValueError("polAngle or polVal not defined/found. Make sure you use something like: define polAngle 0\n in your reference config file or else the program becomes unsure what the name of the parameter should be")
reactionName=fitName
reactionAngle="polAngle"
reactionPol="polVal"
pols = fitName.split("_")[1].rstrip().lstrip()
if pols not in ["000","045","090","135","AMO"]:
raise ValueError("fitName not expected. Should be in the format myFitName_pol where myFitName is your choice and pol = {000,045,090,135,AMO}")
pols = "_".join([pols])
if verbose:
print("FITNAME: "+fitName)
print("POLARIZATIONS USED: ")
print(pols)
preamble="".join(preamble)
preamble=re.sub(r'\n+','\n',preamble).strip()
waveStrings=[preamble]
for lme in lmes:
waveStrings.append(writeWave(*lme,preamble=preamble))
# output config file name?
cfgFileName=constructOutputFileName(lmes,i)
#mapLtoSpect={0:"S",1:"P",2:"D"};
#names=[mapLtoSpect[lme[0]]+str(lme[1])+lme[2] for lme in lmes]
#cfgFileName="_".join(names)+"("+str(i)+").cfg"
with open(cfgFileName,"w") as cfgFile:
outputString="\n\n".join(waveStrings)
outputString=outputString.replace("\r\n", os.linesep)
cfgFile.writelines(outputString)
return cfgFileName, pols