14     Function to load properly module informations from an input json file. 
   17     if file_path.endswith(
".json"):
 
   19             with open(file_path, 
"r") 
as file:
 
   20                 return json.load(file)
 
   21         except Exception 
as e:
 
   22             print(f
"Can not read file at {file_path}: {e}.")
 
   25         print(
"Unexpected input file or format.")
 
   28 def find(bec = None, layer_disk = None, phi = None, eta = None, side = None, asdec = False, input_data = "Geometry.json", output_file = "Geometry_find.json"):
 
   31     this can look for specific set of modules based on parameters: bec(barrel or end cap), layer_disk, phi, eta and side. 
   37     for ID, info 
in data.items():
 
   38         if bec 
is not None and int(info[
"BEC"]) != bec:
 
   41         if layer_disk 
is not None and int(info[
"LayerDisk"]) != layer_disk:
 
   44         if phi 
is not None and int(info[
"PhiModule"]) 
not in [i 
for i 
in phi]:
 
   47         if eta 
is not None and int(info[
"EtaModule"]) > eta:
 
   50         if side 
is not None and int(info[
"Side"]) != side:
 
   54             info[
"Decimal_ID"] = 
str(
int(ID, 16))
 
   58     with open(output_file, 
"w") 
as f:
 
   59         selected_data = {ID: data[ID] 
for ID 
in IDs}
 
   60         json.dump(selected_data, f, indent=4)
 
   64 def merge(file_1 = "Geometry_1.json", file_2 = "Geometry_2.json", output_file = "Geometry_merge.json"):
 
   67     Function to merge any two json files produced with different configuration. 
   74     IDs.extend(data1.keys())
 
   75     IDs.extend(data2.keys())
 
   77     with open(output_file, 
"w") 
as f3:
 
   81                 selected_data[ID] = data1[ID]
 
   83                 selected_data[ID] = data2[ID]
 
   84         json.dump(selected_data, f3, indent=4)
 
   88 def select_random(frac = 0, input_data = "Geometry.json", output_file = "Geometry_rand.json", seed = None):
 
   91     Function to select a given fraction of modules randomly from all the modules using Geometry.json as input. The seed can be change. 
   97     num = 
int(
round(frac * len(data), 0))
 
  103     IDs = random.sample(
list(data.keys()), k=num) 
 
  105     for ID, info 
in data.items():
 
  106         info[
"Decimal_ID"] = 
str(
int(ID, 16))
 
  108     with open(output_file, 
"w") 
as f:
 
  113         selected_data = {ID: data[ID] 
for ID 
in IDs}
 
  114         json.dump(selected_data, f, indent=4)
 
  118 def generate_uncorr(fractions = [], input_data = "Geometry.json", prefix = "Geometry_rand", output_dir = None, seed = None):
 
  121     Function to generate uncorrelated files. Each file contains randomly selected modules according to the values in fractions. 
  125             generate_uncorr(fraction=[1,5], input_data = "PixelGeometry.json", prefix = "PixelGeometry" output_dir = "path/to/dir") 
  127             - PixelGeometry_1pct_corr.json : Contains 1% of modules from PixelGeometry.json file. 
  128             - PixelGeometry_5pct_corr.json : Contains 5% of modules from PixelGeometry.json file (Some module can be in the first file but not the second one and vis versa.) 
  131     if output_dir 
is None:
 
  132         raise ValueError(f
"No output_dir was provided.")
 
  135     for frac 
in sorted(fractions):
 
  136         output_file = f
"{output_dir}/{prefix}_{int(frac*100)}pct_uncorr.json" 
  143 def generate_corr(fractions = [], input_data = "geometry.json", prefix = "Geometry_rand", output_dir = None, seed = None):
 
  146     Generate correlated files using a random selection for each fractions, but modules that have been selected are kept in the next files and removed from the input_data file. 
  150             generate_corr(fraction=[1,5], input_data = "PixelGeometry.json", prefix = "PixelGeometry" output_dir = "path/to/dir") 
  151         will create 3 files :  
  152             - PixelGeometry_1pct_corr.json : Contains 1% of modules from PixelGeometry.json file 
  153             - PixelGeometry_5pct_corr.json : Contains all selected modules in the 1% file + additional Pixel modules to get to a total of 5% module w.r.t to the input file, PixelGeometry.json 
  154             - PixelGeometry_not_selected.json : Contains all modules that have not been randomly selected. 
  158     if output_dir 
is None:
 
  159         raise ValueError(f
"No output_dir was provided.")
 
  161     not_selected_yet_file=f
"{output_dir}/{prefix}_not_selected.json" 
  166     for i, frac 
in enumerate(
sorted(fractions)):
 
  168         output_file = f
"{output_dir}/{prefix}_{pct}pct_corr.json" 
  169         output_file_temp = f
"{output_dir}/{prefix}_{pct}pct_temp.json" 
  173             data_not_masked = 
difference(input_data, output_file, not_selected_yet_file)
 
  174             output_files.append(output_file)
 
  177             new_frac = 
frac_convertor(frac, input_data, output_files[i-1], not_selected_yet_file)
 
  179             data_temp = 
select_random(new_frac, not_selected_yet_file, output_file_temp, seed)
 
  180             data_not_masked = 
difference(not_selected_yet_file, output_file_temp, not_selected_yet_file)
 
  182             data = 
merge(output_files[i-1], output_file_temp, output_file)
 
  183             output_files.append(output_file)
 
  185             os.remove(output_file_temp)
 
  190         if i == len(fractions) - 1:
 
  191             IDs.append(data_not_masked)    
 
  195 def difference(file_1 = "Geometry_1.json", file_2 = "Geometry_2.json", output_file = "Geometry_diff.json"):
 
  198     Function to perform the differnence between two json files produces with different configuration 
  205     IDs = [ID 
for ID 
in list(data1.keys()) 
if ID 
not in list(data2.keys())]
 
  207     with open(output_file, 
"w") 
as f:
 
  208         selected_data = {ID : data1[ID] 
for ID 
in IDs}
 
  209         json.dump(selected_data, f, indent=4)
 
  213 def frac_convertor(frac = None, file_1 = "Geometry.json", file_2 = "Selected_geometry.json", file_3 = "Not_selected_yet.json"):
 
  216     Function used in the generate_corr() function to compute the new fraction of module to select. 
  218     Since the input_data file in select_random() contains less and less modules as one selects them, the fraction of module to be selected has to be recompute to match the desired one. 
  221         In file A, there are 100 modules. One wants to create two correlated files :  
  222             - file B : 10% of modules ( size = 10 modules ) 
  223             - file C : 50% of modules ( size = 50 modules = 10 modules from file A + 40 new modules ) 
  225             For file C, one can not use 0.5 as a fraction because it would select 45 modules and file C would contains 55 modules instead of 50, as desired: 
  227                 # of selected modules = len(file A - file B) * frac = (100 - 10) * 0.5 = 45 
  230             The new fraction should be: 
  232                 new_frac = [ (number of wanted modules in final file) - (number of already selected modules) ] / (number of not yet selected modules)  
  233                          = [ (len(file A) * frac) - len(file B) ] / (len(file A - file B)) 
  237             So the file C contains : 
  239                 # of selected modules = len(file A - file B) * new_frac = (100 - 10) * 4/9 = 40 
  251     nIDs=
int(frac*nIDs1) - nIDs2
 
  252     new_frac = nIDs / nIDs3 
if nIDs3 > 0 
else 1
 
  256 if __name__ == 
"__main__": 
 
  258     current_dir = os.path.dirname(os.path.abspath(__file__)) 
 
  261     Generate 1 file with pixel modules from the layer 0 in the barrel (i.e the InnerMostLayer). 
  264     data = 
find(bec = 0, layer_disk = 0, phi = 
None, eta = 
None, side = 
None, asdec = 
False, input_data = 
"PixelGeometry.json", output_file = 
"IBL_modules.json")
 
  268     Generate 1 file with 5% of strip modules. 
  275     Generate 4 uncorrelated files with randomly selected modules according to 1, 5, 10 and 15% of the pixel modules in the input_data file (e.g PixelGeometry.json).  
  282     Generate 4 correlated files with randomly selected modules according to 1, 5, 10 and 15% of the input_data file size (e.g PixelGeometry.json).  
  283     Each file contains modules that have been masked in the previous configuration.