CMS 3D CMS Logo

mixture.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 """
4 mixture.py replaces the functionality of mixture.f
5 
6 Usage:
7 
8 $ python3 mixture.py filename.in
9 
10 Where `filename.in` contains a set of mixtures and its components:
11 
12 The format for `filename.in` is as follows:
13 
14 Each mixture description starts with a hash symbol (#) and contains
15 the following information in a single line:
16 
17  * Name (name of mixture of components)
18  * GMIX name ()
19  * MC Volume
20  * MC Area
21 
22 A mixture definition is followed by a set of compounds, which is the
23 set of components that the mixture is made from.
24 
25 Each compound description starts with an asterisk (*) and contains
26 the following information:
27 
28  * Item number (An index for the list)
29  * Comment (A human readable name for the material)
30  * Material (Component name)
31  * Volume
32  * Multiplicity (How many times the material is in the mixture)
33  * Type (see below)
34 
35 Type stands for a classification of the Material using the following
36 convention:
37 
38  * SUP: Support
39  * COL: Cooling
40  * ELE: Electronics
41  * CAB: Cables
42  * SEN: Sensitive volumes
43 
44 Each Material (component of the mixture) belongs to a single category.
45 `mixture.py` uses these information to compute how the mixture as a whole
46 contributes to each of the categories in terms of radiation length (x0)
47 and nuclear interaction length (l0) \lambda_{0}.
48 
49 The radiation length or the nuclear interaction lenght become relevant
50 depending if we are talking about particles that interact with the detector
51 mainly throgh electromagnetic forces (x0) or either strong interaction or nuclear
52 forces (l0). Notice that these quantities are different and therefore the
53 contribution for each category will depend on them.
54 
55 Any line in `filename.in` is therefore ignored unless it begins with
56 a hash or an asterisk.
57 
58 Hardcoded in `mixture.py` are the files `mixed_materials.input` and
59 `pure_materials.input`. These files act as a database that provides
60 information about the compounds. From each compound defined in
61 `filename.in` `mixture.py` matches the content of `Material` with a
62 single element of the database and extracts the following information
63 (the format of the mentioned .input files):
64 
65  * Name (which should match with Material)
66  * Weight (Atomic Mass) [g/mol]
67  * Number (Atomic number)
68  * Density (g/cm^3)
69  * RadLen (Radiation lenght) (cm)
70  * IntLen (Nuclear interaction lenght) (cm)
71 
72 With these information `material.py` computes for each mixture:
73 
74  * The radiation lenght for the mixture
75  * The nuclear interaction lenght for the mixture
76  * The mixture density
77  * The mixture volume
78  * The total weight
79  * The relative contribution in each categorio on x0 and l0
80  * Normalized quantities based on MC Volume and MC Area values
81 
82 As well for the compounds:
83 
84  * The relative volume within the mixture
85  * The relative weight
86  * The relative radiation lenght
87  * The relative nuclear interaction length
88 
89 """
90 
91 import re
92 import pandas as pd
93 import sys
94 
95 def getMixture(line) :
96  mixture = re.search(
97  r'^#\s*"(?P<MixtureName>[^"]+)"\s+"(?P<GMIXName>[^"]+)"\s+(?P<MCVolume>[0-9.Ee\-+]+)\s+(?P<MCArea>[0-9.Ee\-+]+)',
98  line
99  )
100  return {
101  'mixture_name' : mixture.group("MixtureName"),
102  'gmix_name' : mixture.group("GMIXName"),
103  'mc_volume' : float(mixture.group("MCVolume")),
104  'mc_area' : float(mixture.group("MCArea")),
105  }
106 
107 
108 def getCompound(line) :
109  compound = re.search(
110  r'^\*\s*(?P<Index>[0-9]+)\s+"(?P<Comment>[^"]+)"\s+"(?P<Material>[^"]+)"\s+(?P<Volume>[0-9.Ee\-+]+)\s+(?P<Mult>[0-9.]+)\s+(?P<Type>[^ ]{3})',
111  line
112  )
113  return {
114  'item_number' : int(compound.group("Index")),
115  'comment' : compound.group("Comment"),
116  'material' : compound.group("Material"),
117  'volume' : float(compound.group("Volume")),
118  'multiplicity' : float(compound.group("Mult")),
119  'category' : compound.group("Type"),
120  }
121 
122 def getMixtures(inputFile) :
123 
124  """
125  Returns a `dict` of Mixtures. Each
126  mixture contains a list of compounds.
127  """
128 
129  inFile = open(inputFile,"r")
130 
131  mixtures = []
132  mixture = {}
133 
134  counter = 0
135  prevCounter = 0
136 
137  for line in inFile.readlines():
138 
139  if line[0] == "#":
140  if mixture:
141  mixtures.append(dict(mixture)) #Just to make a copy
142  mixture.clear()
143  mixture = getMixture(line)
144  mixture.update({ 'components' : [] })
145 
146  if line[0] == "*":
147  mixture['components'].append(dict(getCompound(line)))
148 
149  inFile.close()
150 
151  return mixtures
152 
153 def loadMaterialsFile(inputFile):
154 
155  mixMatFile = open(inputFile,"r")
156 
157  mixMats = []
158 
159  for line in mixMatFile.readlines():
160 
161  if line[0] == '"':
162  mixMat = re.search(
163  r'^"(?P<name>[^"]+)"\s+(?P<weight>[0-9.Ee-]+)\s+(?P<number>[0-9.Ee-]+)\s+(?P<density>[0-9.Ee-]+)\s+(?P<x0>[0-9.Ee-]+)\s+(?P<l0>[0-9Ee.-]+)',
164  line
165  )
166 
167  mixMats.append({
168  "name" : mixMat.group("name"),
169  "weight" : float(mixMat.group("weight")),
170  "number" : float(mixMat.group("number")),
171  "density" : float(mixMat.group("density")),
172  "x0" : float(mixMat.group("x0")),
173  "l0" : float(mixMat.group("l0")),
174  })
175 
176  return mixMats
177 
178 def main(argv):
179 
180  listOfMixtures = getMixtures(str(argv[1]))
181 
182  fname = re.search("(?P<filename>[a-zA-Z0-9_]+)",str(argv[1]))
183 
184  fname = str(fname.group("filename"))
185  radLenFile = open(fname + ".x0","w");
186  intLenFile = open(fname + ".l0","w");
187 
188  listOfMixedMaterials = loadMaterialsFile(inputFile="mixed_materials.input")
189  listOfPureMaterials = loadMaterialsFile(inputFile="pure_materials.input")
190  listOfMaterials = listOfMixedMaterials + listOfPureMaterials
191 
192  dfAllMaterials = pd.DataFrame(listOfMaterials)
193 
194  for index in range(len(listOfMixtures)):
195 
196  gmixName = listOfMixtures[index]["gmix_name"]
197  print("================================")
198  print(gmixName)
199 
200  components = pd.DataFrame(listOfMixtures[index]['components'])
201 
202  components["volume"] = components["multiplicity"]*components["volume"]
203  totalVolume = sum(
204  components["volume"]
205  )
206 
207  components["percentVolume"] = components["volume"] / totalVolume
208 
209  components = pd.merge(
210  components,
211  dfAllMaterials[["name","density","x0","l0"]],
212  left_on="material",
213  right_on="name"
214  )
215 
216  components["weight"] = components["density"] * components["volume"]
217 
218  totalDensity = sum(
219  components["percentVolume"] * components["density"]
220  )
221 
222  totalWeight = totalDensity * totalVolume
223 
224  components["percentWeight"] = (
225  components["density"] * components["volume"] / totalWeight
226  )
227 
228  components["ws"] = (
229  components["percentWeight"] / (components["density"]*components["x0"])
230  )
231 
232  components["ws2"] = (
233  components["percentWeight"] / (components["density"]*components["l0"])
234  )
235 
236  totalRadLen = 1 / ( sum(components["ws"]) * totalDensity )
237 
238  totalIntLen = 1/ ( sum(components["ws2"]) * totalDensity )
239 
240  components["percentRadLen"] = (
241  components["ws"] * totalRadLen * totalDensity
242  )
243 
244  components["percentIntLen"] = (
245  components["ws2"] * totalIntLen * totalDensity
246  )
247 
248  displayDf = components[[
249  "comment",
250  "material","volume",
251  "percentVolume","percentWeight",
252  "density","weight","x0","percentRadLen",
253  "l0","percentIntLen"
254  ]].copy()
255 
256  displayDf["percentVolume"] *= 100.
257  displayDf["percentWeight"] *= 100.
258  displayDf["percentRadLen"] *= 100.
259  displayDf["percentIntLen"] *= 100.
260 
261  displayDf = displayDf.rename(
262  columns = {
263  "comment" : "Component",
264  "material" : "Material",
265  "volume" : "Volume [cm^3]",
266  "percentVolume" : "Volume %",
267  "density" : "Density",
268  "weight" : "Weight",
269  "percentWeight" : "Weight %",
270  "x0" : "X_0 [cm]",
271  "percentRadLen" : "X_0 %",
272  "l0": "lambda_0 [cm]",
273  "percentIntLen" : "lambda_0 %",
274  }
275  )
276 
277  print(displayDf)
278 
279 
280  # Normalized vars:
281 
282  mcVolume = listOfMixtures[index]["mc_volume"]
283  mcArea = listOfMixtures[index]["mc_area"]
284  normalizationFactor = -1.
285 
286  if mcVolume > 0:
287  normalizationFactor = totalVolume / mcVolume
288  else:
289  normalizationFactor = 1.
290 
291  normalizedDensity = totalDensity * normalizationFactor
292  normalizedRadLen = totalRadLen / normalizationFactor
293  normalizedIntLen = totalIntLen / normalizationFactor
294 
295  percentRadL = -1.
296  percentIntL = -1.
297 
298  if mcArea > 0:
299  percentRadL = mcVolume / (mcArea*normalizedRadLen)
300  percentIntL = mcVolume / (mcArea*normalizedIntLen)
301 
302  pSupRadLen = 0.
303  pSenRadLen = 0.
304  pCabRadLen = 0.
305  pColRadLen = 0.
306  pEleRadLen = 0.
307 
308  pSupIntLen = 0.
309  pSenIntLen = 0.
310  pCabIntLen = 0.
311  pColIntLen = 0.
312  pEleIntLen = 0.
313 
314  for index, component in components.iterrows():
315  catg = component["category"]
316  prl = component["percentRadLen"]
317  irl = component["percentIntLen"]
318  if catg.upper() == "SUP":
319  pSupRadLen += prl
320  pSupIntLen += irl
321  elif catg.upper() == "SEN":
322  pSenRadLen += prl
323  pSenIntLen += irl
324  elif catg.upper() == "CAB":
325  pCabRadLen += prl
326  pCabIntLen += irl
327  elif catg.upper() == "COL":
328  pColRadLen += prl
329  pColIntLen += irl
330  elif catg.upper() == "ELE":
331  pEleRadLen += prl
332  pEleIntLen += irl
333 
334  print("================================")
335  print("Mixture Density [g/cm^3]: " , totalDensity)
336  print("Norm. mixture density [g/cm^3]: ", normalizedDensity)
337  print("Mixture Volume [cm^3]: ", totalVolume)
338  print("MC Volume [cm^3]: ", mcVolume)
339  print("MC Area [cm^2]: ", mcArea)
340  print("Normalization Factor: ", normalizationFactor)
341  print("Mixture x0 [cm]: ", totalRadLen)
342  print("Norm. Mixture x0 [cm]: ", normalizedRadLen)
343  if mcArea > 0 :
344  print("Norm. Mixture x0 [%]: ", 100. * percentRadL)
345  print("Mixture l0 [cm]: ", totalIntLen)
346  print("Norm. Mixture l0 [cm]: ", normalizedIntLen)
347  if mcArea > 0 :
348  print("Norm. Mixture l0 [%]: ", 100. * percentIntL)
349  print("Total Weight [g]: ", totalWeight)
350 
351  print("================================")
352  print("X0 Contribution: ")
353  print("Support :", pSupRadLen)
354  print("Sensitive :", pSenRadLen)
355  print("Cables :", pCabRadLen)
356  print("Cooling :", pColRadLen)
357  print("Electronics :", pEleRadLen)
358 
359  print("================================")
360  print("l0 Contribution: ")
361  print("Support :", pSupIntLen)
362  print("Sensitive :", pSenIntLen)
363  print("Cables :", pCabIntLen)
364  print("Cooling :", pColIntLen)
365  print("Electronics :", pEleIntLen)
366 
367  radLenFile.write("{0:<50}{1:>8}{2:>8}{3:>8}{4:>8}{5:>8}\n".format(
368  gmixName,
369  round(pSupRadLen,3), round(pSenRadLen,3),
370  round(pCabRadLen,3), round(pColRadLen,3),
371  round(pEleRadLen,3)
372  ))
373 
374  intLenFile.write("{0:<50}{1:>8}{2:>8}{3:>8}{4:>8}{5:>8}\n".format(
375  gmixName,
376  round(pSupIntLen,3), round(pSenIntLen,3),
377  round(pCabIntLen,3), round(pColIntLen,3),
378  round(pEleIntLen,3)
379  ))
380 
381  radLenFile.close()
382  intLenFile.close()
383 
384 if __name__== "__main__":
385  main(sys.argv)
def getCompound(line)
Definition: mixture.py:108
def copy(args, dbName)
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def getMixtures(inputFile)
Definition: mixture.py:122
def getMixture(line)
Definition: mixture.py:95
def main(argv)
Definition: mixture.py:178
def loadMaterialsFile(inputFile)
Definition: mixture.py:153
Definition: main.py:1
#define str(s)