RTModel 3.3__cp314-cp314-win_amd64.whl

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.
RTModel/RTModel.py ADDED
@@ -0,0 +1,640 @@
1
+ import site
2
+ import subprocess
3
+ import os
4
+ import sys
5
+ import glob
6
+ import time
7
+ from pathlib import Path
8
+ from tqdm import tqdm
9
+ import shutil
10
+
11
+
12
+ class RTModel:
13
+ def __init__(self, event = None):
14
+ # Directory preliminaries
15
+ print('*********************')
16
+ print('**** RTModel ****')
17
+ print('*********************')
18
+ self.bindir = self.find_bin_directory()
19
+ if(os.path.exists(self.bindir + 'Reader.exe')):
20
+ self.readerexe = 'Reader.exe'
21
+ self.initcondexe = 'InitCond.exe'
22
+ self.levmarexe = 'LevMar.exe'
23
+ self.modelselectorexe = 'ModelSelector.exe'
24
+ self.finalizerexe = 'Finalizer.exe'
25
+ else:
26
+ self.readerexe = 'Reader'
27
+ self.initcondexe = 'InitCond'
28
+ self.levmarexe = 'LevMar'
29
+ self.modelselectorexe = 'ModelSelector'
30
+ self.finalizerexe = 'Finalizer'
31
+ if(event == None):
32
+ self.eventname = os.getcwd()
33
+ else:
34
+ self.eventname = os.path.realpath(event)
35
+ if(os.path.exists(self.eventname)):
36
+ print("Event name: " + self.eventname)
37
+ else:
38
+ print("! Invalid path for event: " + self.eventname)
39
+ self.inidir = "ini"
40
+ self.modelcodes = ['PS', 'PX', 'BS', 'BO', 'LS', 'LX', 'LO', 'LK', 'TS', 'TX', 'TO']
41
+ self.endphase = len(self.modelcodes)*2+3
42
+ self.eventinifile = 'event.ini'
43
+ self.nprocessors = os.cpu_count()
44
+ print('Number of processors: {}'.format(self.nprocessors))
45
+ self.config_Reader()
46
+ self.config_InitCond()
47
+ self.config_LevMar()
48
+ self.config_ModelSelector()
49
+ self.satellitedir = '.'
50
+ self.astrometric = False
51
+ self.parameters_ranges = {'PS': [[-11.,1.0, 1.0],[-4.6, 7.6, 1.0],[-300,300,5.0],[-11.5,2.3,2.3]],
52
+ 'PX': [[-3.0,3.0, 0.5],[-4.6, 7.6, 1.0],[-300,300,5.0],[-11.5,2.3,2.3],[-3.0,3.0,0.1],[-3.0,3.0,0.1]],
53
+ 'BS': [[-4.6,7.6,1.0],[-11.5,0.0,0.5],[0,3.0,0.5],[0,3.0,0.5],[-300,300,1.0],[-300,300,1.0],[-11.5,2.3,2.3]],
54
+ 'BO': [[-4.6,7.6,1.0],[-11.5,0.0,0.5],[0,3.0,0.5],[0,3.0,0.5],[-300,300,1.0],[-300,300,1.0],[-11.5,2.3,2.3],
55
+ [-3.0,3.0,0.03],[-3.0,3.0,0.03],[-1.0,1.0,0.01],[-1.0,1.0,0.01],[1.e-7,1.0,0.01]],
56
+ 'LS': [[-4.0,3.0,.1],[-16.1,16.1,0.5],[-3.0,3.0,0.1], [-12.56,12.56,0.1],[-11.5,-2.5,0.3],[-4.6,7.6,0.6],
57
+ [-300,300,5.0]],
58
+ 'LX': [[-4.0,3.0,.1],[-16.1,16.1,0.5],[-3.0,3.0,0.1], [-12.56,12.56,0.1],[-11.5,-2.5,0.3],[-4.6,7.6,0.6],
59
+ [-300,300,5.0],[-3.0,3.0,0.03],[-3.0,3.0,0.03]],
60
+ 'LO': [[-4.0,3.0,.1],[-16.1,16.1,0.5],[-3.0,3.0,0.1], [-12.56,12.56,0.1],[-11.5,-2.5,0.3],[-4.6,7.6,0.6],
61
+ [-300,300,5.0],[-3.0,3.0,0.03],[-3.0,3.0,0.03],[-1.0,1.0,0.01],[-1.0,1.0,0.01],[1.e-7,1.0,0.01]],
62
+ 'LK': [[-4.0,3.0,.1],[-16.1,16.1,0.5],[-3.0,3.0,0.1], [-12.56,12.56,0.1],[-11.5,-2.5,0.3],[-4.6,7.6,0.6],
63
+ [-300,300,5.0],[-3.0,3.0,0.03],[-3.0,3.0,0.03],[-1.0,1.0,0.01],[-1.0,1.0,0.01],[1.e-7,1.0,0.01],
64
+ [-10,10,0.1],[0.5001,10,0.1]],
65
+ 'TS': [[-4.0,3.0,.1],[-16.1,16.1,0.5],[-3.0,3.0,0.1], [-12.56,12.56,0.1],[-11.5,-2.5,0.3],[-4.6,7.6,0.6],
66
+ [-300,300,5.0],[-4.0,3.0,0.3],[-11.5,11.5,0.5], [-12.56,12.56,0.3]],
67
+ 'TX': [[-4.0,3.0,.1],[-16.1,16.1,0.5],[-3.0,3.0,0.1], [-12.56,12.56,0.1],[-11.5,-2.5,0.3],[-4.6,7.6,0.6],
68
+ [-300,300,5.0],[-4.0,3.0,0.3],[-11.5,11.5,0.5], [-12.56,12.56,0.3],[-3.0,3.0,0.03],[-3.0,3.0,0.03]],
69
+ 'TO': [[-4.0,3.0,.1],[-16.1,16.1,0.5],[-3.0,3.0,0.1], [-12.56,12.56,0.1],[-11.5,-2.5,0.3],[-4.6,7.6,0.6],
70
+ [-300,300,5.0],[-4.0,3.0,0.3],[-11.5,11.5,0.5], [-12.56,12.56,0.3],[-3.0,3.0,0.03],[-3.0,3.0,0.03],
71
+ [-1.0,1.0,0.01],[-1.0,1.0,0.01],[1.e-7,1.0,0.01]],
72
+ 'astrometry': [[-30.0,30.0,1.0],[-30.0,30.0,1.0],[0.05,1.0,0.1],[0.001,30.0,0.2]]
73
+ }
74
+
75
+ def set_processors(self, nprocessors):
76
+ self.nprocessors = nprocessors
77
+
78
+ def set_event(self, event):
79
+ self.eventname = os.path.realpath(event)
80
+ if(not os.path.exists(self.eventname)):
81
+ print("! Invalid path for event: " + self.eventname)
82
+
83
+ def set_satellite_dir(self, satellitedir):
84
+ self.satellitedir = os.path.realpath(satellitedir)
85
+ if(not os.path.exists(self.satellitedir)):
86
+ print("! Invalid path for satellite directory: " + self.satellitedir)
87
+
88
+ def set_constraints(self, constraints = None):
89
+ self.constraints = constraints
90
+ if(not os.path.exists(self.eventname + '/' + self.inidir)):
91
+ os.makedirs(self.eventname + '/' + self.inidir)
92
+ with open(self.eventname + '/' + self.inidir + '/Constraints.ini','w') as f:
93
+ for cons in constraints:
94
+ f.write(cons[0] + ' = '+ str(cons[1]) + ' '+ str(cons[2]) + ' '+ str(cons[3]) + ' ' + '\n')
95
+
96
+ def set_parameter_ranges(self):
97
+ if(not os.path.exists(self.eventname + '/' + self.inidir)):
98
+ os.makedirs(self.eventname + '/' + self.inidir)
99
+ with open(self.eventname + '/' + self.inidir + '/Parameters_Ranges.ini','w') as f:
100
+ for modelcode in self.modelcodes:
101
+ f.write(modelcode + '\n')
102
+ for par in self.parameters_ranges[modelcode]:
103
+ f.write(str(par[0]) + ' ' + str(par[1]) + ' ' + str(par[2]) + '\n')
104
+ modelcode = 'astrometry'
105
+ f.write(modelcode + '\n')
106
+ for par in self.parameters_ranges[modelcode]:
107
+ f.write(str(par[0]) + ' ' + str(par[1]) + ' ' + str(par[2]) + '\n')
108
+
109
+
110
+ def config_Reader(self, tau = 1, binning = 4000, otherseasons = 1, renormalize = 1, thresholdoutliers = 10):
111
+ self.Reader_tau= tau # conventional correlation time for consecutive points
112
+ self.Reader_binning = binning # maximum number of points left after re-binning
113
+ self.Reader_otherseasons = otherseasons # How to use other seasons (0: Yes, >=1 decrease significance)
114
+ self.Reader_renormalize = renormalize # Re-normalize error bars if non-zero
115
+ self.Reader_thresholdoutliers = thresholdoutliers # Threshold in sigmas for removing outliers
116
+
117
+ def Reader(self):
118
+ if(not os.path.exists(self.eventname + '/' + self.inidir)):
119
+ os.makedirs(self.eventname + '/' + self.inidir)
120
+ with open(self.eventname + '/' + self.inidir + '/Reader.ini','w') as f:
121
+ f.write('tau = ' + str(self.Reader_tau) + '\n')
122
+ f.write('binning = ' + str(self.Reader_binning) + '\n')
123
+ f.write('otherseasons = ' + str(self.Reader_otherseasons) + '\n')
124
+ f.write('renormalize = ' + str(self.Reader_renormalize) + '\n')
125
+ f.write('thresholdoutliers = ' + str(self.Reader_thresholdoutliers) + '\n')
126
+ print('- Launching: Reader')
127
+ print(' Pre-processing data...')
128
+ try:
129
+ completedprocess=subprocess.run([self.bindir+self.readerexe,self.eventname], cwd = self.bindir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text = True)
130
+ with open(self.eventname + '/FilterToData.txt') as f:
131
+ lines = f.readlines()
132
+ lines = [line.split('.dat')[0] for line in lines]
133
+ sats = [[] for i in range(10)]
134
+ ground = []
135
+ for line in lines:
136
+ if(line[-1].isdigit()):
137
+ sats[int(line[-1])].append(line)
138
+ else:
139
+ ground.append(line)
140
+ print(" Found ground telescopes: ",ground)
141
+ for i in range(10):
142
+ if(len(sats[i])>0):
143
+ print(f" Found satellite {i}: ",sats[i])
144
+ with open(self.eventname + '/LCToFit.txt') as f:
145
+ lines = f.readlines()
146
+ del(lines[0])
147
+ self.astrometric = False
148
+ for line in lines:
149
+ if(float(line.split()[6])>0):
150
+ self.astrometric = True
151
+ print(' Astrometric data found: static models will be skipped')
152
+ break
153
+ print(' OK')
154
+ except subprocess.CalledProcessError as e:
155
+ print('\033[30;41m! Error in pre-processing. Please check your data!\033[m')
156
+ print('\033[30;43m'+e.stdout+'\033[m')
157
+ print('\033[30;43m'+e.stderr+'\033[m')
158
+ print('\033[30;41m! Program stopped here!\033[m')
159
+ self.done = True
160
+
161
+ def config_InitCond(self, npeaks = 2, peakthreshold = 10.0, oldmodels = 4, override = None, nostatic = False, onlyorbital = False, usesatellite = 0
162
+ , templatelibrary = None, modelcategories = ['PS','PX','BS','BO','LS','LX','LO'], onlyupdate =False):
163
+ self.InitCond_npeaks = npeaks # Number of peaks in the observed light curve to be considered for setting initial conditions.
164
+ self.InitCond_peakthreshold = peakthreshold # Number of sigmas necessary for a deviation to be identified as a maximum or a minimum.
165
+ self.InitCond_oldmodels = oldmodels # Maximum number of old models to include in new run as initial conditions
166
+ self.InitCond_override = override # Override peak identification and manually set peak times
167
+ self.InitCond_nostatic = nostatic or onlyorbital # No static models will be calculated.
168
+ self.InitCond_onlyorbital = onlyorbital # Only orbital motion models will be calculated.
169
+ self.InitCond_usesatellite = usesatellite # Satellite to be used for initial conditions. Ground telescopes by default.
170
+ self.InitCond_templatelibrary = templatelibrary # Template library to be used in place of the default one.
171
+ self.InitCond_modelcategories = modelcategories # Model categories to be fit
172
+ self.InitCond_onlyupdate = onlyupdate # No search but only update of previously found best models
173
+
174
+ def InitCond(self):
175
+ ''' Establishes initial conditions for fitting by executing the InitCond external module.
176
+ Options can be assigned through the config_InitCond() method. '''
177
+ if(not os.path.exists(self.eventname + '/' + self.inidir)):
178
+ os.makedirs(self.eventname + '/' + self.inidir)
179
+ with open(self.eventname + '/' + self.inidir + '/InitCond.ini','w') as f:
180
+ f.write('npeaks = ' + str(self.InitCond_npeaks) + '\n')
181
+ f.write('peakthreshold = ' + str(self.InitCond_peakthreshold) + '\n')
182
+ f.write('oldmodels = ' + str(self.InitCond_oldmodels) + '\n')
183
+ f.write('usesatellite = ' + str(self.InitCond_usesatellite) + '\n')
184
+ if(self.InitCond_nostatic):
185
+ f.write('nostatic = 1\n')
186
+ if(self.InitCond_onlyorbital):
187
+ f.write('onlyorbital = 1\n')
188
+ if(self.InitCond_override != None):
189
+ f.write('override = ' + str(self.InitCond_override[0])+ ' ' + str(self.InitCond_override[1]) + '\n')
190
+ if(self.InitCond_templatelibrary != None):
191
+ f.write('templatelibrary = ' + self.InitCond_templatelibrary + '\n')
192
+ if(self.InitCond_modelcategories != None):
193
+ f.write('modelcategories = '+ ''.join(self.InitCond_modelcategories) + '\n')
194
+ if(self.InitCond_onlyupdate):
195
+ f.write('onlyupdate = 1\n')
196
+ print('- Launching: InitCond')
197
+ print(' Setting initial conditions...')
198
+ try:
199
+ completedprocess=subprocess.run([self.bindir+self.initcondexe,self.eventname], cwd = self.bindir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text = True)
200
+ peaksearch = True
201
+ imod=0
202
+ while(peaksearch):
203
+ initfils=glob.glob(self.eventname + '/InitCond/InitCond'+ self.modelcodes[imod] + '*')
204
+ if(len(initfils)!=0):
205
+ peaksearch = False
206
+ with open(initfils[0], 'r') as f:
207
+ npeaks = int(f.readline().split()[0])
208
+ print('Peaks: ')
209
+ for i in range(0,npeaks):
210
+ chs=f.readline().split()
211
+ print(f'{float(chs[0]):.4f} [{float(chs[4]):.4f}]')
212
+ imod+=1
213
+ print('\n OK')
214
+ except subprocess.CalledProcessError as e:
215
+ print('\033[30;41m! Error in setting initial conditions!\033[m')
216
+ print('\033[30;43m'+e.stdout+'\033[m')
217
+ print('\033[30;43m'+e.stderr+'\033[m')
218
+ print('\033[30;41m! Program stopped here!\033[m')
219
+ self.done = True
220
+
221
+ def config_LevMar(self, nfits = 6, offsetdegeneracy = 2, timelimit = 600.0, maxsteps = 50, bumperpower = 2.0, \
222
+ mass_luminosity_exponent = None, mass_radius_exponent = None, lens_mass_luminosity_exponent = None, \
223
+ turn_off_secondary_source = False, turn_off_secondary_lens = False, block_tertiary_lens = False, stepchainsave=False):
224
+ self.LevMar_nfits = nfits # Number of models to be calculated from the same initial condition using the bumper method
225
+ self.LevMar_offsetdegeneracy = offsetdegeneracy # Number of models to be fit after applying offset degeneracy to best model found so far
226
+ self.LevMar_maxsteps = maxsteps # Maximum number of steps in each fit
227
+ self.LevMar_timelimit = timelimit # Maximum time in seconds for total execution
228
+ self.LevMar_bumperpower = bumperpower # Repulsion factor of bumpers
229
+ self.LevMar_mass_luminosity_exponent = mass_luminosity_exponent # mass-luminosity exponent for binary sources
230
+ self.LevMar_mass_radius_exponent = mass_radius_exponent # mass-radius exponent for binary sources
231
+ self.LevMar_lens_mass_luminosity_exponent = lens_mass_luminosity_exponent # mass-luminosity exponent for binary lenses
232
+ self.LevMar_turn_off_secondary_lens = turn_off_secondary_lens # Option for dark secondary lenses
233
+ self.LevMar_turn_off_secondary_source = turn_off_secondary_source # Option for dark secondary sources
234
+ self.LevMar_block_tertiary_lens = block_tertiary_lens # Option for blocked tertiary lens
235
+ self.LevMar_stepchainsave = stepchainsave # If True, step chains are saved
236
+
237
+ def LevMar(self,strmodel, parameters_file = None, parameters = None):
238
+ if(not os.path.exists(self.eventname + '/' + self.inidir)):
239
+ os.makedirs(self.eventname + '/' + self.inidir)
240
+ if(parameters != None):
241
+ parameters_file = self.eventname + '/' + self.inidir + '/parameters.ini'
242
+ with open(parameters_file,'w') as f:
243
+ line =''
244
+ for fl in parameters:
245
+ line = line + str(fl) + ' '
246
+ f.write(line)
247
+ self.set_parameter_ranges()
248
+ with open(self.eventname + '/' + self.inidir + '/LevMar.ini','w') as f:
249
+ f.write('nfits = ' + str(self.LevMar_nfits) + '\n')
250
+ f.write('offsetdegeneracy = ' + str(self.LevMar_offsetdegeneracy) + '\n')
251
+ f.write('maxsteps = ' + str(self.LevMar_maxsteps) + '\n')
252
+ f.write('timelimit = ' + str(self.LevMar_timelimit) + '\n')
253
+ f.write('bumperpower = ' + str(self.LevMar_bumperpower) + '\n')
254
+ if(self.LevMar_mass_luminosity_exponent != None):
255
+ f.write('mass_luminosity_exponent = ' + str(self.LevMar_mass_luminosity_exponent) + '\n')
256
+ if(self.LevMar_mass_radius_exponent != None):
257
+ f.write('mass_radius_exponent = ' + str(self.LevMar_mass_radius_exponent) + '\n')
258
+ if(self.LevMar_mass_luminosity_exponent != None):
259
+ f.write('lens_mass_luminosity_exponent = ' + str(self.LevMar_lens_mass_luminosity_exponent) + '\n')
260
+ if(self.LevMar_turn_off_secondary_lens):
261
+ f.write('turn_off_secondary_lens = True\n')
262
+ if(self.LevMar_turn_off_secondary_source):
263
+ f.write('turn_off_secondary_source = True\n')
264
+ if(self.LevMar_block_tertiary_lens):
265
+ f.write('block_tertiary_lens = True\n')
266
+ if(parameters_file != None):
267
+ f.write('parametersfile = ' + parameters_file)
268
+ if(self.LevMar_stepchainsave):
269
+ f.write('stepchainsave = True\n')
270
+ print('- Launching: LevMar')
271
+ print(' Fitting ' + strmodel + ' ...')
272
+ try:
273
+ completedprocess=subprocess.run([self.bindir+self.levmarexe,self.eventname, strmodel,self.satellitedir], cwd = self.bindir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text = True)
274
+ print(' OK')
275
+ except subprocess.CalledProcessError as e:
276
+ print('\033[30;41m! Error in fit!\033[m')
277
+ print('\033[30;43m'+e.stdout+'\033[m')
278
+ print('\033[30;43m'+e.stderr+'\033[m')
279
+ print('\033[30;41m! Program stopped here!\033[m')
280
+ self.done = True
281
+
282
+ def launch_fits(self,modelcode):
283
+ if(not os.path.exists(self.eventname + '/' + self.inidir)):
284
+ os.makedirs(self.eventname + '/' + self.inidir)
285
+ with open(self.eventname + '/' + self.inidir + '/LevMar.ini','w') as f:
286
+ f.write('nfits = ' + str(self.LevMar_nfits) + '\n')
287
+ f.write('offsetdegeneracy = ' + str(self.LevMar_offsetdegeneracy) + '\n')
288
+ f.write('maxsteps = ' + str(self.LevMar_maxsteps) + '\n')
289
+ f.write('timelimit = ' + str(self.LevMar_timelimit) + '\n')
290
+ f.write('bumperpower = ' + str(self.LevMar_bumperpower) + '\n')
291
+ if(self.LevMar_mass_luminosity_exponent != None):
292
+ f.write('mass_luminosity_exponent = ' + str(self.LevMar_mass_luminosity_exponent) + '\n')
293
+ if(self.LevMar_mass_radius_exponent != None):
294
+ f.write('mass_radius_exponent = ' + str(self.LevMar_mass_radius_exponent) + '\n')
295
+ if(self.LevMar_lens_mass_luminosity_exponent != None):
296
+ f.write('lens_mass_luminosity_exponent = ' + str(self.LevMar_lens_mass_luminosity_exponent) + '\n')
297
+ if(self.LevMar_turn_off_secondary_lens):
298
+ f.write('turn_off_secondary_lens = True\n')
299
+ if(self.LevMar_turn_off_secondary_source):
300
+ f.write('turn_off_secondary_source = True\n')
301
+ if(self.LevMar_block_tertiary_lens):
302
+ f.write('block_tertiary_lens = True\n')
303
+ if(self.LevMar_stepchainsave):
304
+ f.write('stepchainsave = True\n')
305
+ stringfits = {'PS' : '- Single-lens-Single-source fits',
306
+ 'PX' : '- Single-lens-Single-source fits with parallax',
307
+ 'BS' : '- Single-lens-Binary-source fits',
308
+ 'BO' : '- Single-lens-Binary-source fits with xallarap',
309
+ 'LS' : '- Binary-lens-Single-source fits',
310
+ 'LX' : '- Binary-lens-Single-source fits with parallax',
311
+ 'LO' : '- Binary-lens-Single-source fits with orbital motion',
312
+ 'LK' : '- Binary-lens-Single-source fits with eccentric orbital motion',
313
+ 'TS' : '- Triple-lens-Single-source fits',
314
+ 'TX' : '- Triple-lens-Single-source fits with parallax',
315
+ 'TO' : '- Triple-lens-Single-source fits with orbital motion'}
316
+ self.set_parameter_ranges()
317
+ print(stringfits[modelcode])
318
+ initcondfile = self.eventname + '/InitCond/' + 'InitCond'+ modelcode + '.txt'
319
+ if(os.path.exists(initcondfile)):
320
+ with open(self.eventname + '/InitCond/' + 'InitCond'+ modelcode + '.txt') as f:
321
+ line = f.readline().split()
322
+ npeaks = int(line[0])
323
+ ninitconds = int(line[1])
324
+ processes = []
325
+ procnumbers = []
326
+ procepochs = []
327
+ iinitcond = 0
328
+ finitcond = 0
329
+ finitcondold = -1
330
+ timeouts = 0
331
+ crashes = 0
332
+ pbar = tqdm(total = ninitconds,desc = 'Fits completed',file=sys.stdout, colour='GREEN', smoothing = 0)
333
+ while(finitcond < ninitconds):
334
+ i=0
335
+ while i < len(processes):
336
+ if(time.time() - procepochs[i] > self.LevMar_timelimit):
337
+ processes[i].kill()
338
+ timeouts += 1
339
+ crashes -= 1
340
+ #premodfiles = glob.glob(self.eventname +'/PreModels/*.txt')
341
+ #strmodel = modelcode + '{:0>4}'.format(str(procnumbers[i]))
342
+ #with open(self.eventname +'/PreModels/' + strmodel + '/t' + strmodel + '.dat','w') as f:
343
+ # f.write(f'{len(premodfiles)} {self.LevMar_nfits}')
344
+ if(processes[i].poll() != None):
345
+ if(processes[i].returncode!=0):
346
+ crashes +=1
347
+ # Here we have to append results to main model file
348
+ if(not self.LevMar_stepchainsave):
349
+ strmodel = modelcode + '{:0>4}'.format(str(procnumbers[i])) + ".txt"
350
+ if(os.path.exists(self.eventname +'/PreModels/' + strmodel)):
351
+ with open(self.eventname +'/PreModels/' + strmodel) as f:
352
+ content = f.read()
353
+ with open(self.eventname +'/PreModels/'+ modelcode + ".txt","a") as f:
354
+ f.write(content)
355
+ os.remove(self.eventname +'/PreModels/' + strmodel)
356
+ processes.pop(i)
357
+ procnumbers.pop(i)
358
+ procepochs.pop(i)
359
+ finitcond += 1
360
+ else:
361
+ i += 1
362
+ while(iinitcond < ninitconds and len(processes) < self.nprocessors):
363
+ strmodel = modelcode + '{:0>4}'.format(str(iinitcond))
364
+ #if(glob.glob(self.eventname +'/PreModels/' + strmodel + '/t' + strmodel + '.dat')==[]):
365
+ processes.append(subprocess.Popen([self.bindir+self.levmarexe,self.eventname, strmodel,self.satellitedir], cwd = self.bindir, shell = False, stdout=subprocess.DEVNULL))
366
+ procnumbers.append(iinitcond)
367
+ procepochs.append(time.time())
368
+ #else:
369
+ # finitcond += 1
370
+ iinitcond += 1
371
+ if(finitcond != finitcondold):
372
+ #print(' Fits launched: {}; completed: {}/{}'.format(iinitcond, finitcond, ninitconds))
373
+ pbar.update(finitcond - max(finitcondold,0))
374
+ finitcondold =finitcond
375
+ time.sleep(0.1)
376
+ pbar.close()
377
+ if(crashes>0):
378
+ print('crashed fits: ' + str(crashes))
379
+ if(timeouts>0):
380
+ print('timed out fits: ' + str(timeouts))
381
+ print(' OK')
382
+ else:
383
+ print('- No initial conditions for this category')
384
+
385
+ def config_ModelSelector(self, sigmasoverlap = 3.0, sigmachisquare = 1.0, maxmodels = 10):
386
+ self.ModelSelector_sigmasoverlap = sigmasoverlap # factor multiplying the inverse covariance in search for superpositions (models are incompatible if farther than sigmasoverlap*sigma)
387
+ self.ModelSelector_sigmachisquare = sigmachisquare # number of sigmas in the chi square distribution for accepting alternative models after the best one
388
+ self.ModelSelector_maxmodels = maxmodels # maximum number of models returned
389
+
390
+ def ModelSelector(self, modelcode):
391
+ if(not os.path.exists(self.eventname + '/' + self.inidir)):
392
+ os.makedirs(self.eventname + '/' + self.inidir)
393
+ with open(self.eventname + '/' + self.inidir + '/ModelSelector.ini','w') as f:
394
+ f.write('sigmasoverlap = ' + str(self.ModelSelector_sigmasoverlap) + '\n')
395
+ f.write('sigmachisquare = ' + str(self.ModelSelector_sigmachisquare) + '\n')
396
+ f.write('maxmodels = ' + str(self.ModelSelector_maxmodels) + '\n')
397
+ stringmodels = {'PS' : '- Selecting models for Single-lens-Single-source fits',
398
+ 'PX' : '- Selecting models for Single-lens-Single-source fits with parallax',
399
+ 'BS' : '- Selecting models for Single-lens-Binary-source fits',
400
+ 'BO' : '- Selecting models for Single-lens-Binary-source fits with xallarap',
401
+ 'LS' : '- Selecting models for Binary-lens-Single-source fits',
402
+ 'LX' : '- Selecting models for Binary-lens-Single-source fits with parallax',
403
+ 'LO' : '- Selecting models for Binary-lens-Single-source fits with orbital motion',
404
+ 'LK' : '- Selecting models for Binary-lens-Single-source fits with eccentric orbital motion',
405
+ 'TS' : '- Selecting models for Triple-lens-Single-source fits',
406
+ 'TX' : '- Selecting models for Triple-lens-Single-source fits with parallax',
407
+ 'TO' : '- Selecting models for Triple-lens-Single-source fits with orbital motion'}
408
+ print(stringmodels[modelcode])
409
+ try:
410
+ completedprocess=subprocess.run([self.bindir+self.modelselectorexe,self.eventname, modelcode], cwd = self.bindir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text = True)
411
+ print(' OK')
412
+ except subprocess.CalledProcessError as e:
413
+ print('\033[30;41m! Error in model selection!\033[m')
414
+ print('\033[30;43m'+e.stdout+'\033[m')
415
+ print('\033[30;43m'+e.stderr+'\033[m')
416
+ print('\033[30;41m! Program stopped here!\033[m')
417
+ self.done = True
418
+
419
+ def Finalizer(self):
420
+ print('- Launching: Finalizer')
421
+ print(' Making final assessment for this event')
422
+ try:
423
+ completedprocess=subprocess.run([self.bindir+self.finalizerexe,self.eventname], cwd = self.bindir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True, text = True)
424
+ with open(self.eventname + '/Nature.txt') as f:
425
+ for line in f.readlines():
426
+ print(" " + line,end='')
427
+ print(" OK")
428
+ except subprocess.CalledProcessError as e:
429
+ print('\033[30;41m! Error in finalization!\033[m')
430
+ print('\033[30;43m'+e.stdout+'\033[m')
431
+ print('\033[30;43m'+e.stderr+'\033[m')
432
+ print('\033[30;41m! Program stopped here!\033[m')
433
+ self.done = True
434
+
435
+ def run(self, event = None, cleanup = True):
436
+ if(not cleanup):
437
+ self.LevMar_stepchainsave = True
438
+ phase =0
439
+ if(event!= None):
440
+ self.eventname = os.path.realpath(event)
441
+ self.done = False
442
+ print("o " + time.asctime())
443
+ while not(self.done):
444
+ # Check that event directory exists
445
+ if phase == 0:
446
+ if(os.path.exists(self.eventname + '/Data')):
447
+ print('- Analyzing event: ',self.eventname)
448
+ phase = 1
449
+ else:
450
+ print('! Event data for ' + self.eventname + ' not found !')
451
+ self.done = True
452
+ # Launch Reader
453
+ elif phase == 1:
454
+ self.Reader()
455
+ print("o " + time.asctime())
456
+ phase = 2
457
+ # Launch InitCond
458
+ elif phase == 2:
459
+ self.InitCond()
460
+ print("o " + time.asctime())
461
+ phase = 3
462
+ # Launch Finalizer
463
+ elif phase == self.endphase:
464
+ self.Finalizer()
465
+ print("o " + time.asctime())
466
+ phase += 1
467
+ # Conclude analysis
468
+ elif phase > self.endphase:
469
+ if(cleanup):
470
+ print('- Cleaning up preliminary models')
471
+ self.cleanup_preliminary_models()
472
+ print("- Analysis of " + self.eventname + " successfully completed!")
473
+ print("o " + time.asctime())
474
+ self.done = True
475
+ # Launch LevMar for next class
476
+ elif phase%2 == 1:
477
+ if(self.InitCond_modelcategories == None or self.modelcodes[phase//2-1] in self.InitCond_modelcategories):
478
+ self.launch_fits(self.modelcodes[phase//2-1])
479
+ print("o " + time.asctime())
480
+ phase += 1
481
+ # Launch ModelSelector for this class
482
+ else:
483
+ if(self.InitCond_modelcategories == None or self.modelcodes[phase//2-2] in self.InitCond_modelcategories):
484
+ self.ModelSelector(self.modelcodes[phase//2-2])
485
+ print("o " + time.asctime())
486
+ phase += 1
487
+
488
+ def cleanup_preliminary_models(self):
489
+ os.chdir(self.eventname)
490
+ if(os.path.exists('PreModels')):
491
+ shutil.rmtree('PreModels')
492
+
493
+ def archive_run(self, destination = None):
494
+ olddir = os.getcwd()
495
+ os.chdir(self.eventname)
496
+ if(os.path.exists('LCToFit.txt')):
497
+ previousrunslist = glob.glob('run-*')
498
+ previousrunslist.sort()
499
+ if(destination == None):
500
+ if(len(previousrunslist)>0):
501
+ lastrun = int(previousrunslist[-1].split('-')[-1])
502
+ else:
503
+ lastrun = 0
504
+ rundir = 'run-' + str(lastrun+1). zfill(4)
505
+ else:
506
+ rundir = destination
507
+ alllist = glob.glob('*')
508
+ alllist.remove('Data')
509
+ filelist = list(set(alllist) - set(previousrunslist))
510
+ os.mkdir(rundir)
511
+ shutil.copytree('Data',rundir+'/Data')
512
+ for nam in filelist:
513
+ shutil.move(nam,rundir)
514
+ os.chdir(olddir)
515
+
516
+ def recover_options(self,run = None):
517
+ if(self.eventname == None):
518
+ print('! No event chosen')
519
+ if(run!=None):
520
+ pathname = run
521
+ else:
522
+ pathname = self.eventname
523
+ if(not(os.path.exists(pathname))):
524
+ print("Invalid path!")
525
+ return
526
+ if(os.path.exists(pathname + '/' + self.inidir + '/Constraints.ini')):
527
+ with open(pathname + '/' + self.inidir + '/Constraints.ini','r') as f:
528
+ lines = f.read().splitlines()
529
+ print('Constraints --- ',lines)
530
+ self.constraints =[]
531
+ for line in lines:
532
+ chunks =line.split()
533
+ self.constraints.append([chunks[0], float(chunks[2]), float(chunks[3]), float(chunks[4])])
534
+ self.set_constraints(self.constraints)
535
+ if(os.path.exists(pathname + '/' + self.inidir + '/Reader.ini')):
536
+ with open(pathname + '/' + self.inidir + '/Reader.ini','r') as f:
537
+ lines = f.read().splitlines()
538
+ print('Reader --- ',lines)
539
+ for line in lines:
540
+ chunks = line.split()
541
+ if(chunks[0]=='tau'):
542
+ self.Reader_tau = float(chunks[2])
543
+ elif(chunks[0]=='binning'):
544
+ self.Reader_binning = int(chunks[2])
545
+ elif(chunks[0]=='otherseasons'):
546
+ self.Reader_otherseasons = int(chunks[2])
547
+ elif(chunks[0]=='renormalize'):
548
+ self.Reader_renormalize = int(chunks[2])
549
+ elif(chunks[0]=='thresholdoutliers'):
550
+ self.Reader_thresholdoutliers = float(chunks[2])
551
+ if(os.path.exists(pathname + '/' + self.inidir + '/InitCond.ini')):
552
+ with open(pathname + '/' + self.inidir + '/InitCond.ini','r') as f:
553
+ lines = f.read().splitlines()
554
+ print('InitCond --- ',lines)
555
+ self.InitCond_nostatic = False
556
+ self.InitCond_onlyorbital = False
557
+ self.InitCond_override = None
558
+ self.InitCond_onlyupdate = False
559
+ for line in lines:
560
+ chunks = line.split()
561
+ if(chunks[0]=='npeaks'):
562
+ self.InitCond_npeaks = int(chunks[2])
563
+ elif(chunks[0]=='peakthreshold'):
564
+ self.InitCond_peakthreshold = float(chunks[2])
565
+ elif(chunks[0]=='oldmodels'):
566
+ self.InitCond_oldmodels = int(chunks[2])
567
+ elif(chunks[0]=='usesatellite'):
568
+ self.InitCond_usesatellite = int(chunks[2])
569
+ elif(chunks[0]=='nostatic'):
570
+ self.InitCond_nostatic = (int(chunks[2])!=0)
571
+ elif(chunks[0]=='onlyorbital'):
572
+ self.InitCond_onlyorbital = (int(chunks[2])!=0)
573
+ elif(chunks[0]=='onlyupdate'):
574
+ self.InitCond_onlyupdate = (int(chunks[2])!=0)
575
+ elif(chunks[0]=='override'):
576
+ self.InitCond_override = (float(chunks[2]),float(chunks[3]))
577
+ elif(chunks[0]=='templatelibrary'):
578
+ self.InitCond_templatelibrary = chunks[2]
579
+ elif(chunks[0]=='modelcategories'):
580
+ self.InitCond_modelcategories = [chunks[2][i:i+2] for i in range(0, len(chunks[2]), 2)]
581
+ if(os.path.exists(pathname + '/' + self.inidir + '/LevMar.ini')):
582
+ with open(pathname + '/' + self.inidir + '/LevMar.ini','r') as f:
583
+ lines = f.read().splitlines()
584
+ print('LevMar --- ',lines)
585
+ for line in lines:
586
+ chunks = line.split()
587
+ if(chunks[0]=='nfits'):
588
+ self.LevMar_nfits = int(chunks[2])
589
+ if(chunks[0]=='offsetdegeneracy'):
590
+ self.LevMar_offsetdegeneracy = int(chunks[2])
591
+ elif(chunks[0]=='maxsteps'):
592
+ self.LevMar_maxsteps = int(chunks[2])
593
+ elif(chunks[0]=='timelimit'):
594
+ self.LevMar_timelimit = float(chunks[2])
595
+ elif(chunks[0]=='bumperpower'):
596
+ self.LevMar_bumperpower = float(chunks[2])
597
+ elif(chunks[0] == 'turn_off_secondary_source' and chunks[2] == 'True'):
598
+ self.LevMar_turn_off_secondary_source = True
599
+ elif(chunks[0] == 'turn_off_secondary_lens' and chunks[2] == 'True'):
600
+ self.LevMar_turn_off_secondary_lens = True
601
+ elif(chunks[0] == 'block_tertiary_lens' and chunks[2] == 'True'):
602
+ self.LevMar_block_tertiary_lens = True
603
+ elif(chunks[0] == 'mass_luminosity_exponent'):
604
+ self.LevMar_mass_luminosity_exponent = float(chunks[2])
605
+ elif(chunks[0] == 'mass_radius_exponent'):
606
+ self.LevMar_mass_radius_exponent = float(chunks[2])
607
+ elif(chunks[0] == 'lens_mass_luminosity_exponent'):
608
+ self.LevMar_lens_mass_luminosity_exponent = float(chunks[2])
609
+ if(os.path.exists(pathname + '/' + self.inidir + '/ModelSelector.ini')):
610
+ with open(pathname + '/' + self.inidir + '/ModelSelector.ini','r') as f:
611
+ lines = f.read().splitlines()
612
+ print('ModelSelector --- ',lines)
613
+ for line in lines:
614
+ chunks = line.split()
615
+ if(chunks[0]=='sigmasoverlap'):
616
+ self.ModelSelector_sigmasoverlap = float(chunks[2])
617
+ elif(chunks[0]=='sigmachisquare'):
618
+ self.ModelSelector_sigmachisquare = float(chunks[2])
619
+ elif(chunks[0]=='maxmodels'):
620
+ self.ModelSelector_maxmodels = int(chunks[2])
621
+
622
+ @staticmethod
623
+ def find_bin_directory() -> str:
624
+ """
625
+ Searches for the RTModel/bin directory in the available site-packages directories.
626
+
627
+ :return: The string of the parth to the bin directory.
628
+ """
629
+ bin_directory_string = None
630
+ site_packages_directories = site.getsitepackages()
631
+ site_packages_directories.append(site.getusersitepackages())
632
+ for site_packages_directory in site_packages_directories:
633
+ bin_directory_path = Path(site_packages_directory).joinpath('RTModel/bin')
634
+ if bin_directory_path.exists():
635
+ bin_directory_string = str(bin_directory_path) + '/'
636
+ break
637
+ if bin_directory_string is None:
638
+ raise FileNotFoundError(f'RTModel binary directory not found. Searched {site_packages_directories} '
639
+ f'site-packages directories.')
640
+ return bin_directory_string
RTModel/__init__.py ADDED
@@ -0,0 +1,8 @@
1
+ __author__ = 'Valerio Bozza'
2
+ __credits__ = 'University of Salerno, Italy'
3
+
4
+ from .RTModel import RTModel
5
+
6
+ from importlib.metadata import version
7
+
8
+ __version__ = version("RTModel")
Binary file
Binary file
RTModel/bin/LevMar.exe ADDED
Binary file
Binary file