Merge lp:~maddm/maddm/no_numpy_scipy into lp:~maddm/maddm/3.0.1

Proposed by Olivier Mattelaer
Status: Merged
Merged at revision: 15
Proposed branch: lp:~maddm/maddm/no_numpy_scipy
Merge into: lp:~maddm/maddm/3.0.1
Diff against target: 376 lines (+125/-37)
3 files modified
__init__.py (+1/-1)
maddm_interface.py (+14/-2)
maddm_run_interface.py (+110/-34)
To merge this branch: bzr merge lp:~maddm/maddm/no_numpy_scipy
Reviewer Review Type Date Requested Status
Olivier Mattelaer Approve
Federico Ambrogi Pending
Review via email: mp+345141@code.launchpad.net

Commit message

Avoid direct crash if numpy/scipy are not present on the system.
-> forbids indirect detection but allows relic density computation and direct detection.

This allows to have maddm v2 options still working in version 3 even if numpy/scipy are not available.

To post a comment you must log in.
lp:~maddm/maddm/no_numpy_scipy updated
18. By olivier-mattelaer

some issue created by the change

19. By olivier-mattelaer

additional fix

20. By Federico Ambrogi <email address hidden>

Formatted string as as python 2.6

Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :

mail from federico:

Hi Olivier,

I dowloaded the branch and replaced it inside the PLUGIN directory, so I don’t know how to test what is the behaviour when you try to install maddm without it numpy,scipy.
But it works i.e. I can run maddm without numpy and scipy. Here my comments:

1) If I look at your modified script I read:

"PPC4DMID module requires scipy to be working. Please install those python module. (they are not present)")

but it should be something like:

“Fermi-LAT limit calculation for indirect detection requires numpy and scipy. Please install the missing modules…)

I.e. it is not related to PPPC but in general to Fermi limits.

2) If I don’t have numpy and scipy, why does it compute the diagrams for indirect detection if ask for "add indirect_detection” ?
If the indirect detection module must be switched off, should the whole module be disabled?
I think a warning message should appear when the user tries to add the indirect detection calculation, and then maddm should not calculate anything.

3)
Then I noticed that when I try to switch on the indirect detection, it does not happen of course as we want, but maddm does not print anything on screen,
i.e. if I keen on typing 3 to select the option for indirect detection, on the screen nothing happens.
It should warn that “Indirect detection not available since numpy and scipy are missing…”

review: Needs Fixing
Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote :

Hi,

Thanks for the review:

1) Done.

2) I add a warning and a question asking if he wants to generate the diagram anyway (with default to stop)

3) Ok a warning will be displayed but this is not possible in 2.6.2 and will need to wait 2.6.3 but the code is ready for 2.6.3 already.

Thanks,

Olivier

If nobody object, I will release this code this afternoon.

review: Approve
lp:~maddm/maddm/no_numpy_scipy updated
21. By olivier-mattelaer

change according to federico review

22. By olivier-mattelaer

remove some printout

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '__init__.py'
2--- __init__.py 2018-03-30 22:19:49 +0000
3+++ __init__.py 2018-05-16 14:22:05 +0000
4@@ -16,6 +16,6 @@
5 new_reweight = {'indirect': MGoutput.Indirect_Reweight}
6
7 ## The test/code have been validated up to this version
8-latest_validated_version = (2,6,2)
9+latest_validated_version = (2,6,3)
10 minimal_mg5amcnlo_version = (2,6,2)
11 maximal_mg5amcnlo_version = (1000,1000,1000)
12
13=== modified file 'maddm_interface.py'
14--- maddm_interface.py 2018-04-29 20:55:19 +0000
15+++ maddm_interface.py 2018-05-16 14:22:05 +0000
16@@ -115,6 +115,11 @@
17 def post_install_PPPC4DMID(self):
18 if os.path.exists(pjoin(MG5DIR, 'PPPC4DMID')):
19 self.options['pppc4dmid_path'] = pjoin(MG5DIR, 'PPPC4DMID')
20+
21+ if not maddm_run_interface.HAS_SCIPY:
22+ logger.critical("Fermi-LAT limit calculation for indirect detection requires numpy and scipy. Please install the missing modules.")
23+ logger.info("you can try to use \"pip install scipy\"")
24+
25 return
26
27 def set_configuration(self, config_path=None, final=True, **opts):
28@@ -980,7 +985,7 @@
29 has_diagram = True
30 return has_diagram
31
32- def generate_indirect(self, argument):
33+ def generate_indirect(self, argument, user=True):
34 """User level function which performs indirect detection functions
35 Generates the DM DM > X where X is anything user specified.
36 Also works for loop induced processes as well as NLO-QCD.
37@@ -988,6 +993,13 @@
38 related to syntax: generate indirect a g / n3
39 """
40
41+ if not maddm_run_interface.HAS_NUMPY and user:
42+ logger.warning("numpy module not detected on your machine. \n"+
43+ "Running indirect detection will not be possible as long as numpy is not installed (try 'pip install numpy')"
44+ )
45+ ans = self.ask("Do you want to generate the diagrams anyway?", 'n', ['y','n'])
46+ if ans == 'n':
47+ return
48
49 self.install_indirect()
50
51@@ -1042,7 +1054,7 @@
52
53 for final_state in final_states:
54 try:
55- self.exec_cmd('add indirect %s --noloop' % final_state,postcmd=False)
56+ self.generate_indirect([final_state, '--noloop'], user=False)
57 except diagram_generation.NoDiagramException:
58 continue
59 logger.info('no diagram for %s' % final_state)
60
61=== modified file 'maddm_run_interface.py'
62--- maddm_run_interface.py 2018-04-29 20:53:38 +0000
63+++ maddm_run_interface.py 2018-05-16 14:22:05 +0000
64@@ -10,12 +10,7 @@
65 import stat
66 import shutil
67
68-from scipy.interpolate import interp1d
69-from scipy.integrate import quad
70-from scipy.optimize import minimize_scalar
71-from scipy.optimize import brute
72-from scipy.optimize import fmin
73-from scipy.special import gammainc
74+
75
76 import MGoutput
77 from madgraph import MadGraph5Error
78@@ -34,18 +29,37 @@
79
80 #import darkmatter as darkmatter
81
82-import numpy as np
83+logger = logging.getLogger('madgraph.plugin.maddm')
84
85 try:
86 import pymultinest
87-except:
88- print('WARNING: Multinest module not found! All multinest parameter scanning features will be disabled.')
89-
90-
91-#import types
92+except ImportError:
93+ pass
94+
95+try:
96+ from scipy.interpolate import interp1d
97+ from scipy.integrate import quad
98+ from scipy.optimize import brute, fmin, minimize_scalar
99+ from scipy.special import gammainc
100+except ImportError, error:
101+ print error
102+ logger.warning('scipy module not found! Some Indirect detection features will be disabled.')
103+ HAS_SCIPY = False
104+else:
105+ HAS_SCIPY = True
106+
107+try:
108+ import numpy as np
109+except ImportError:
110+ logger.warning('numpy module not found! Indirect detection features will be disabled.')
111+ HAS_NUMPY = False
112+else:
113+ HAS_NUMPY = True
114+
115+class ModuleMissing(Exception): pass
116
117 pjoin = os.path.join
118-logger = logging.getLogger('madgraph.plugin.maddm')
119+
120 logger_tuto = logging.getLogger('tutorial_plugin')
121 #logger.setLevel(10) #level 20 = INFO
122
123@@ -111,14 +125,18 @@
124 self._sigma_ID[item] = -1.0
125 self._sigma_ID_width[item] = -1.0
126
127- self.load_constraints()
128+ if HAS_NUMPY:
129+ self.load_constraints()
130+
131
132 logger.info('Loaded experimental constraints. To change, use the set command')
133 logger.info('Omega h^2 = %.4e +- %.4e' %(self._oh2_planck, self._oh2_planck_width))
134- logger.info('Spin Independent cross section: %s' % self._dd_si_limit_file)
135- logger.info('Spin Dependent cross section (p): %s' % self._dd_sd_proton_limit_file)
136- logger.info('Spin Dependent cross section (n): %s' % self._dd_sd_neutron_limit_file)
137-
138+ if HAS_NUMPY:
139+ logger.info('Spin Independent cross section: %s' % self._dd_si_limit_file)
140+ logger.info('Spin Dependent cross section (p): %s' % self._dd_sd_proton_limit_file)
141+ logger.info('Spin Dependent cross section (n): %s' % self._dd_sd_neutron_limit_file)
142+ else:
143+ logger.info('Spin (in)dependent not available due to the missing python module: numpy')
144 # for chan in self._allowed_final_states:
145 # logger.info('Indirect Detection cross section for final state %s at velocity %.2e: %s'\
146 # % (chan, self._id_limit_vel[chan] ,self._id_limit_file[chan]))
147@@ -146,6 +164,10 @@
148
149 #Returns a value in cm^2
150 def SI_max(self, mdm):
151+ if not HAS_NUMPY:
152+ logger.warning("missing numpy module for SI limit")
153+ return __infty__
154+
155 if (mdm < np.min(self._dd_si_limit_mDM) or mdm > np.max(self._dd_si_limit_mDM)):
156 logger.warning('Dark matter mass value '+str(mdm)+' is outside the range of SI limit')
157 return __infty__
158@@ -154,6 +176,10 @@
159
160 #Returns a value in cm^2
161 def SD_max(self,mdm, nucleon):
162+ if not HAS_NUMPY:
163+ logger.warning("missing numpy module for SD limit")
164+ return __infty__
165+
166 if nucleon not in ['n','p']:
167 logger.error('nucleon can only be p or n')
168 return __infty__
169@@ -173,6 +199,9 @@
170
171 #Returns a value in cm^3/s
172 def ID_max(self,mdm, channel):
173+ if not HAS_NUMPY:
174+ logger.warning("missing numpy module for ID limit")
175+ return __infty__
176 if (mdm < np.min(self._id_limit_mdm[channel]) or mdm > np.max(self._id_limit_mdm[channel])):
177 logger.warning('Dark matter mass value %.2e for channel %s is outside the range of ID limit' % (mdm, channel))
178 return __infty__
179@@ -267,6 +296,10 @@
180 # this function extracts the values of the spectra interpolated linearly between two values mdm_1 and mdm_2
181 # mdm is the DM candidate mass, spectrum is gammas, positron etc, channel is the SM annihilation e.g. bbar, hh etc.
182 def interpolate_spectra(self, sp_dic, mdm = '', spectrum = '' , channel = '' , earth = False , prof = 'Ein' , prop = 'MED' , halo_func = 'MF1'):
183+
184+ if not HAS_SCIPY:
185+ raise ModuleMissing('scipy module is required for this functionality.')
186+
187 M = sp_dic['Masses']
188 dm_min = max([m for m in M if m <= mdm]) # extracting lower mass limit to interpolate from
189 dm_max = min([m for m in M if m >= mdm]) # extracting upper mass limit to interpolate from
190@@ -306,7 +339,8 @@
191 self.dSph_ll_files_path = pjoin(MDMDIR, 'Fermi_Data', 'likelihoods')
192 self.dwarves_list = ['coma_berenices', 'draco', 'segue_1', 'ursa_major_II', 'ursa_minor', 'reticulum_II' ] # dSphs with the 6 highest Jfactors
193 self.dwarveslist_all = self.extract_dwarveslist()
194- self.dw_in = self.dw_dic()
195+ if HAS_NUMPY and HAS_SCIPY:
196+ self.dw_in = self.dw_dic()
197 self.ll_tot = ''
198
199 # This function reads the list of dwarves from the Jfactor.dat file
200@@ -363,6 +397,10 @@
201 def eflux(self,spectrum, emin=1e2, emax=1e5, quiet=False):
202 """ Integrate a generic spectrum, multiplied by E, to get the energy flux.
203 """
204+
205+ if not HAS_SCIPY:
206+ raise ModuleMissing('scipy module is required for this functionality.')
207+
208 espectrum = lambda e: spectrum(e)*e
209 tol = min(espectrum(emin),espectrum(emax))*1e-10
210 try:
211@@ -373,6 +411,9 @@
212
213 def marg_like_dw(self,dw_in_i,pred,marginalize):
214
215+ if not HAS_SCIPY:
216+ raise ModuleMissing('scipy module is required for this functionality.')
217+
218 j0, nBin = self.j0 , self.nBin
219
220 j,jerr,like_inter = dw_in_i['Jfac'], dw_in_i['Jfac_err'], dw_in_i['likelihood']
221@@ -403,6 +444,9 @@
222
223 def res_tot_dw(self,pred,marginalize):
224
225+ if not HAS_SCIPY:
226+ raise ModuleMissing('scipy module is required for this functionality.')
227+
228 dw_in = self.dw_in
229 ll_tot = 0.0
230 ll_null = 0.0
231@@ -436,7 +480,20 @@
232 # otherwise it calculates the likelihood and p-value for the given point
233 def Fermi_sigmav_lim(self, mDM, x = '' , dndlogx = '' , marginalize = True, sigmav_th = False , maj_dirac='', \
234 sigmavmin=1e-35, sigmavmax=1e-15, step_size_scaling=1.0, cl_val = 0.95):
235-
236+ stop = False
237+ if not HAS_NUMPY:
238+ logger.warning("Fermi limit ignored due to missing numpy module")
239+ stop = True
240+ if not HAS_SCIPY:
241+ logger.warning("Fermi limit ignored due to missing scipy module")
242+ stop = True
243+
244+ if stop:
245+ if sigmav_th:
246+ return -1, -1
247+ else:
248+ return -1
249+
250 np.seterr(divide='ignore', invalid='ignore') # Keep numpy from complaining about dN/dE = 0...
251 j0 , nBin = self.j0 , self.nBin
252
253@@ -1226,8 +1283,8 @@
254 sp_name = sp + '_spectrum_pythia8.dat'
255 out_dir = pjoin(self.dir_path,'Indirect', 'Events', run_name, sp_name )
256 if sp == 'gammas': # x values are the same for all the spectra
257- x = np.loadtxt(out_dir , unpack = True )[0]
258- self.Spectra.spectra['x'] = [ np.power(10,num) for num in x] # from log[10,x] to x
259+ x = np.loadtxt(out_dir , unpack = True )[0]
260+ self.Spectra.spectra['x'] = [ np.power(10,num) for num in x] # from log[10,x] to x
261 self.Spectra.spectra[sp] = np.loadtxt(out_dir , unpack = True )[1].tolist()
262
263
264@@ -1239,6 +1296,10 @@
265 logger.error('PPPC4DMID not installed. Please install by typing "install PPPC4DMID".')
266 return
267
268+ if not HAS_SCIPY:
269+ logger.error('using PPPC4DMID requires scipy module. Please install it (for example with "pip install scipy")')
270+ return
271+
272 if 'PPPC4DMID' in self.maddm_card['indirect_flux_source_method'] or 'inclusive' in self.maddm_card['sigmav_method']:
273 if self.Spectra.check_mass(mdm):
274 if '_ew' in self.maddm_card['indirect_flux_source_method']:
275@@ -1627,8 +1688,8 @@
276
277 if self.mode['relic']:
278 logger.info("\n***** Relic Density")
279-
280- logger.info( self.form_s('Relic Density') + '= ' + self.form_n(omega ) + ' ' + pass_relic )
281+ print 'OMEGA IS ', omega
282+ logger.info( self.form_s('Relic Density') + '= ' + self.form_n(omega) + ' ' + pass_relic )
283 logger.info( self.form_s('x_f' ) + '= ' + self.form_s(self.form_n(x_f ) ) )
284 logger.info( self.form_s('sigmav(xf)' ) + '= ' + self.form_s(self.form_n(sigma_xf ) ) )
285 logger.info( self.form_s('xsi' ) + '= ' + self.form_s(self.form_n(xsi ) ) )
286@@ -1916,11 +1977,11 @@
287 th_mess = self.det_message_screen(sig_th , ul)
288 line = self.form_s(what) + self.form_s('Thermal = '+ self.form_n(sig_th)) + ' ' + self.form_s(th_mess)
289 line = line + '\t' + self.form_s('All DM = ' + self.form_n(sig_alldm) ) + ' ' + self.form_s(alldm_mess)
290- line = line + '\t' + '{:16}'.format(exp+' ul') + ' = ' + self.form_n(ul)
291+ line = line + '\t' + '{0:16}'.format(exp+' ul') + ' = ' + self.form_n(ul)
292
293 else:
294 line = self.form_s(what) + self.form_s('All DM = ' + self.form_n(sig_alldm) ) + ' ' + self.form_s(alldm_mess)
295- line = line + '\t' + '{:16}'.format(exp+' ul') + ' = ' + self.form_n(ul)
296+ line = line + '\t' + '{0:16}'.format(exp+' ul') + ' = ' + self.form_n(ul)
297
298 elif not direc and no_lim:
299
300@@ -1941,11 +2002,11 @@
301 # os.symlink(pjoin(self.dir_path,'Indirect','Events'), pjoin(self.dir_path, 'output' , 'Output_Indirect') )
302
303 def form_s(stringa):
304- formatted = '{:22}'.format(stringa)
305+ formatted = '{0:22}'.format(stringa)
306 return formatted
307
308 def form_n(num):
309- formatted = '{:3.2e}'.format(num)
310+ formatted = '{0:3.2e}'.format(num)
311 return formatted
312
313 out = open(pjoin(self.dir_path, 'output', point, 'MadDM_results.txt'),'w')
314@@ -2063,10 +2124,10 @@
315 elif n1 <= 0 : return 'No Theory Prediction'
316
317 def form_s(self,stringa):
318- formatted = '{:20}'.format(stringa)
319+ formatted = '{0:20}'.format(stringa)
320 return formatted
321 def form_n(self,num):
322- formatted = '{:3.2e}'.format(num)
323+ formatted = '{0:3.2e}'.format(num)
324 return formatted
325
326 def ask_run_configuration(self, mode=None, force=False):
327@@ -2356,11 +2417,23 @@
328 def set_default_indirect(self):
329 """set the default value for relic="""
330
331- if self.availmode['has_indirect_detection']:
332+ if not HAS_NUMPY:
333+ self.switch['indirect'] = 'Not Avail. (numpy missing)'
334+ elif self.availmode['has_indirect_detection']:
335 self.switch['indirect'] = 'sigmav'
336 else:
337 self.switch['indirect'] = 'Not Avail.'
338
339+ def print_options_indirect(self):
340+ """print statement for the options"""
341+
342+ if not self.availmode['has_indirect_detection']:
343+ return "Please install module"
344+ elif not HAS_NUMPY:
345+ return "numpy not available"
346+ else:
347+ return self.print_options('indirect', keep_default=True)
348+
349 def get_allowed_indirect(self):
350 """Specify which parameter are allowed for relic="""
351
352@@ -2368,10 +2441,13 @@
353 if hasattr(self, 'allowed_indirect'):
354 return getattr(self, 'allowed_indirect')
355
356- if self.availmode['has_indirect_detection']:
357+ if not HAS_NUMPY:
358+ self.allowed_indirect = ['OFF']
359+ elif self.availmode['has_indirect_detection']:
360 self.allowed_indirect = ['OFF', 'sigmav', 'flux_source', 'flux_earth']
361 else:
362- return []
363+ self.allowed_indirect = []
364+ return self.allowed_indirect
365
366
367 def check_value_indirect(self, value):
368@@ -2599,7 +2675,7 @@
369
370 try:
371 return cmd.ControlSwitch.default(self, line, raise_error=True)
372- except cmd.NotValidInput:
373+ except cmd.NotValidInput, error:
374 return common_run.AskforEditCard.default(self, line)
375
376 def trigger_7(self, line):

Subscribers

People subscribed via source and target branches

to all changes: