Merge lp:~maddm/maddm/no_numpy_scipy into lp:~maddm/maddm/3.0.1
- no_numpy_scipy
- Merge into 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 |
Related bugs: |
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.
Description of the change
To post a comment you must log in.
lp:~maddm/maddm/no_numpy_scipy
updated
Revision history for this message
Olivier Mattelaer (olivier-mattelaer) wrote : | # |
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
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): |
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…”