33from datetime import datetime
44from decimal import Decimal
55from os .path import join
6+ from multiprocessing import Pool
7+ import copy
68
79try :
810 from scipy .optimize import minimize
@@ -218,9 +220,33 @@ def from_range(N, intervals):
218220class InvalidInterval (McRunException ):
219221 pass
220222
223+ def _simulate_point (args ):
224+ i , point , intervals , mcstas_config , mcstas_dir = args
225+
226+ from shutil import copyfile
227+ from os .path import join
228+
229+ # Make a new instance of McStas and configure it
230+ mcstas = copy .deepcopy (mcstas_config ) # You need to define a way to deepcopy or clone your mcstas object
231+ par_values = []
232+
233+ for key in intervals :
234+ mcstas .set_parameter (key , point [key ])
235+ par_values .append (point [key ])
236+
237+ current_dir = f'{ mcstas_dir } /{ i } '
238+ mcstas .run (pipe = False , extra_opts = {'dir' : current_dir })
239+ detectors = mcsimdetectors (current_dir )
240+
241+ result = {
242+ 'index' : i ,
243+ 'params' : par_values ,
244+ 'detectors' : detectors
245+ }
246+ return result
221247
222248class Scanner :
223- """ Perform a series of simulation steps along a given set of points """
249+ """ Perform a series of simulation steps along a given set of points"""
224250 def __init__ (self , mcstas , intervals ):
225251 self .mcstas = mcstas
226252 self .intervals = intervals
@@ -244,6 +270,7 @@ def run(self):
244270 mcstas_dir = self .mcstas .options .dir
245271 if mcstas_dir == '' :
246272 mcstas_dir = '.'
273+
247274
248275 with open (self .outfile , 'w' ) as outfile :
249276 for i , point in enumerate (self .points ):
@@ -278,6 +305,67 @@ def run(self):
278305 outfile .flush ()
279306
280307
308+ class Scanner_split :
309+ """ Perform a series of simulation steps along a given set of points,
310+ Where each simulation is controlled by its own thread. """
311+ def __init__ (self , mcstas , intervals , nb_cpu ):
312+ self .mcstas = mcstas
313+ self .intervals = intervals
314+ self .points = None
315+ self .nb_cpu = nb_cpu
316+ self .outfile = mcstas .options .optimise_file
317+ self .simfile = join (mcstas .options .dir , 'mccode.sim' )
318+
319+ def set_points (self , points ):
320+ self .points = points
321+
322+ def set_outfile (self , path ):
323+ self .outfile = path
324+
325+ def run (self ):
326+ LOG .info ('Running Scanner split, result file is "%s"' % self .outfile )
327+
328+ if len (self .intervals ) == 0 :
329+ raise InvalidInterval ('No interval range specified' )
330+
331+ mcstas_dir = self .mcstas .options .dir or '.'
332+
333+ # Prepare data to pass into processes
334+ args_list = [
335+ (i , point , self .intervals , self .mcstas , mcstas_dir )
336+ for i , point in enumerate (self .points )
337+ ]
338+
339+ with Pool (processes = self .nb_cpu ) as pool :
340+ results = pool .map (_simulate_point , args_list )
341+
342+ # Sort results to preserve order
343+ results .sort (key = lambda r : r ['index' ])
344+
345+ with open (self .outfile , 'w' ) as outfile :
346+ wrote_headers = False
347+ for result in results :
348+ if result ['detectors' ] is None :
349+ continue
350+
351+ if not wrote_headers :
352+ names = [d .name for d in result ['detectors' ]]
353+ outfile .write (build_header (self .mcstas .options , self .intervals .keys (), self .intervals , names ))
354+ with open (self .simfile , 'w' ) as simfile :
355+ simfile .write (build_mccodesim_header (
356+ self .mcstas .options ,
357+ self .intervals ,
358+ names ,
359+ version = self .mcstas .version
360+ ))
361+ wrote_headers = True
362+
363+ values = ['%s %s' % (d .intensity , d .error ) for d in result ['detectors' ]]
364+ line = '%s %s\n ' % (' ' .join (map (str , result ['params' ])), ' ' .join (values ))
365+ outfile .write (line )
366+ outfile .flush ()
367+
368+
281369class Optimizer :
282370 """ Optimize monitors by varying the parameters within interval """
283371
0 commit comments