1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 """ A python file to replace the fortran script gen_ximprove.
16 This script analyses the result of the survey/ previous refine and
17 creates the jobs for the following script.
18 """
19 from __future__ import division
20
21 from __future__ import absolute_import
22 import collections
23 import os
24 import glob
25 import logging
26 import math
27 import re
28 import subprocess
29 import shutil
30 import stat
31 import sys
32 import six
33 from six.moves import range
34 from six.moves import zip
35
36 try:
37 import madgraph
38 except ImportError:
39 MADEVENT = True
40 import internal.sum_html as sum_html
41 import internal.banner as bannermod
42 import internal.misc as misc
43 import internal.files as files
44 import internal.cluster as cluster
45 import internal.combine_grid as combine_grid
46 import internal.combine_runs as combine_runs
47 import internal.lhe_parser as lhe_parser
48 if six.PY3:
49 import internal.hel_recycle as hel_recycle
50 else:
51 MADEVENT= False
52 import madgraph.madevent.sum_html as sum_html
53 import madgraph.various.banner as bannermod
54 import madgraph.various.misc as misc
55 import madgraph.iolibs.files as files
56 import madgraph.various.cluster as cluster
57 import madgraph.madevent.combine_grid as combine_grid
58 import madgraph.madevent.combine_runs as combine_runs
59 import madgraph.various.lhe_parser as lhe_parser
60 if six.PY3:
61 import madgraph.madevent.hel_recycle as hel_recycle
62
63 logger = logging.getLogger('madgraph.madevent.gen_ximprove')
64 pjoin = os.path.join
67 """a class to call the fortran gensym executable and handle it's output
68 in order to create the various job that are needed for the survey"""
69
70
71 @ staticmethod
74
75 combining_job = 2
76 splitted_grid = False
77 min_iterations = 3
78 mode= "survey"
79
80
82
83 try:
84 super(gensym, self).__init__(cmd, opt)
85 except TypeError:
86 pass
87
88
89 self.run_statistics = {}
90
91 self.cmd = cmd
92 self.run_card = cmd.run_card
93 self.me_dir = cmd.me_dir
94
95
96
97 self.cross = collections.defaultdict(int)
98 self.abscross = collections.defaultdict(int)
99 self.sigma = collections.defaultdict(int)
100 self.chi2 = collections.defaultdict(int)
101
102 self.splitted_grid = False
103 if self.cmd.proc_characteristics['loop_induced']:
104 nexternal = self.cmd.proc_characteristics['nexternal']
105 self.splitted_grid = max(2, (nexternal-2)**2)
106 if hasattr(self.cmd, "opts") and self.cmd.opts['accuracy'] == 0.1:
107 self.cmd.opts['accuracy'] = 0.02
108
109 if isinstance(cmd.cluster, cluster.MultiCore) and self.splitted_grid > 1:
110 self.splitted_grid = int(cmd.cluster.nb_core**0.5)
111 if self.splitted_grid == 1 and cmd.cluster.nb_core >1:
112 self.splitted_grid = 2
113
114
115 if self.run_card['survey_splitting'] != -1:
116 self.splitted_grid = self.run_card['survey_splitting']
117 if self.run_card['survey_nchannel_per_job'] != 1 and 'survey_nchannel_per_job' in self.run_card.user_set:
118 self.combining_job = self.run_card['survey_nchannel_per_job']
119 elif self.run_card['hard_survey'] > 1:
120 self.combining_job = 1
121
122
123 self.splitted_Pdir = {}
124 self.splitted_for_dir = lambda x,y: self.splitted_grid
125 self.combining_job_for_Pdir = lambda x: self.combining_job
126 self.lastoffset = {}
127
128 done_warning_zero_coupling = False
130 """launch a single call to madevent to get the list of non zero helicity"""
131
132 self.subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses',
133 'subproc.mg'))]
134 subproc = self.subproc
135 P_zero_result = []
136 nb_tot_proc = len(subproc)
137 job_list = {}
138
139
140 for nb_proc,subdir in enumerate(subproc):
141 self.cmd.update_status('Compiling for process %s/%s.' % \
142 (nb_proc+1,nb_tot_proc), level=None)
143
144 subdir = subdir.strip()
145 Pdir = pjoin(self.me_dir, 'SubProcesses',subdir)
146 logger.info(' %s ' % subdir)
147
148 self.cmd.compile(['madevent_forhel'], cwd=Pdir)
149 if not os.path.exists(pjoin(Pdir, 'madevent_forhel')):
150 raise Exception('Error make madevent_forhel not successful')
151
152 if not os.path.exists(pjoin(Pdir, 'Hel')):
153 os.mkdir(pjoin(Pdir, 'Hel'))
154 ff = open(pjoin(Pdir, 'Hel', 'input_app.txt'),'w')
155 ff.write('1000 1 1 \n 0.1 \n 2\n 0\n -1\n 1\n')
156 ff.close()
157 else:
158 try:
159 os.remove(pjoin(Pdir, 'Hel','results.dat'))
160 except Exception:
161 pass
162
163 p = misc.Popen(['../madevent_forhel < input_app.txt'], stdout=subprocess.PIPE,
164 stderr=subprocess.STDOUT, cwd=pjoin(Pdir,'Hel'), shell=True)
165
166 (stdout, _) = p.communicate(" ".encode())
167 stdout = stdout.decode('ascii')
168 if os.path.exists(pjoin(self.me_dir,'error')):
169 raise Exception(pjoin(self.me_dir,'error'))
170
171
172
173
174 if 'no events passed cuts' in stdout:
175 raise Exception
176
177 all_zamp = set()
178 all_hel = set()
179 zero_gc = list()
180 all_zampperhel = set()
181 all_bad_amps_perhel = set()
182
183 for line in stdout.splitlines():
184 if 'GC_' in line:
185 lsplit = line.split()
186 if float(lsplit[2]) ==0 == float(lsplit[3]):
187 zero_gc.append(lsplit[0])
188 if 'Matrix Element/Good Helicity:' in line:
189 all_hel.add(tuple(line.split()[3:5]))
190 if 'Amplitude/ZEROAMP:' in line:
191 all_zamp.add(tuple(line.split()[1:3]))
192 if 'HEL/ZEROAMP:' in line:
193 nb_mat, nb_hel, nb_amp = line.split()[1:4]
194 if (nb_mat, nb_hel) not in all_hel:
195 continue
196 if (nb_mat,nb_amp) in all_zamp:
197 continue
198 all_zampperhel.add(tuple(line.split()[1:4]))
199
200 if zero_gc and not gensym.done_warning_zero_coupling:
201 gensym.done_warning_zero_coupling = True
202 logger.warning("The optimizer detects that you have coupling evaluated to zero: \n"+\
203 "%s\n" % (' '.join(zero_gc)) +\
204 "This will slow down the computation. Please consider using restricted model:\n" +\
205 "https://answers.launchpad.net/mg5amcnlo/+faq/2312")
206
207
208 all_good_hels = collections.defaultdict(list)
209 for me_index, hel in all_hel:
210 all_good_hels[me_index].append(int(hel))
211
212
213 if self.run_card['hel_zeroamp']:
214 all_bad_amps = collections.defaultdict(list)
215 for me_index, amp in all_zamp:
216 all_bad_amps[me_index].append(int(amp))
217
218 all_bad_amps_perhel = collections.defaultdict(list)
219 for me_index, hel, amp in all_zampperhel:
220 all_bad_amps_perhel[me_index].append((int(hel),int(amp)))
221
222 elif all_zamp:
223 nb_zero = sum(int(a[1]) for a in all_zamp)
224 if zero_gc:
225 logger.warning("Those zero couplings lead to %s Feynman diagram evaluated to zero (on 10 PS point),\n" % nb_zero +\
226 "This part can optimize if you set the flag hel_zeroamp to True in the run_card."+\
227 "Note that restricted model will be more optimal.")
228 else:
229 logger.warning("The optimization detected that you have %i zero matrix-element for this SubProcess: %s.\n" % nb_zero +\
230 "This part can optimize if you set the flag hel_zeroamp to True in the run_card.")
231
232
233 data = [all_hel, all_zamp, all_bad_amps_perhel]
234 if not self.run_card['hel_zeroamp']:
235 data[1] = ''
236 if not self.run_card['hel_filtering']:
237 data[0] = ''
238 data = str(data)
239 if os.path.exists(pjoin(Pdir,'Hel','selection')):
240 old_data = open(pjoin(Pdir,'Hel','selection')).read()
241 if old_data == data:
242 continue
243
244
245 with open(pjoin(Pdir,'Hel','selection'),'w') as fsock:
246 fsock.write(data)
247
248
249 for matrix_file in misc.glob('matrix*orig.f', Pdir):
250
251 split_file = matrix_file.split('/')
252 me_index = split_file[-1][len('matrix'):-len('_orig.f')]
253
254 basename = split_file[-1].replace('orig', 'optim')
255 split_out = split_file[:-1] + [basename]
256 out_file = pjoin('/', '/'.join(split_out))
257
258 basename = 'template_%s' % split_file[-1].replace("_orig", "")
259 split_templ = split_file[:-1] + [basename]
260 templ_file = pjoin('/', '/'.join(split_templ))
261
262
263
264 good_hels = [str(x) for x in sorted(all_good_hels[me_index])]
265 if self.run_card['hel_zeroamp']:
266
267 bad_amps = [str(x) for x in sorted(all_bad_amps[me_index])]
268 bad_amps_perhel = [x for x in sorted(all_bad_amps_perhel[me_index])]
269 else:
270 bad_amps = []
271 bad_amps_perhel = []
272 if __debug__:
273 mtext = open(matrix_file).read()
274 nb_amp = int(re.findall('PARAMETER \(NGRAPHS=(\d+)\)', mtext)[0])
275 logger.debug('nb_hel: %s zero amp: %s bad_amps_hel: %s/%s', len(good_hels),len(bad_amps),len(bad_amps_perhel), len(good_hels)*nb_amp )
276 if len(good_hels) == 1:
277 files.cp(matrix_file, matrix_file.replace('orig','optim'))
278 continue
279 recycler = hel_recycle.HelicityRecycler(good_hels, bad_amps, bad_amps_perhel)
280
281 recycler.hel_filt = self.run_card['hel_filtering']
282 recycler.amp_splt = self.run_card['hel_splitamp']
283 recycler.amp_filt = self.run_card['hel_zeroamp']
284
285 recycler.set_input(matrix_file)
286 recycler.set_output(out_file)
287 recycler.set_template(templ_file)
288 recycler.generate_output_file()
289 del recycler
290
291
292
293
294
295
296 return {}, P_zero_result
297
298
299 - def launch(self, to_submit=True, clean=True):
300 """ """
301
302 if not hasattr(self, 'subproc'):
303 self.subproc = [l.strip() for l in open(pjoin(self.me_dir,'SubProcesses',
304 'subproc.mg'))]
305 subproc = self.subproc
306
307 P_zero_result = []
308
309 nb_tot_proc = len(subproc)
310 job_list = {}
311 for nb_proc,subdir in enumerate(subproc):
312 self.cmd.update_status('Compiling for process %s/%s. <br> (previous processes already running)' % \
313 (nb_proc+1,nb_tot_proc), level=None)
314
315 subdir = subdir.strip()
316 Pdir = pjoin(self.me_dir, 'SubProcesses',subdir)
317 logger.info(' %s ' % subdir)
318
319
320 if clean:
321 for match in misc.glob('*ajob*', Pdir):
322 if os.path.basename(match)[:4] in ['ajob', 'wait', 'run.', 'done']:
323 os.remove(match)
324 for match in misc.glob('G*', Pdir):
325 if os.path.exists(pjoin(match,'results.dat')):
326 os.remove(pjoin(match, 'results.dat'))
327 if os.path.exists(pjoin(match, 'ftn25')):
328 os.remove(pjoin(match, 'ftn25'))
329
330
331 self.cmd.compile(['gensym'], cwd=Pdir)
332 if not os.path.exists(pjoin(Pdir, 'gensym')):
333 raise Exception('Error make gensym not successful')
334
335
336 p = misc.Popen(['./gensym'], stdout=subprocess.PIPE,
337 stderr=subprocess.STDOUT, cwd=Pdir)
338
339 (stdout, _) = p.communicate(''.encode())
340 stdout = stdout.decode('ascii')
341 if os.path.exists(pjoin(self.me_dir,'error')):
342 files.mv(pjoin(self.me_dir,'error'), pjoin(Pdir,'ajob.no_ps.log'))
343 P_zero_result.append(subdir)
344 continue
345
346 jobs = stdout.split()
347 job_list[Pdir] = jobs
348 try:
349
350 [float(s) for s in jobs]
351 except Exception:
352 logger.debug("unformated string found in gensym. Please check:\n %s" % stdout)
353 done=False
354 job_list[Pdir] = []
355 lines = stdout.split('\n')
356 for l in lines:
357 try:
358 [float(s) for s in l.split()]
359 except:
360 continue
361 else:
362 if done:
363 raise Exception('Parsing error in gensym: %s' % stdout)
364 job_list[Pdir] = l.split()
365 done = True
366 if not done:
367 raise Exception('Parsing error in gensym: %s' % stdout)
368
369 self.cmd.compile(['madevent'], cwd=Pdir)
370 if to_submit:
371 self.submit_to_cluster(job_list)
372 job_list = {}
373
374 return job_list, P_zero_result
375
376 - def resubmit(self, min_precision=1.0, resubmit_zero=False):
377 """collect the result of the current run and relaunch each channel
378 not completed or optionally a completed one with a precision worse than
379 a threshold (and/or the zero result channel)"""
380
381 job_list, P_zero_result = self.launch(to_submit=False, clean=False)
382
383 for P , jobs in dict(job_list).items():
384 misc.sprint(jobs)
385 to_resub = []
386 for job in jobs:
387 if os.path.exists(pjoin(P, 'G%s' % job)) and os.path.exists(pjoin(P, 'G%s' % job, 'results.dat')):
388 one_result = sum_html.OneResult(job)
389 try:
390 one_result.read_results(pjoin(P, 'G%s' % job, 'results.dat'))
391 except:
392 to_resub.append(job)
393 if one_result.xsec == 0:
394 if resubmit_zero:
395 to_resub.append(job)
396 elif max(one_result.xerru, one_result.xerrc)/one_result.xsec > min_precision:
397 to_resub.append(job)
398 else:
399 to_resub.append(job)
400 if to_resub:
401 for G in to_resub:
402 try:
403 shutil.rmtree(pjoin(P, 'G%s' % G))
404 except Exception as error:
405 misc.sprint(error)
406 pass
407 misc.sprint(to_resub)
408 self.submit_to_cluster({P: to_resub})
409
410
411
412
413
414
415
416
417
418
419
421 """ """
422
423 if self.run_card['job_strategy'] > 0:
424 if len(job_list) >1:
425 for path, dirs in job_list.items():
426 self.submit_to_cluster({path:dirs})
427 return
428 path, value = list(job_list.items())[0]
429 nexternal = self.cmd.proc_characteristics['nexternal']
430 current = open(pjoin(path, "nexternal.inc")).read()
431 ext = re.search(r"PARAMETER \(NEXTERNAL=(\d+)\)", current).group(1)
432
433 if self.run_card['job_strategy'] == 2:
434 self.splitted_grid = 2
435 if nexternal == int(ext):
436 to_split = 2
437 else:
438 to_split = 0
439 if hasattr(self, 'splitted_Pdir'):
440 self.splitted_Pdir[path] = to_split
441 else:
442 self.splitted_Pdir = {path: to_split}
443 self.splitted_for_dir = lambda x,y : self.splitted_Pdir[x]
444 elif self.run_card['job_strategy'] == 1:
445 if nexternal == int(ext):
446 combine = 1
447 else:
448 combine = self.combining_job
449 if hasattr(self, 'splitted_Pdir'):
450 self.splitted_Pdir[path] = combine
451 else:
452 self.splitted_Pdir = {path: combine}
453 self.combining_job_for_Pdir = lambda x : self.splitted_Pdir[x]
454
455 if not self.splitted_grid:
456 return self.submit_to_cluster_no_splitting(job_list)
457 elif self.cmd.cluster_mode == 0:
458 return self.submit_to_cluster_no_splitting(job_list)
459 elif self.cmd.cluster_mode == 2 and self.cmd.options['nb_core'] == 1:
460 return self.submit_to_cluster_no_splitting(job_list)
461 else:
462 return self.submit_to_cluster_splitted(job_list)
463
464
466 """submit the survey without the parralelization.
467 This is the old mode which is still usefull in single core"""
468
469
470 self.write_parameter(parralelization=False, Pdirs=list(job_list.keys()))
471
472
473
474 for Pdir, jobs in job_list.items():
475 jobs = list(jobs)
476 i=0
477 while jobs:
478 i+=1
479 to_submit = ['0']
480 for _ in range(self.combining_job_for_Pdir(Pdir)):
481 if jobs:
482 to_submit.append(jobs.pop(0))
483
484 self.cmd.launch_job(pjoin(self.me_dir, 'SubProcesses', 'survey.sh'),
485 argument=to_submit,
486 cwd=pjoin(self.me_dir,'SubProcesses' , Pdir))
487
488
490 """prepare the input_file for submitting the channel"""
491
492
493 if 'SubProcesses' not in Pdir:
494 Pdir = pjoin(self.me_dir, 'SubProcesses', Pdir)
495
496
497 self.splitted_Pdir[(Pdir, G)] = int(nb_job)
498
499
500
501 run_card = self.cmd.run_card
502 options = {'event' : submit_ps,
503 'maxiter': 1,
504 'miniter': 1,
505 'accuracy': self.cmd.opts['accuracy'],
506 'helicity': run_card['nhel_survey'] if 'nhel_survey' in run_card \
507 else run_card['nhel'],
508 'gridmode': -2,
509 'channel' : G
510 }
511
512 Gdir = pjoin(Pdir, 'G%s' % G)
513 self.write_parameter_file(pjoin(Gdir, 'input_app.txt'), options)
514
515
516 assert os.path.exists(pjoin(Gdir, "ftn25"))
517
518
519
520
521 packet = cluster.Packet((Pdir, G, step+1),
522 self.combine_iteration,
523 (Pdir, G, step+1))
524
525 if step ==0:
526 self.lastoffset[(Pdir, G)] = 0
527
528
529 for i in range(int(nb_job)):
530 name = "G%s_%s" % (G,i+1)
531 self.lastoffset[(Pdir, G)] += 1
532 offset = self.lastoffset[(Pdir, G)]
533 self.cmd.launch_job(pjoin(self.me_dir, 'SubProcesses', 'refine_splitted.sh'),
534 argument=[name, 'G%s'%G, offset],
535 cwd= Pdir,
536 packet_member=packet)
537
538
540 """ submit the version of the survey with splitted grid creation
541 """
542
543
544
545
546 for Pdir, jobs in job_list.items():
547 if not jobs:
548 continue
549 if self.splitted_for_dir(Pdir, jobs[0]) <= 1:
550 return self.submit_to_cluster_no_splitting({Pdir:jobs})
551
552 self.write_parameter(parralelization=True, Pdirs=[Pdir])
553
554
555 for job in jobs:
556 packet = cluster.Packet((Pdir, job, 1), self.combine_iteration, (Pdir, job, 1))
557 for i in range(self.splitted_for_dir(Pdir, job)):
558 self.cmd.launch_job(pjoin(self.me_dir, 'SubProcesses', 'survey.sh'),
559 argument=[i+1, job],
560 cwd=pjoin(self.me_dir,'SubProcesses' , Pdir),
561 packet_member=packet)
562
564
565 grid_calculator, cross, error = self.combine_grid(Pdir, G, step)
566
567
568 nb_events = grid_calculator.target_evt
569
570 Gdirs = []
571 for i in range(self.splitted_for_dir(Pdir, G)):
572 path = pjoin(Pdir, "G%s_%s" % (G, i+1))
573 Gdirs.append(path)
574
575
576
577
578
579 need_submit = False
580 if step < self.min_iterations and cross != 0:
581 if step == 1:
582 need_submit = True
583 else:
584 across = self.abscross[(Pdir,G)]/(self.sigma[(Pdir,G)]+1e-99)
585 tot_across = self.get_current_axsec()
586 if across / tot_across < 1e-6:
587 need_submit = False
588 elif error < self.cmd.opts['accuracy'] / 100:
589 need_submit = False
590 else:
591 need_submit = True
592
593 elif step >= self.cmd.opts['iterations']:
594 need_submit = False
595 elif self.cmd.opts['accuracy'] < 0:
596
597 raise Exception("Not Implemented")
598 elif self.abscross[(Pdir,G)] == 0:
599 need_submit = False
600 else:
601 across = self.abscross[(Pdir,G)]/(self.sigma[(Pdir,G)]+1e-99)
602 tot_across = self.get_current_axsec()
603 if across == 0:
604 need_submit = False
605 elif across / tot_across < 1e-5:
606 need_submit = False
607 elif error > self.cmd.opts['accuracy']:
608 need_submit = True
609 else:
610 need_submit = False
611
612
613 if cross:
614 grid_calculator.write_grid_for_submission(Pdir,G,
615 self.splitted_for_dir(Pdir, G),
616 nb_events,mode=self.mode,
617 conservative_factor=5.0)
618
619 xsec_format = '.%ig'%(max(3,int(math.log10(1.0/float(error)))+2)
620 if float(cross)!=0.0 and float(error)!=0.0 else 8)
621 if need_submit:
622 message = "%%s/G%%s is at %%%s +- %%.3g pb. Now submitting iteration #%s."%(xsec_format, step+1)
623 logger.info(message%\
624 (os.path.basename(Pdir), G, float(cross),
625 float(error)*float(cross)))
626 self.resubmit_survey(Pdir,G, Gdirs, step)
627 elif cross:
628 logger.info("Survey finished for %s/G%s at %s"%(
629 os.path.basename(Pdir),G,('%%%s +- %%.3g pb'%xsec_format))%
630 (float(cross), float(error)*float(cross)))
631
632 newGpath = pjoin(self.me_dir,'SubProcesses' , Pdir, 'G%s' % G)
633 if not os.path.exists(newGpath):
634 os.mkdir(newGpath)
635
636
637 files.cp(pjoin(Gdirs[0], 'ftn25'),
638 pjoin(self.me_dir,'SubProcesses' , Pdir, 'G%s' % G, 'ftn26'))
639
640
641 fsock = open(pjoin(newGpath, 'events.lhe'), 'w')
642 for Gdir in Gdirs:
643 fsock.write(open(pjoin(Gdir, 'events.lhe')).read())
644
645
646 files.cp(pjoin(Gdirs[0], 'log.txt'),
647 pjoin(self.me_dir,'SubProcesses' , Pdir, 'G%s' % G))
648
649
650
651 self.write_results(grid_calculator, cross, error, Pdir, G, step)
652 else:
653 logger.info("Survey finished for %s/G%s [0 cross]", os.path.basename(Pdir),G)
654
655 Gdir = pjoin(self.me_dir,'SubProcesses' , Pdir, 'G%s' % G)
656 if not os.path.exists(Gdir):
657 os.mkdir(Gdir)
658
659 files.cp(pjoin(Gdirs[0], 'log.txt'), Gdir)
660
661 self.write_results(grid_calculator, cross, error, Pdir, G, step)
662
663 return 0
664
665 - def combine_grid(self, Pdir, G, step, exclude_sub_jobs=[]):
666 """ exclude_sub_jobs is to remove some of the subjobs if a numerical
667 issue is detected in one of them. Warning is issue when this occurs.
668 """
669
670
671 grid_calculator = combine_grid.grid_information(self.run_card['nhel'])
672
673 for i in range(self.splitted_for_dir(Pdir, G)):
674 if i in exclude_sub_jobs:
675 continue
676 path = pjoin(Pdir, "G%s_%s" % (G, i+1))
677 fsock = misc.mult_try_open(pjoin(path, 'results.dat'))
678 one_result = grid_calculator.add_results_information(fsock)
679 fsock.close()
680 if one_result.axsec == 0:
681 grid_calculator.onefail = True
682 continue
683 fsock = misc.mult_try_open(pjoin(path, 'grid_information'))
684 grid_calculator.add_one_grid_information(fsock)
685 fsock.close()
686 os.remove(pjoin(path, 'results.dat'))
687
688
689
690
691
692
693 cross, across, sigma = grid_calculator.get_cross_section()
694
695
696
697 maxwgt = grid_calculator.get_max_wgt(0.01)
698 if maxwgt:
699 nunwgt = grid_calculator.get_nunwgt(maxwgt)
700
701
702
703
704 apply_instability_security = False
705 rel_contrib = 0.0
706 if (self.__class__ != gensym or step > 1):
707 Pdir_across = 0.0
708 Gdir_across = 0.0
709 for (mPdir,mG) in self.abscross.keys():
710 if mPdir == Pdir:
711 Pdir_across += (self.abscross[(mPdir,mG)]/
712 (self.sigma[(mPdir,mG)]+1e-99))
713 if mG == G:
714 Gdir_across += (self.abscross[(mPdir,mG)]/
715 (self.sigma[(mPdir,mG)]+1e-99))
716 rel_contrib = abs(Gdir_across/(Pdir_across+1e-99))
717 if rel_contrib > (1.0e-8) and \
718 nunwgt < 2 and len(grid_calculator.results) > 1:
719 apply_instability_security = True
720
721 if apply_instability_security:
722
723 th_maxwgt = [(r.th_maxwgt,i) for i,r in enumerate(grid_calculator.results)]
724 th_maxwgt.sort()
725 ratio = th_maxwgt[-1][0]/th_maxwgt[-2][0]
726 if ratio > 1e4:
727 logger.warning(
728 """"One Event with large weight have been found (ratio = %.3g) in channel G%s (with rel.contrib=%.3g).
729 This is likely due to numerical instabilities. The associated job is discarded to recover.
730 For offline investigation, the problematic discarded events are stored in:
731 %s"""%(ratio,G,rel_contrib,pjoin(Pdir,'DiscardedUnstableEvents')))
732 exclude_sub_jobs = list(exclude_sub_jobs)
733 exclude_sub_jobs.append(th_maxwgt[-1][1])
734 grid_calculator.results.run_statistics['skipped_subchannel'] += 1
735
736
737 gPath = pjoin(Pdir, "G%s_%s" % (G, th_maxwgt[-1][1]+1))
738 if os.path.isfile(pjoin(gPath,'events.lhe')):
739 lhe_file = lhe_parser.EventFile(pjoin(gPath,'events.lhe'))
740 discardedPath = pjoin(Pdir,'DiscardedUnstableEvents')
741 if not os.path.exists(discardedPath):
742 os.mkdir(discardedPath)
743 if os.path.isdir(discardedPath):
744
745
746 evtRecord = open(pjoin(discardedPath,'discarded_G%s.dat'%G),'a')
747 lhe_file.seek(0)
748 try:
749 evtRecord.write('\n'+str(max(lhe_file,key=lambda evt:abs(evt.wgt))))
750 except Exception:
751
752 lhe_file.close()
753 evtRecord.write(pjoin(gPath,'events.lhe').read())
754 evtRecord.close()
755
756 return self.combine_grid(Pdir, G, step, exclude_sub_jobs)
757
758
759 if across !=0:
760 if sigma != 0:
761 self.cross[(Pdir,G)] += cross**3/sigma**2
762 self.abscross[(Pdir,G)] += across * cross**2/sigma**2
763 self.sigma[(Pdir,G)] += cross**2/ sigma**2
764 self.chi2[(Pdir,G)] += cross**4/sigma**2
765
766 cross = self.cross[(Pdir,G)]/self.sigma[(Pdir,G)]
767 if step > 1:
768 error = math.sqrt(abs((self.chi2[(Pdir,G)]/cross**2 - \
769 self.sigma[(Pdir,G)])/(step-1))/self.sigma[(Pdir,G)])
770 else:
771 error = sigma/cross
772 else:
773 self.cross[(Pdir,G)] = cross
774 self.abscross[(Pdir,G)] = across
775 self.sigma[(Pdir,G)] = 0
776 self.chi2[(Pdir,G)] = 0
777 cross = self.cross[(Pdir,G)]
778 error = 0
779
780 else:
781 error = 0
782
783 grid_calculator.results.compute_values(update_statistics=True)
784 if (str(os.path.basename(Pdir)), G) in self.run_statistics:
785 self.run_statistics[(str(os.path.basename(Pdir)), G)]\
786 .aggregate_statistics(grid_calculator.results.run_statistics)
787 else:
788 self.run_statistics[(str(os.path.basename(Pdir)), G)] = \
789 grid_calculator.results.run_statistics
790
791 self.warnings_from_statistics(G, grid_calculator.results.run_statistics)
792 stats_msg = grid_calculator.results.run_statistics.nice_output(
793 '/'.join([os.path.basename(Pdir),'G%s'%G]))
794
795 if stats_msg:
796 logger.log(5, stats_msg)
797
798
799 for i in range(self.splitted_for_dir(Pdir, G)):
800 path = pjoin(Pdir, "G%s_%s" % (G, i+1))
801 try:
802 os.remove(pjoin(path, 'grid_information'))
803 except OSError as oneerror:
804 if oneerror.errno != 2:
805 raise
806 return grid_calculator, cross, error
807
809 """Possible warn user for worrying MadLoop stats for this channel."""
810
811 if stats['n_madloop_calls']==0:
812 return
813
814 EPS_fraction = float(stats['exceptional_points'])/stats['n_madloop_calls']
815
816 msg = "Channel %s has encountered a fraction of %.3g\n"+ \
817 "of numerically unstable loop matrix element computations\n"+\
818 "(which could not be rescued using quadruple precision).\n"+\
819 "The results might not be trusted."
820
821 if 0.01 > EPS_fraction > 0.001:
822 logger.warning(msg%(G,EPS_fraction))
823 elif EPS_fraction > 0.01:
824 logger.critical((msg%(G,EPS_fraction)).replace('might', 'can'))
825 raise Exception((msg%(G,EPS_fraction)).replace('might', 'can'))
826
828
829 across = 0
830 for (Pdir,G) in self.abscross:
831 across += self.abscross[(Pdir,G)]/(self.sigma[(Pdir,G)]+1e-99)
832 return across
833
834 - def write_results(self, grid_calculator, cross, error, Pdir, G, step):
835
836
837 if cross == 0:
838 abscross,nw, luminosity = 0, 0, 0
839 wgt, maxit,nunwgt, wgt, nevents = 0,0,0,0,0
840 maxwgt = 0
841 error = 0
842 else:
843 grid_calculator.results.compute_values()
844 abscross = self.abscross[(Pdir,G)]/self.sigma[(Pdir,G)]
845 nw = grid_calculator.results.nw
846 wgt = grid_calculator.results.wgt
847 maxit = step
848 wgt = 0
849 nevents = grid_calculator.results.nevents
850 maxwgt = grid_calculator.get_max_wgt()
851 nunwgt = grid_calculator.get_nunwgt()
852 luminosity = nunwgt/cross
853
854
855 def fstr(nb):
856 data = '%E' % nb
857 nb, power = data.split('E')
858 nb = float(nb) /10
859 power = int(power) + 1
860 return '%.5fE%+03i' %(nb,power)
861 line = '%s %s %s %i %i %i %i %s %s %s %s 0.0 0\n' % \
862 (fstr(cross), fstr(error*cross), fstr(error*cross),
863 nevents, nw, maxit,nunwgt,
864 fstr(luminosity), fstr(wgt), fstr(abscross), fstr(maxwgt))
865
866 fsock = open(pjoin(self.me_dir,'SubProcesses' , Pdir, 'G%s' % G,
867 'results.dat'),'w')
868 fsock.writelines(line)
869 fsock.close()
870
872 """submit the next iteration of the survey"""
873
874
875 run_card = self.cmd.run_card
876 options = {'event' : 2**(step) * self.cmd.opts['points'] / self.splitted_grid,
877 'maxiter': 1,
878 'miniter': 1,
879 'accuracy': self.cmd.opts['accuracy'],
880 'helicity': run_card['nhel_survey'] if 'nhel_survey' in run_card \
881 else run_card['nhel'],
882 'gridmode': -2,
883 'channel' : ''
884 }
885
886 if int(options['helicity']) == 1:
887 options['event'] = options['event'] * 2**(self.cmd.proc_characteristics['nexternal']//3)
888
889 for Gdir in Gdirs:
890 self.write_parameter_file(pjoin(Gdir, 'input_app.txt'), options)
891
892
893
894 packet = cluster.Packet((Pdir, G, step+1), self.combine_iteration, \
895 (Pdir, G, step+1))
896 nb_step = len(Gdirs) * (step+1)
897 for i,subdir in enumerate(Gdirs):
898 subdir = subdir.rsplit('_',1)[1]
899 subdir = int(subdir)
900 offset = nb_step+i+1
901 offset=str(offset)
902 tag = "%s.%s" % (subdir, offset)
903
904 self.cmd.launch_job(pjoin(self.me_dir, 'SubProcesses', 'survey.sh'),
905 argument=[tag, G],
906 cwd=pjoin(self.me_dir,'SubProcesses' , Pdir),
907 packet_member=packet)
908
909
910
911
913 """ """
914
915 template =""" %(event)s %(maxiter)s %(miniter)s !Number of events and max and min iterations
916 %(accuracy)s !Accuracy
917 %(gridmode)s !Grid Adjustment 0=none, 2=adjust
918 1 !Suppress Amplitude 1=yes
919 %(helicity)s !Helicity Sum/event 0=exact
920 %(channel)s """
921 options['event'] = int(options['event'])
922 open(path, 'w').write(template % options)
923
924
925
927 """Write the parameter of the survey run"""
928
929 run_card = self.cmd.run_card
930
931 options = {'event' : self.cmd.opts['points'],
932 'maxiter': self.cmd.opts['iterations'],
933 'miniter': self.min_iterations,
934 'accuracy': self.cmd.opts['accuracy'],
935 'helicity': run_card['nhel_survey'] if 'nhel_survey' in run_card \
936 else run_card['nhel'],
937 'gridmode': 2,
938 'channel': ''
939 }
940
941 if int(options['helicity'])== 1:
942 options['event'] = options['event'] * 2**(self.cmd.proc_characteristics['nexternal']//3)
943
944 if parralelization:
945 options['gridmode'] = -2
946 options['maxiter'] = 1
947 options['miniter'] = 1
948 options['event'] /= self.splitted_grid
949
950 if not Pdirs:
951 Pdirs = self.subproc
952
953 for Pdir in Pdirs:
954 path =pjoin(Pdir, 'input_app.txt')
955 self.write_parameter_file(path, options)
956
960
961
962
963 gen_events_security = 1.2
964 combining_job = 0
965 max_request_event = 1000
966 max_event_in_iter = 5000
967 min_event_in_iter = 1000
968 max_splitting = 130
969 min_iter = 3
970 max_iter = 9
971 keep_grid_for_refine = False
972
973
974 @ staticmethod
977
978
996
997
999
1000 try:
1001 super(gen_ximprove, self).__init__(cmd, opt)
1002 except TypeError:
1003 pass
1004
1005 self.run_statistics = {}
1006 self.cmd = cmd
1007 self.run_card = cmd.run_card
1008 run_card = self.run_card
1009 self.me_dir = cmd.me_dir
1010
1011
1012 self.gridpack = run_card['gridpack']
1013 self.nhel = run_card['nhel']
1014 if "nhel_refine" in run_card:
1015 self.nhel = run_card["nhel_refine"]
1016
1017 if self.run_card['refine_evt_by_job'] != -1:
1018 self.max_request_event = run_card['refine_evt_by_job']
1019
1020
1021
1022 self.gen_events = True
1023 self.parralel = False
1024
1025 self.err_goal = 0.01
1026 self.max_np = 9
1027 self.split_channels = False
1028
1029 self.nreq = 2000
1030 self.iseed = 4321
1031
1032
1033 self.results = 0
1034
1035 if isinstance(opt, dict):
1036 self.configure(opt)
1037 elif isinstance(opt, bannermod.GridpackCard):
1038 self.configure_gridpack(opt)
1039
1042
1056
1057
1078
1080 """not needed but for gridpack --which is not handle here for the moment"""
1081 return
1082
1083
1085 """return the list of channel that need to be improved"""
1086
1087 assert self.err_goal >=1
1088 self.err_goal = int(self.err_goal)
1089
1090 goal_lum = self.err_goal/(self.results.axsec+1e-99)
1091 logger.info('Effective Luminosity %s pb^-1', goal_lum)
1092
1093 all_channels = sum([list(P) for P in self.results],[])
1094 all_channels.sort(key= lambda x:x.get('luminosity'), reverse=True)
1095
1096 to_refine = []
1097 for C in all_channels:
1098 if C.get('axsec') == 0:
1099 continue
1100 if goal_lum/(C.get('luminosity')+1e-99) >= 1 + (self.gen_events_security-1)/2:
1101 logger.debug("channel %s need to improve by %.2f (xsec=%s pb, iter=%s)", C.name, goal_lum/(C.get('luminosity')+1e-99), C.get('xsec'), int(C.get('maxit')))
1102 to_refine.append(C)
1103 elif C.get('xerr') > max(C.get('axsec'),
1104 (1/(100*math.sqrt(self.err_goal)))*all_channels[-1].get('axsec')):
1105 to_refine.append(C)
1106
1107 logger.info('need to improve %s channels' % len(to_refine))
1108 return goal_lum, to_refine
1109
1111 """update the html from this object since it contains all the information"""
1112
1113
1114 run = self.cmd.results.current['run_name']
1115 if not os.path.exists(pjoin(self.cmd.me_dir, 'HTML', run)):
1116 os.mkdir(pjoin(self.cmd.me_dir, 'HTML', run))
1117
1118 unit = self.cmd.results.unit
1119 P_text = ""
1120 if self.results:
1121 Presults = self.results
1122 else:
1123 self.results = sum_html.collect_result(self.cmd, None)
1124 Presults = self.results
1125
1126 for P_comb in Presults:
1127 P_text += P_comb.get_html(run, unit, self.cmd.me_dir)
1128
1129 Presults.write_results_dat(pjoin(self.cmd.me_dir,'SubProcesses', 'results.dat'))
1130
1131 fsock = open(pjoin(self.cmd.me_dir, 'HTML', run, 'results.html'),'w')
1132 fsock.write(sum_html.results_header)
1133 fsock.write('%s <dl>' % Presults.get_html(run, unit, self.cmd.me_dir))
1134 fsock.write('%s </dl></body>' % P_text)
1135
1136 self.cmd.results.add_detail('cross', Presults.xsec)
1137 self.cmd.results.add_detail('error', Presults.xerru)
1138
1139 return Presults.xsec, Presults.xerru
1140
1163
1165
1166 for path in misc.glob(pjoin('*', '*','multijob.dat'), pjoin(self.me_dir, 'SubProcesses')):
1167 open(path,'w').write('0\n')
1168
1170 """ """
1171 if nb_split <=1:
1172 return
1173 f = open(pjoin(self.me_dir, 'SubProcesses', Channel.get('name'), 'multijob.dat'), 'w')
1174 f.write('%i\n' % nb_split)
1175 f.close()
1176
1192
1193
1194
1195 alphabet = "abcdefghijklmnopqrstuvwxyz"
1197 """generate the script in order to generate a given number of event"""
1198
1199
1200
1201 goal_lum, to_refine = self.find_job_for_event()
1202
1203
1204 self.reset_multijob()
1205
1206 jobs = []
1207
1208
1209
1210 if self.combining_job >1:
1211
1212 new_order = []
1213 if self.combining_job % 2 == 0:
1214 for i in range(len(to_refine) //2):
1215 new_order.append(to_refine[i])
1216 new_order.append(to_refine[-i-1])
1217 if len(to_refine) % 2:
1218 new_order.append(to_refine[i+1])
1219 else:
1220 for i in range(len(to_refine) //3):
1221 new_order.append(to_refine[i])
1222 new_order.append(to_refine[-2*i-1])
1223 new_order.append(to_refine[-2*i-2])
1224 if len(to_refine) % 3 == 1:
1225 new_order.append(to_refine[i+1])
1226 elif len(to_refine) % 3 == 2:
1227 new_order.append(to_refine[i+2])
1228
1229 assert set([id(C) for C in to_refine]) == set([id(C) for C in new_order])
1230 to_refine = new_order
1231
1232
1233
1234 for C in to_refine:
1235
1236 needed_event = goal_lum*C.get('axsec')
1237 nb_split = int(max(1,((needed_event-1)// self.max_request_event) +1))
1238 if not self.split_channels:
1239 nb_split = 1
1240 if nb_split > self.max_splitting:
1241 nb_split = self.max_splitting
1242 nb_split=max(1, nb_split)
1243
1244
1245
1246 if C.get('nunwgt') > 0:
1247 nevents = needed_event / nb_split * (C.get('nevents') / C.get('nunwgt'))
1248
1249 nevents = int(nevents / (2**self.min_iter-1))
1250 else:
1251 nevents = self.max_event_in_iter
1252
1253 if nevents < self.min_event_in_iter:
1254 nb_split = int(nb_split * nevents / self.min_event_in_iter) + 1
1255 nevents = self.min_event_in_iter
1256
1257
1258 nevents = max(self.min_event_in_iter, min(self.max_event_in_iter, nevents))
1259 logger.debug("%s : need %s event. Need %s split job of %s points", C.name, needed_event, nb_split, nevents)
1260
1261
1262
1263 self.write_multijob(C, nb_split)
1264
1265 packet = cluster.Packet((C.parent_name, C.name),
1266 combine_runs.CombineRuns,
1267 (pjoin(self.me_dir, 'SubProcesses', C.parent_name)),
1268 {"subproc": C.name, "nb_split":nb_split})
1269
1270
1271
1272 info = {'name': self.cmd.results.current['run_name'],
1273 'script_name': 'unknown',
1274 'directory': C.name,
1275 'P_dir': C.parent_name,
1276 'Ppath': pjoin(self.cmd.me_dir, 'SubProcesses', C.parent_name),
1277 'offset': 1,
1278 'nevents': nevents,
1279 'maxiter': self.max_iter,
1280 'miniter': self.min_iter,
1281 'precision': -goal_lum/nb_split,
1282 'nhel': self.run_card['nhel'],
1283 'channel': C.name.replace('G',''),
1284 'grid_refinment' : 0,
1285 'base_directory': '',
1286 'packet': packet,
1287 }
1288
1289 if nb_split == 1:
1290 jobs.append(info)
1291 else:
1292 for i in range(nb_split):
1293 new_info = dict(info)
1294 new_info['offset'] = i+1
1295 new_info['directory'] += self.alphabet[i % 26] + str((i+1)//26)
1296 if self.keep_grid_for_refine:
1297 new_info['base_directory'] = info['directory']
1298 jobs.append(new_info)
1299
1300 self.create_ajob(pjoin(self.me_dir, 'SubProcesses', 'refine.sh'), jobs)
1301
1302
1303 - def create_ajob(self, template, jobs, write_dir=None):
1304 """create the ajob"""
1305
1306 if not jobs:
1307 return
1308
1309 if not write_dir:
1310 write_dir = pjoin(self.me_dir, 'SubProcesses')
1311
1312
1313 P2job= collections.defaultdict(list)
1314 for j in jobs:
1315 P2job[j['P_dir']].append(j)
1316 if len(P2job) >1:
1317 for P in P2job.values():
1318 self.create_ajob(template, P, write_dir)
1319 return
1320
1321
1322
1323 path = pjoin(write_dir, jobs[0]['P_dir'])
1324
1325 template_text = open(template, 'r').read()
1326
1327
1328 if self.combining_job > 1:
1329 skip1=0
1330 n_channels = len(jobs)
1331 nb_sub = n_channels // self.combining_job
1332 nb_job_in_last = n_channels % self.combining_job
1333 if nb_sub == 0:
1334 nb_sub = 1
1335 nb_job_in_last =0
1336 if nb_job_in_last:
1337 nb_sub +=1
1338 skip1 = self.combining_job - nb_job_in_last
1339 if skip1 > nb_sub:
1340 self.combining_job -=1
1341 return self.create_ajob(template, jobs, write_dir)
1342 combining_job = self.combining_job
1343 else:
1344
1345
1346 skip1=0
1347 combining_job =1
1348 nb_sub = len(jobs)
1349
1350
1351 nb_use = 0
1352 for i in range(nb_sub):
1353 script_number = i+1
1354 if i < skip1:
1355 nb_job = combining_job -1
1356 else:
1357 nb_job = min(combining_job, len(jobs))
1358 fsock = open(pjoin(path, 'ajob%i' % script_number), 'w')
1359 for j in range(nb_use, nb_use + nb_job):
1360 if j> len(jobs):
1361 break
1362 info = jobs[j]
1363 info['script_name'] = 'ajob%i' % script_number
1364 info['keeplog'] = 'false'
1365 if "base_directory" not in info:
1366 info["base_directory"] = "./"
1367 fsock.write(template_text % info)
1368 nb_use += nb_job
1369
1370 fsock.close()
1371 return script_number
1372
1374 """create the ajob to achieve a give precision on the total cross-section"""
1375
1376
1377 assert self.err_goal <=1
1378 xtot = abs(self.results.xsec)
1379 logger.info("Working on precision: %s %%" %(100*self.err_goal))
1380 all_channels = sum([list(P) for P in self.results if P.mfactor],[])
1381 limit = self.err_goal * xtot / len(all_channels)
1382 to_refine = []
1383 rerr = 0
1384 for C in all_channels:
1385 cerr = C.mfactor*(C.xerru + len(all_channels)*C.xerrc)
1386 if cerr > abs(limit):
1387 to_refine.append(C)
1388 else:
1389 rerr += cerr
1390 rerr *=rerr
1391 if not len(to_refine):
1392 return
1393
1394
1395 limit = math.sqrt((self.err_goal * xtot)**2 - rerr/math.sqrt(len(to_refine)))
1396 for C in to_refine[:]:
1397 cerr = C.mfactor*(C.xerru + len(to_refine)*C.xerrc)
1398 if cerr < limit:
1399 to_refine.remove(C)
1400
1401
1402 logger.info('need to improve %s channels' % len(to_refine))
1403
1404
1405 jobs = []
1406
1407
1408
1409 for C in to_refine:
1410
1411
1412 yerr = C.mfactor*(C.xerru+len(to_refine)*C.xerrc)
1413 nevents = 0.2*C.nevents*(yerr/limit)**2
1414
1415 nb_split = int((nevents*(C.nunwgt/C.nevents)/self.max_request_event/ (2**self.min_iter-1))**(2/3))
1416 nb_split = max(nb_split, 1)
1417
1418 if nb_split > self.max_splitting:
1419 nb_split = self.max_splitting
1420
1421 if nb_split >1:
1422 nevents = nevents / nb_split
1423 self.write_multijob(C, nb_split)
1424
1425 nevents = min(self.min_event_in_iter, max(self.max_event_in_iter, nevents))
1426
1427
1428
1429 info = {'name': self.cmd.results.current['run_name'],
1430 'script_name': 'unknown',
1431 'directory': C.name,
1432 'P_dir': C.parent_name,
1433 'Ppath': pjoin(self.cmd.me_dir, 'SubProcesses', C.parent_name),
1434 'offset': 1,
1435 'nevents': nevents,
1436 'maxiter': self.max_iter,
1437 'miniter': self.min_iter,
1438 'precision': yerr/math.sqrt(nb_split)/(C.get('xsec')+ yerr),
1439 'nhel': self.run_card['nhel'],
1440 'channel': C.name.replace('G',''),
1441 'grid_refinment' : 1
1442 }
1443
1444 if nb_split == 1:
1445 jobs.append(info)
1446 else:
1447 for i in range(nb_split):
1448 new_info = dict(info)
1449 new_info['offset'] = i+1
1450 new_info['directory'] += self.alphabet[i % 26] + str((i+1)//26)
1451 jobs.append(new_info)
1452 self.create_ajob(pjoin(self.me_dir, 'SubProcesses', 'refine.sh'), jobs)
1453
1455 """update the html from this object since it contains all the information"""
1456
1457
1458 run = self.cmd.results.current['run_name']
1459 if not os.path.exists(pjoin(self.cmd.me_dir, 'HTML', run)):
1460 os.mkdir(pjoin(self.cmd.me_dir, 'HTML', run))
1461
1462 unit = self.cmd.results.unit
1463 P_text = ""
1464 if self.results:
1465 Presults = self.results
1466 else:
1467 self.results = sum_html.collect_result(self.cmd, None)
1468 Presults = self.results
1469
1470 for P_comb in Presults:
1471 P_text += P_comb.get_html(run, unit, self.cmd.me_dir)
1472
1473 Presults.write_results_dat(pjoin(self.cmd.me_dir,'SubProcesses', 'results.dat'))
1474
1475 fsock = open(pjoin(self.cmd.me_dir, 'HTML', run, 'results.html'),'w')
1476 fsock.write(sum_html.results_header)
1477 fsock.write('%s <dl>' % Presults.get_html(run, unit, self.cmd.me_dir))
1478 fsock.write('%s </dl></body>' % P_text)
1479
1480 self.cmd.results.add_detail('cross', Presults.xsec)
1481 self.cmd.results.add_detail('error', Presults.xerru)
1482
1483 return Presults.xsec, Presults.xerru
1484
1509
1524
1526 """Doing the refine in multicore. Each core handle a couple of PS point."""
1527
1528 nb_ps_by_job = 2000
1529 mode = "refine"
1530 gen_events_security = 1.15
1531
1532
1533
1535
1536 super(gen_ximprove_share, self).__init__(*args, **opts)
1537 self.generated_events = {}
1538 self.splitted_for_dir = lambda x,y : self.splitted_Pdir[(x,y)]
1539
1540
1542 """generate the script in order to generate a given number of event"""
1543
1544
1545
1546 goal_lum, to_refine = self.find_job_for_event()
1547 self.goal_lum = goal_lum
1548
1549
1550 total_ps_points = 0
1551 channel_to_ps_point = []
1552 for C in to_refine:
1553
1554 try:
1555 os.remove(pjoin(self.me_dir, "SubProcesses",C.parent_name, C.name, "events.lhe"))
1556 except:
1557 pass
1558
1559
1560 needed_event = goal_lum*C.get('axsec')
1561 if needed_event == 0:
1562 continue
1563
1564 if C.get('nunwgt') > 0:
1565 nevents = needed_event * (C.get('nevents') / C.get('nunwgt'))
1566
1567 nevents = int(nevents / (2**self.min_iter-1))
1568 else:
1569 nb_split = int(max(1,((needed_event-1)// self.max_request_event) +1))
1570 if not self.split_channels:
1571 nb_split = 1
1572 if nb_split > self.max_splitting:
1573 nb_split = self.max_splitting
1574 nevents = self.max_event_in_iter * self.max_splitting
1575 else:
1576 nevents = self.max_event_in_iter * nb_split
1577
1578 if nevents > self.max_splitting*self.max_event_in_iter:
1579 logger.warning("Channel %s/%s has a very low efficiency of unweighting. Might not be possible to reach target" % \
1580 (C.name, C.parent_name))
1581 nevents = self.max_event_in_iter * self.max_splitting
1582
1583 total_ps_points += nevents
1584 channel_to_ps_point.append((C, nevents))
1585
1586 if self.cmd.options["run_mode"] == 1:
1587 if self.cmd.options["cluster_size"]:
1588 nb_ps_by_job = total_ps_points /int(self.cmd.options["cluster_size"])
1589 else:
1590 nb_ps_by_job = self.nb_ps_by_job
1591 elif self.cmd.options["run_mode"] == 2:
1592 remain = total_ps_points % self.cmd.options["nb_core"]
1593 if remain:
1594 nb_ps_by_job = 1 + (total_ps_points - remain) / self.cmd.options["nb_core"]
1595 else:
1596 nb_ps_by_job = total_ps_points / self.cmd.options["nb_core"]
1597 else:
1598 nb_ps_by_job = self.nb_ps_by_job
1599
1600 nb_ps_by_job = int(max(nb_ps_by_job, 500))
1601
1602 for C, nevents in channel_to_ps_point:
1603 if nevents % nb_ps_by_job:
1604 nb_job = 1 + int(nevents // nb_ps_by_job)
1605 else:
1606 nb_job = int(nevents // nb_ps_by_job)
1607 submit_ps = min(nevents, nb_ps_by_job)
1608 if nb_job == 1:
1609 submit_ps = max(submit_ps, self.min_event_in_iter)
1610 self.create_resubmit_one_iter(C.parent_name, C.name[1:], submit_ps, nb_job, step=0)
1611 needed_event = goal_lum*C.get('xsec')
1612 logger.debug("%s/%s : need %s event. Need %s split job of %s points", C.parent_name, C.name, needed_event, nb_job, submit_ps)
1613
1614
1616
1617 grid_calculator, cross, error = self.combine_grid(Pdir, G, step)
1618
1619
1620 Gdirs = []
1621 for i in range(self.splitted_for_dir(Pdir, G)):
1622 path = pjoin(Pdir, "G%s_%s" % (G, i+1))
1623 Gdirs.append(path)
1624 assert len(grid_calculator.results) == len(Gdirs) == self.splitted_for_dir(Pdir, G)
1625
1626
1627
1628 needed_event = cross * self.goal_lum
1629 if needed_event == 0:
1630 return 0
1631
1632
1633 if self.err_goal >=1:
1634 if needed_event > self.gen_events_security * self.err_goal:
1635 needed_event = int(self.gen_events_security * self.err_goal)
1636
1637 if (Pdir, G) in self.generated_events:
1638 old_nunwgt, old_maxwgt = self.generated_events[(Pdir, G)]
1639 else:
1640 old_nunwgt, old_maxwgt = 0, 0
1641
1642 if old_nunwgt == 0 and os.path.exists(pjoin(Pdir,"G%s" % G, "events.lhe")):
1643
1644 lhe = lhe_parser.EventFile(pjoin(Pdir,"G%s" % G, "events.lhe"))
1645 old_nunwgt = lhe.unweight(None, trunc_error=0.005, log_level=0)
1646 old_maxwgt = lhe.max_wgt
1647
1648
1649
1650 maxwgt = max(grid_calculator.get_max_wgt(), old_maxwgt)
1651 new_evt = grid_calculator.get_nunwgt(maxwgt)
1652 efficiency = new_evt / sum([R.nevents for R in grid_calculator.results])
1653 nunwgt = old_nunwgt * old_maxwgt / maxwgt
1654 nunwgt += new_evt
1655
1656
1657 one_iter_nb_event = max(grid_calculator.get_nunwgt(),1)
1658 drop_previous_iteration = False
1659
1660 n_target_one_iter = (needed_event-one_iter_nb_event) / ( one_iter_nb_event/ sum([R.nevents for R in grid_calculator.results]))
1661 n_target_combined = (needed_event-nunwgt) / efficiency
1662 if n_target_one_iter < n_target_combined:
1663
1664
1665 drop_previous_iteration = True
1666 nunwgt = one_iter_nb_event
1667 maxwgt = grid_calculator.get_max_wgt()
1668 new_evt = nunwgt
1669 efficiency = ( one_iter_nb_event/ sum([R.nevents for R in grid_calculator.results]))
1670
1671 try:
1672 if drop_previous_iteration:
1673 raise IOError
1674 output_file = open(pjoin(Pdir,"G%s" % G, "events.lhe"), 'a')
1675 except IOError:
1676 output_file = open(pjoin(Pdir,"G%s" % G, "events.lhe"), 'w')
1677
1678 misc.call(["cat"] + [pjoin(d, "events.lhe") for d in Gdirs],
1679 stdout=output_file)
1680 output_file.close()
1681
1682
1683 if nunwgt < 0.6 * needed_event and step > self.min_iter:
1684 lhe = lhe_parser.EventFile(output_file.name)
1685 old_nunwgt =nunwgt
1686 nunwgt = lhe.unweight(None, trunc_error=0.01, log_level=0)
1687
1688
1689 self.generated_events[(Pdir, G)] = (nunwgt, maxwgt)
1690
1691
1692
1693 if nunwgt >= int(0.96*needed_event)+1:
1694
1695 logger.info("found enough event for %s/G%s" % (os.path.basename(Pdir), G))
1696 self.write_results(grid_calculator, cross, error, Pdir, G, step, efficiency)
1697 return 0
1698 elif step >= self.max_iter:
1699 logger.debug("fail to find enough event")
1700 self.write_results(grid_calculator, cross, error, Pdir, G, step, efficiency)
1701 return 0
1702
1703 nb_split_before = len(grid_calculator.results)
1704 nevents = grid_calculator.results[0].nevents
1705 if nevents == 0:
1706 nevents = max(g.nevents for g in grid_calculator.results)
1707
1708 need_ps_point = (needed_event - nunwgt)/(efficiency+1e-99)
1709 need_job = need_ps_point // nevents + 1
1710
1711 if step < self.min_iter:
1712
1713 job_at_first_iter = nb_split_before/2**(step-1)
1714 expected_total_job = job_at_first_iter * (2**self.min_iter-1)
1715 done_job = job_at_first_iter * (2**step-1)
1716 expected_remaining_job = expected_total_job - done_job
1717
1718 logger.debug("efficiency status (smaller is better): %s", need_job/expected_remaining_job)
1719
1720 need_job = min(need_job, expected_remaining_job*1.25)
1721
1722 nb_job = (need_job-0.5)//(2**(self.min_iter-step)-1) + 1
1723 nb_job = max(1, nb_job)
1724 grid_calculator.write_grid_for_submission(Pdir,G,
1725 self.splitted_for_dir(Pdir, G), nb_job*nevents ,mode=self.mode,
1726 conservative_factor=self.max_iter)
1727 logger.info("%s/G%s is at %i/%i (%.2g%%) event. Resubmit %i job at iteration %i." \
1728 % (os.path.basename(Pdir), G, int(nunwgt),int(needed_event)+1,
1729 (float(nunwgt)/needed_event)*100.0 if needed_event>0.0 else 0.0,
1730 nb_job, step))
1731 self.create_resubmit_one_iter(Pdir, G, nevents, nb_job, step)
1732
1733
1734 elif step < self.max_iter:
1735 if step + 1 == self.max_iter:
1736 need_job = 1.20 * need_job
1737
1738 nb_job = int(min(need_job, nb_split_before*1.5))
1739 grid_calculator.write_grid_for_submission(Pdir,G,
1740 self.splitted_for_dir(Pdir, G), nb_job*nevents ,mode=self.mode,
1741 conservative_factor=self.max_iter)
1742
1743
1744 logger.info("%s/G%s is at %i/%i ('%.2g%%') event. Resubmit %i job at iteration %i." \
1745 % (os.path.basename(Pdir), G, int(nunwgt),int(needed_event)+1,
1746 (float(nunwgt)/needed_event)*100.0 if needed_event>0.0 else 0.0,
1747 nb_job, step))
1748 self.create_resubmit_one_iter(Pdir, G, nevents, nb_job, step)
1749
1750
1751
1752 return 0
1753
1754
1755 - def write_results(self, grid_calculator, cross, error, Pdir, G, step, efficiency):
1756
1757
1758 if cross == 0:
1759 abscross,nw, luminosity = 0, 0, 0
1760 wgt, maxit,nunwgt, wgt, nevents = 0,0,0,0,0
1761 error = 0
1762 else:
1763 grid_calculator.results.compute_values()
1764 abscross = self.abscross[(Pdir,G)]/self.sigma[(Pdir,G)]
1765 nunwgt, wgt = self.generated_events[(Pdir, G)]
1766 nw = int(nunwgt / efficiency)
1767 nunwgt = int(nunwgt)
1768 maxit = step
1769 nevents = nunwgt
1770
1771 luminosity = nunwgt/cross
1772
1773
1774 def fstr(nb):
1775 data = '%E' % nb
1776 nb, power = data.split('E')
1777 nb = float(nb) /10
1778 power = int(power) + 1
1779 return '%.5fE%+03i' %(nb,power)
1780 line = '%s %s %s %i %i %i %i %s %s %s 0.0 0.0 0\n' % \
1781 (fstr(cross), fstr(error*cross), fstr(error*cross),
1782 nevents, nw, maxit,nunwgt,
1783 fstr(luminosity), fstr(wgt), fstr(abscross))
1784
1785 fsock = open(pjoin(self.me_dir,'SubProcesses' , Pdir, 'G%s' % G,
1786 'results.dat'),'w')
1787 fsock.writelines(line)
1788 fsock.close()
1789
1794
1795 min_iter = 1
1796 max_iter = 13
1797 max_request_event = 1e12
1798 max_event_in_iter = 4000
1799 min_event_in_iter = 500
1800 combining_job = sys.maxsize
1801 gen_events_security = 1.00
1802
1807
1809
1810 self.ngran = -1
1811 self.gscalefact = {}
1812 self.readonly = False
1813 if 'ngran' in opts:
1814 self.gran = opts['ngran']
1815
1816 if 'readonly' in opts:
1817 self.readonly = opts['readonly']
1818 super(gen_ximprove_gridpack,self).__init__(*args, **opts)
1819 if self.ngran == -1:
1820 self.ngran = 1
1821
1823 """return the list of channel that need to be improved"""
1824 import random
1825
1826 assert self.err_goal >=1
1827 self.err_goal = int(self.err_goal)
1828 self.gscalefact = {}
1829
1830 xtot = self.results.axsec
1831 goal_lum = self.err_goal/(xtot+1e-99)
1832
1833
1834 all_channels = sum([list(P) for P in self.results],[])
1835 all_channels.sort(key=lambda x : x.get('luminosity'), reverse=True)
1836
1837 to_refine = []
1838 for C in all_channels:
1839 tag = C.get('name')
1840 self.gscalefact[tag] = 0
1841 R = random.random()
1842 if C.get('axsec') == 0:
1843 continue
1844 if (goal_lum * C.get('axsec') < R*self.ngran ):
1845 continue
1846 self.gscalefact[tag] = max(1, 1/(goal_lum * C.get('axsec')/ self.ngran))
1847
1848 logger.debug('request events for ', C.get('name'), 'cross=',
1849 C.get('axsec'), 'needed events = ', goal_lum * C.get('axsec'))
1850 to_refine.append(C)
1851
1852 logger.info('need to improve %s channels' % len(to_refine))
1853 return goal_lum, to_refine
1854
1856 """generate the script in order to generate a given number of event"""
1857
1858
1859
1860 goal_lum, to_refine = self.find_job_for_event()
1861
1862 jobs = []
1863
1864
1865
1866 for C in to_refine:
1867
1868 needed_event = max(goal_lum*C.get('axsec'), self.ngran)
1869 nb_split = 1
1870
1871
1872 if C.get('nunwgt') > 0:
1873 nevents = needed_event / nb_split * (C.get('nevents') / C.get('nunwgt'))
1874
1875 nevents = int(nevents / (2**self.min_iter-1))
1876 else:
1877 nevents = self.max_event_in_iter
1878
1879 if nevents < self.min_event_in_iter:
1880 nevents = self.min_event_in_iter
1881
1882
1883 nevents = max(self.min_event_in_iter, min(self.max_event_in_iter, nevents))
1884 logger.debug("%s : need %s event. Need %s split job of %s points", C.name, needed_event, nb_split, nevents)
1885
1886
1887
1888 info = {'name': self.cmd.results.current['run_name'],
1889 'script_name': 'unknown',
1890 'directory': C.name,
1891 'P_dir': os.path.basename(C.parent_name),
1892 'offset': 1,
1893 'Ppath': pjoin(self.cmd.me_dir, 'SubProcesses', C.parent_name),
1894 'nevents': nevents,
1895 'maxiter': self.max_iter,
1896 'miniter': self.min_iter,
1897 'precision': -1*int(needed_event)/C.get('axsec'),
1898 'requested_event': needed_event,
1899 'nhel': self.run_card['nhel'],
1900 'channel': C.name.replace('G',''),
1901 'grid_refinment' : 0,
1902 'base_directory': '',
1903 'packet': None,
1904 }
1905
1906
1907 jobs.append(info)
1908
1909
1910 write_dir = '.' if self.readonly else None
1911 self.create_ajob(pjoin(self.me_dir, 'SubProcesses', 'refine.sh'), jobs, write_dir)
1912
1913 done = []
1914 for j in jobs:
1915 if j['P_dir'] in done:
1916 continue
1917 done.append(j['P_dir'])
1918
1919 pwd = pjoin(os.getcwd(),j['P_dir']) if self.readonly else pjoin(self.me_dir, 'SubProcesses', j['P_dir'])
1920 exe = pjoin(pwd, 'ajob1')
1921 st = os.stat(exe)
1922 os.chmod(exe, st.st_mode | stat.S_IEXEC)
1923
1924
1925 cluster.onecore.launch_and_wait(exe, cwd=pwd, packet_member=j['packet'])
1926 write_dir = '.' if self.readonly else pjoin(self.me_dir, 'SubProcesses')
1927
1928 self.check_events(goal_lum, to_refine, jobs, write_dir)
1929
1931 """check that we get the number of requested events if not resubmit."""
1932
1933 new_jobs = []
1934
1935 for C, job_info in zip(to_refine, jobs):
1936 P = job_info['P_dir']
1937 G = job_info['channel']
1938 axsec = C.get('axsec')
1939 requested_events= job_info['requested_event']
1940
1941
1942 new_results = sum_html.OneResult((P,G))
1943 new_results.read_results(pjoin(Sdir,P, 'G%s'%G, 'results.dat'))
1944
1945
1946 if new_results.get('nunwgt') < requested_events:
1947 pwd = pjoin(os.getcwd(),job_info['P_dir'],'G%s'%G) if self.readonly else \
1948 pjoin(self.me_dir, 'SubProcesses', job_info['P_dir'],'G%s'%G)
1949 job_info['requested_event'] -= new_results.get('nunwgt')
1950 job_info['precision'] -= -1*job_info['requested_event']/axsec
1951 job_info['offset'] += 1
1952 new_jobs.append(job_info)
1953 files.mv(pjoin(pwd, 'events.lhe'), pjoin(pwd, 'events.lhe.previous'))
1954
1955 if new_jobs:
1956 self.create_ajob(pjoin(self.me_dir, 'SubProcesses', 'refine.sh'), new_jobs, Sdir)
1957
1958 done = []
1959 for j in new_jobs:
1960 if j['P_dir'] in done:
1961 continue
1962 G = j['channel']
1963
1964 pwd = pjoin(os.getcwd(),j['P_dir']) if self.readonly \
1965 else pjoin(self.me_dir, 'SubProcesses', j['P_dir'])
1966 exe = pjoin(pwd, 'ajob1')
1967 st = os.stat(exe)
1968 os.chmod(exe, st.st_mode | stat.S_IEXEC)
1969
1970
1971 cluster.onecore.launch_and_wait(exe, cwd=pwd, packet_member=j['packet'])
1972 pwd = pjoin(pwd, 'G%s'%G)
1973
1974 files.put_at_end(pjoin(pwd, 'events.lhe'),pjoin(pwd, 'events.lhe.previous'))
1975
1976 return self.check_events(goal_lum, to_refine, new_jobs, Sdir)
1977