EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
extractor.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file extractor.cc
1 
2 //
3 // c++ -o extractor extractor.cc
4 //
5 
6 //
7 // FIXME: for now for outgoing electron side it is easier just to
8 // change rotation angles by hand in the output file;
9 //
10 
11 #include <vector>
12 #include <map>
13 #include <string>
14 
15 #include <math.h>
16 #include <assert.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 using namespace std;
22 
23 // Give some small default value, which would allow on-axis particles
24 // to pass through, but block everything else and immediately trigger
25 // questions if some of the magnet bores are not present in the database;
26 #define _APERTURE_RADIUS_DEFAULT_ (0.01)
27 
28 // FIXME: command-line parameter, please;
29 //#define _ZMIN_ ( 0.00)
30 #define _ZMIN_ (-40.00)
31 //#define _ZMAX_ ( 0.00)
32 #define _ZMAX_ (40.00)
33 
34 class Bore {
35 public:
36  Bore(double rZin, double rZout, double dOut):
37  mApertureRadiusZin(rZin), mApertureRadiusZout(rZout), mOutsideDiameter(dOut) {};
38  ~Bore() {};
39 
40  double mApertureRadiusZin, mApertureRadiusZout, mOutsideDiameter;
41 };
42 
43 static std::map<std::string, Bore*> bores;
44 
45 class MagElement {
46 public:
47  MagElement(std::string name): mName(name), mApertureRadiusZin(_APERTURE_RADIUS_DEFAULT_),
48  mApertureRadiusZout(_APERTURE_RADIUS_DEFAULT_), mOutsideDiameter(0.0),
49  mTHETAstart(0.0), mTHETAend(0.0),
50  mSstart(0.0), mSend(0.0), mXstart(0.0), mYstart(0.0), mZstart(0.0), mXend(0.0), mYend(0.0), mZend(0.0),
51  mLength(0.0), mX(0.0), mY(0.0), mZ(0.0), mTHETA(0.0) {
52  if (bores.find(name) != bores.end()) {
53  Bore *bore = bores[name];
54 
55  // Convert [cm] -> [m];
56  mApertureRadiusZin = 0.01 * bore->mApertureRadiusZin;
57  mApertureRadiusZout = 0.01 * bore->mApertureRadiusZout;
58  mOutsideDiameter = 0.01 * bore->mOutsideDiameter;
59  } //if
60  };
62 
63  virtual double GetField( void ) const { return 0.0; };
64  virtual double GetGradient( void ) const { return 0.0; };
65 
66  // NB: need at least one virtual method, otherwise dynamic_cast fails
67  // claiming base class is not polymorphic;
68  virtual void Calculate(double Brho) = 0;
69  virtual void Print( void ) { printf("%10s -> L = %7.3f; X = %7.3f, Z = %8.3f, TH = %7.2f mrad",
70  mName.c_str(), mLength, mX, mZ, mTHETA * 1000); };
71  virtual void WriteOut(FILE *fout) {
72  // I'm changing format of this file anyway (Apr'2018), so change coordinate order to XYZ too;
73  fprintf(fout, "%10s %8.4f %8.4f %8.4f %7.4f %7.3f %7.4f %7.3f %7.2f %7.3f %8.3f\n",
74  mName.c_str(), mX, mY, mZ, mApertureRadiusZin, mApertureRadiusZout, mOutsideDiameter, mLength, mTHETA * 1000., GetField(), GetGradient()); };
75 
76  std::string mName;
77  // mOutsideDiameter has a meaning of full width (height) for dipoles;
78  double mApertureRadiusZin, mApertureRadiusZout, mOutsideDiameter;
79 
80  // Will be used for length calculation;
81  double mSstart, mSend, mTHETAstart, mTHETAend;
82  // Will be used for XYZ calculation;
83  double mXstart, mYstart, mZstart, mXend, mYend, mZend;
84 
85  // Ultimate numbers, which will go into the tables;
86  double mLength, mX, mY, mZ, mTHETA;
87 };
88 
89 class Dipole: public MagElement {
90 public:
91  Dipole(std::string name, double angle): MagElement(name), mANGLE(angle), mField(0.0) {};
92  ~Dipole() {};
93 
94  double GetField( void ) const { return mField; };
95  void Calculate(double Brho) { mField = Brho * mANGLE/mLength; };
96  void Print( void ) { MagElement::Print(); printf(" (D), ANGLE = %9.6f -> %8.3f [T]\n", mANGLE, mField); };
97  double mANGLE;
98 
99  // (Constant) field value;
100  double mField;
101 };
102 
103 class Quadrupole: public MagElement {
104 public:
105  Quadrupole(std::string name, double k1l): MagElement(name), mK1L(k1l), mGradient(0.0) {};
107 
108  double GetGradient( void ) const { return mGradient; };
109  void Calculate(double Brho) { mGradient = Brho * mK1L/mLength; };
110  void Print( void ) { MagElement::Print(); printf(" (Q), K1L = %9.6f ->%9.3f [T/m] \n", mK1L, mGradient); };
111  double mK1L;
112 
113  // (Constant) field gradient value;
114  double mGradient;
115 };
116 
117 class BeamLine {
118 public:
119  BeamLine(unsigned data_par_num, unsigned survey_par_num, bool rear = false):
120  mBrho(0.0), mDataParNum(data_par_num), mSurveyParNum(survey_par_num)/*, mZcoordFlip(rear)*/ {};
121  ~BeamLine() {};
122 
123  void AddDataFile(const char *fname) { mDataFiles.push_back(fname); };
124  void AddSurveyFile(const char *fname) { mSurveyFiles.push_back(fname); };
125 
126  double mBrho;
127 
128  // ALFY is missing in the electron data files; extra columns exist in electron survey file;
129  unsigned mDataParNum, mSurveyParNum;
130  //bool mZcoordFlip;
131  std::vector<std::string> mDataFiles, mSurveyFiles, mAllFiles;
132 
133  std::map<std::string, MagElement*> mMagElements;
134  std::map<double, MagElement*> mOrderedMagElements;
135 };
136 
137 static char *GetTrueElementName(const char *name)
138 {
139  static char rname[1024];
140  assert(strlen(name) < 1024);
141 
142  strcpy(rname, name + (name[0] == '\"' ? 1 : 0));
143  {
144  unsigned slen = strlen(rname);
145 
146  if (rname[slen-1] == '\"') rname[slen-1] = 0;
147  }
148  {
149  unsigned slen = strlen(rname);
150  if (!strcmp(rname+slen-2, "_E") || !strcmp(rname+slen-2, "_F")) rname[slen-2] = 0;
151  if (!strcmp(rname+slen-2, "_6")) rname[slen-2] = 0;
152  if (!strcmp(rname+slen-3, "_E1") || !strcmp(rname+slen-3, "_E2")) rname[slen-3] = 0;
153  }
154 
155  return rname;
156 } // GetTrueElementName()
157 
158 static bool IsElementStartLine(const char *name)
159 {
160  unsigned slen = strlen(name);
161 
162  // NB: yes, E1 & E2 seem to be swapped; also rear files need special treatment;
163  return (!strcmp(name+slen-2, "_F") || !strcmp(name+slen-3, "_E2") ||
164  !strcmp(name+slen-3, "_F\"") || !strcmp(name+slen-4, "_E2\""));
165 } // IsElementStartLine()
166 
167 static bool IsElementEndLine(const char *name)
168 {
169  unsigned slen = strlen(name);
170 
171  return (!strcmp(name+slen-2, "_E") || !strcmp(name+slen-3, "_E1") ||
172  !strcmp(name+slen-3, "_E\"") || !strcmp(name+slen-4, "_E1\"") || !strcmp(name+slen-3, "_6\""));
173 } // IsElementEndLine()
174 
175 int main(int argc, char **argv)
176 {
177  // Make it easy -> hardcode damn file names;
178  BeamLine *electron = new BeamLine(14, 15), *hadron = new BeamLine(15, 8), *beamlines[2] = {hadron, electron};
179  electron->AddDataFile("rr-data-norad-ver3-10GeV-elke.tfs.no-dash");
180  electron->AddSurveyFile("rr-survey-ver3-10GeV-elke.tfs");
181  hadron->AddDataFile("Hadron-275GeV.dataForward");
182  hadron->AddSurveyFile("Hadron-275GeV.surveyForward");
183  hadron->AddDataFile("Hadron-275GeV.dataRear");
184  hadron->AddSurveyFile("Hadron-275GeV.surveyRear");
185 
186  // Read bore information file;
187  {
188  FILE *fbore = fopen("bores.txt", "r");
189  assert(fbore);
190 
191  char buffer[1024];
192 
193  while (fgets(buffer, 1024, fbore)) {
194  if (!strlen(buffer) || buffer[0] == '#') continue;
195 
196  char name[256];
197  double rZin, rZout, rOut;
198  int ret = sscanf(buffer, "%s %lf %lf %lf", name, &rZin, &rZout, &rOut);
199 
200  if (ret == 4) bores[name] = new Bore(rZin, rZout, 2*rOut);
201  } //while
202 
203  fclose(fbore);
204  }
205 
206  // Loop through both beamlines independently;
207  for(unsigned bl=0; bl<2; bl++) {
208  BeamLine *beamline = beamlines[bl];
209 
210  // This looks dumb, but it works; data files will be parsed first;
211  for(unsigned fl=0; fl<beamline->mDataFiles.size(); fl++)
212  beamline->mAllFiles.push_back(beamline->mDataFiles[fl]);
213  for(unsigned fl=0; fl<beamline->mSurveyFiles.size(); fl++)
214  beamline->mAllFiles.push_back(beamline->mSurveyFiles[fl]);
215 
216  // Parse data files first;
217  for(unsigned fl=0; fl<beamline->mAllFiles.size(); fl++) {
218  std::string &fname = beamline->mAllFiles[fl];
219  // FIXME: tired of this *hit, sorry;
220  bool zflip = fname.find("Rear") != std::string::npos;
221  if (beamline == electron) zflip = true;
222 
223  printf("\n --> %s\n\n", fname.c_str());
224  {
225  FILE *fin = fopen(fname.c_str(), "r");
226  assert(fin);
227 
228  int ret;
229  // NB: need a buffer string, since may want to extract header variables as well;
230  char buffer[1024];
231 
232  while (fgets(buffer, 1024, fin)) {
233  // Try to interpret the string as header data first;
234  char str1[128], str2[128], str3[128], str4[128], str5[128], *vptr = 0;
235  int hret = sscanf(buffer, "%s %s %s %s %s", str1, str2, str3, str4, str5);
236  if (hret == 3)
237  vptr = str3;
238  else if (hret == 4)
239  vptr = str4;
240 
241  if (vptr) {
242  // Header string; fish out the ones I may need; if assigned more than once,
243  // (in forward and rearward data files, survey files, etc) check consistency;
244  if (!strcmp(str2, "PC")) {
245  // FIXME: hardcode this coefficient in a more intelligent way later;
246  double value = atof(vptr) * 3.335640951;
247  if (beamline->mBrho)
248  assert(value == beamline->mBrho);
249  else
250  beamline->mBrho = value;
251  } //if
252  } else {
253  char name[256];
254 
255  if (fl < beamline->mDataFiles.size()) {
256  double S, L, BETX, ALFX, BETY, ALFY, MUX, MUY, DX, DPX, ANGLE, K0L, K1L, K2L;
257 
258  // Try this same string as data entry;
259  switch (beamline->mDataParNum) {
260  case 14:
261  ALFY = 0.0;
262  {
263  char qname[256] = "";
264  // NB: K1L column has dash symbols rather than '-' and fscanf() will terminate
265  // conversion at this point if %lf and &K1L were used;
266  ret = sscanf(buffer, "%s %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %s %lf",
267  name, &S, &L, &BETX, &ALFX, &BETY, &MUX, &MUY, &DX, &DPX, &ANGLE, &K0L, qname, &K2L);
268  // NB: this will fail for values starting with the dash; FIXME later;
269  K1L = atof(qname);
270  }
271  break;
272  case 15:
273  ret = sscanf(buffer, "%s %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
274  name, &S, &L, &BETX, &ALFX, &BETY, &ALFY, &MUX, &MUY, &DX, &DPX, &ANGLE, &K0L, &K1L, &K2L);
275  break;
276  default:
277  assert(0);
278  } //switch
279 
280  //printf("%d\n", ret);
281  if (ret != beamline->mDataParNum) continue;
282 
283  // For now I'm only interested in the field strength in these files; ignore all other lines;
284  // FIXME: YI6_HB1 magnet with 0.0 field at 275 GeV is ignored in this picture;
285  if (!ANGLE && !K1L) continue;
286  char *rname = GetTrueElementName(name);
287 
288  // If K1L is non-zero, it is a quad; NB: ANGLE can be 0.0 for the dipole;
289  // For now I'm only interested in the field strength in the 'data' files ->
290  // it looks like I can ignore the _E and _F lines;
291  if (K1L)
292  beamline->mMagElements[rname] = new Quadrupole(rname, /*L,*/ K1L);
293  else
294  beamline->mMagElements[rname] = new Dipole (rname, /*L,*/ ANGLE);
295 
296  //printf("%10s -> %10s -> %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf (%s)\n",
297  // name, rname, S, L, BETX, ALFX, BETY, ALFY, MUX, MUY, DX, DPX, ANGLE, K0L, K1L, K2L, qname);
298  } else {
299  double S, L, ANGLE, X, Y, Z, THETA, dummy;
300 
301  // Try this same string as survey entry; at most 15 columns;
302  int ret = sscanf(buffer, "%s %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
303  name, &S, &L, &ANGLE, &X, &Y, &Z, &THETA, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy);
304  if (ret != beamline->mSurveyParNum) continue;
305 
306  if (zflip) Z *= -1.0;
307  if (THETA < -6.0) THETA += 2*M_PI;
308 
309  char *rname = GetTrueElementName(name);
310  MagElement *element = beamline->mMagElements[rname];
311  if (element) {
312  // Well, center point is missing in hadron files -> base XYZ calculation of
313  // front/end entries (which can come irn reversed order like in electron file);
314  if (IsElementStartLine(name)) {
315  element->mSstart = S;
316  element->mTHETAstart = THETA;
317 
318  element->mXstart = X;
319  element->mYstart = Y;
320  element->mZstart = Z;
321 
322  } else if (IsElementEndLine(name)) {
323  element->mSend = S;
324  element->mTHETAend = THETA;
325 
326  element->mXend = X;
327  element->mYend = Y;
328  element->mZend = Z;
329  } //if
330  } else {
331  printf("Orhpan beam line element: %s\n", rname);
332  } //if
333  } //if
334  }
335  } //while
336 
337  fclose(fin);
338  }
339  } //for fl
340 
341  printf(" Brho --> %f\n", beamline->mBrho);
342  for(std::map<std::string, MagElement*>::iterator it = beamline->mMagElements.begin();
343  it != beamline->mMagElements.end(); it++) {
344  MagElement *element = it->second;
345 
346  if (element) {
347  element->Print();
348  printf(" %10s -> Sstart = %8.4f, Send = %8.4f\n", it->first.c_str(), element->mSstart, element->mSend);
349  assert(element->mSstart && element->mSend);
350 
351  // Calculate element length; fabs() is the easiest hack for hadron rear elements;
352  element->mLength = fabs(element->mSend - element->mSstart); assert(element->mLength);
353 
354  element->mTHETA = (element->mTHETAstart + element->mTHETAend)/2;
355 
356  // Calculate element center point coordinates;
357  element->mX = (element->mXstart + element->mXend)/2;
358  element->mY = (element->mYstart + element->mYend)/2;
359  element->mZ = (element->mZstart + element->mZend)/2;
360 
361  element->Calculate(beamline->mBrho);
362 
363  beamline->mOrderedMagElements[element->mZ] = element;
364  } //if
365  } //for it
366 #if 0
367  printf(" \n bl#%d: Dipoles:\n", bl);
368  for(std::map<std::string, MagElement*>::iterator it = beamline->mMagElements.begin();
369  it != beamline->mMagElements.end(); it++) {
370  Dipole *dipole = dynamic_cast<Dipole*>(it->second);
371  if (dipole) dipole->Print();
372  } //for it
373  printf(" \n bl#%d: Quads:\n", bl);
374  for(std::map<std::string, MagElement*>::iterator it = beamline->mMagElements.begin();
375  it != beamline->mMagElements.end(); it++) {
376  Quadrupole *quad = dynamic_cast<Quadrupole*>(it->second);
377  if (quad) quad->Print();
378  } //for it
379 #endif
380 #if 1
381  printf(" \n bl#%d: Ordered element sequence:\n", bl);
382  for(std::map<double, MagElement*>::iterator it = beamline->mOrderedMagElements.begin();
383  it != beamline->mOrderedMagElements.end(); it++)
384  it->second->Print();
385 #endif
386 
387  // Produce output file;
388  {
389  char fname[1024];
390  snprintf(fname, 1024-1, "%s/ir-magnets-2018-04-04-%s.dat", bl ? "E" : "H", bl ? "electrons" : "hadrons");
391  FILE *fout = fopen(fname, "w"); assert(fout);
392 
393  // Copy over the "header";
394  {
395  FILE *fheader = fopen("header.txt", "r");
396  assert(fheader);
397  {
398  char buffer[1024];
399 
400  while (fgets(buffer, 1024-1, fheader)) fprintf(fout, "%s", buffer);
401  }
402  fclose(fheader);
403  }
404 
405  // The magnetic elements;
406  for(std::map<double, MagElement*>::iterator it = beamline->mOrderedMagElements.begin();
407  it != beamline->mOrderedMagElements.end(); it++)
408  if (it->second->mZ >= _ZMIN_ && it->second->mZ <= _ZMAX_)
409  it->second->WriteOut(fout);
410 
411  fclose(fout);
412  }
413  } //for bl
414 
415  exit(0);
416 } // main()