source: trunk/Mars/msimreflector/MLens.cc@ 19545

Last change on this file since 19545 was 19539, checked in by tbretz, 6 years ago
This is basically a copy of MReflector supposed to describe a lens.
File size: 15.3 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of CheObs, the Modular Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appears in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 6/2019 <mailto:tbretz@physik.rwth-aachen.de>
19!
20! Copyright: CheObs Software Development, 2000-2009
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MLens
28//
29//////////////////////////////////////////////////////////////////////////////
30#include "MLens.h"
31
32#include <fstream>
33#include <errno.h>
34
35#include <stdlib.h> // atof (Ubuntu 8.10)
36
37#include <TClass.h>
38#include <TSystem.h>
39#include <TEllipse.h>
40
41#include "MQuaternion.h"
42#include "MMirror.h"
43
44#include "MLog.h"
45#include "MLogManip.h"
46
47#include "MH.h"
48
49ClassImp(MLens);
50
51using namespace std;
52
53// --------------------------------------------------------------------------
54//
55// Default constructor
56//
57MLens::MLens(const char *name, const char *title)
58{
59 fName = name ? name : "MLens";
60 fTitle = title ? title : "Parameter container storing a collection of several mirrors (reflector)";
61
62 fMirrors.SetOwner();
63}
64
65// --------------------------------------------------------------------------
66//
67// Set the SigmaPSF of all mirrors currently stored.
68//
69void MLens::SetSigmaPSF(Double_t psf)
70{
71 fMirrors.R__FOR_EACH(MMirror, SetSigmaPSF)(psf);
72}
73
74// --------------------------------------------------------------------------
75//
76// Calculate the maximum radius of th ereflector. This is not meant as
77// a precise number but as a rough estimate e.g. to bin a histogram.
78//
79void MLens::InitMaxR()
80{
81 fMaxR = 0;
82
83 TIter Next(&fMirrors);
84 MMirror *m = 0;
85 while ((m=static_cast<MMirror*>(Next())))
86 {
87 // Take into account the maximum incident angle 8eg 10deg) and
88 // the theta-angle of the mirror and the z-distance.
89 const Double_t r = m->GetDist()+1.5*m->GetMaxR();
90 if (r > fMaxR)
91 fMaxR = r;
92 }
93}
94
95// --------------------------------------------------------------------------
96//
97// Return the total Area of all mirrors. Note, that it is recalculated
98// with any call.
99//
100Double_t MLens::GetA() const
101{
102 Double_t A = 0;
103
104 TIter Next(&fMirrors);
105 MMirror *m = 0;
106 while ((m=static_cast<MMirror*>(Next())))
107 A += m->GetA();
108
109 return A;
110}
111
112// --------------------------------------------------------------------------
113//
114// Get the pointer to the first mirror. This is a very dangerous way of
115// access, but the fastest possible. because it is the most often called
116// function in ExecuteReflector we have to have a very fast access.
117//
118const MMirror **MLens::GetFirstPtr() const
119{
120 return (const MMirror**)fMirrors.GetObjectRef(0);
121}
122
123// --------------------------------------------------------------------------
124//
125// Get number of mirrors. There should be no holes in the array!
126//
127const UInt_t MLens::GetNumMirrors() const
128{
129 return fMirrors.GetEntriesFast();
130}
131
132// --------------------------------------------------------------------------
133//
134// Check with a rough estimate whether a photon can hit the reflector.
135//
136Bool_t MLens::CanHit(const MQuaternion &p) const
137{
138 // p is given in the reflectory coordinate frame. This is meant as a
139 // fast check without lengthy calculations to omit all photons which
140 // cannot hit the reflector at all
141 return p.R2()<fMaxR*fMaxR;
142}
143
144// Jeder Spiegel sollte eine Liste aller andern Spiegel in der
145// reihenfolge Ihrer Entfernung enthalten. Wir starten mit der Suche
146// immer beim zuletzt getroffenen Spiegel!
147//
148// --------------------------------------------------------------------------
149//
150// Loops over all mirrors of the reflector. After doing a rough check
151// whether the mirror can be hit at all the reflection is executed
152// calling the ExecuteMirror function of the mirrors.
153//
154// If a mirror was hit its index is retuened, -1 otherwise.
155//
156// FIXME: Do to lopping over all mirrors for all photons this is the
157// most time consuming function in teh reflector simulation. By a more
158// intelligent way of finding the right mirror then just testing all
159// this could be accelerated a lot.
160//
161Int_t MLens::ExecuteOptics(MQuaternion &p, MQuaternion &u) const
162{
163 //static const TObjArray *arr = &((MMirror*)fMirrors[0])->fNeighbors;
164
165 // This way of access is somuch faster than the program is
166 // a few percent slower if accessed by UncheckedAt
167 const MMirror **s = GetFirstPtr();
168 const MMirror **e = s+GetNumMirrors();
169 //const MMirror **s = (const MMirror**)fMirrors.GetObjectRef(0);
170 //const MMirror **e = s+fMirrors.GetEntriesFast();
171 //const MMirror **s = (const MMirror**)arr->GetObjectRef(0);
172 //const MMirror **e = s+arr->GetEntriesFast();
173
174 // Loop over all mirrors
175 for (const MMirror **m=s; m<e; m++)
176 {
177 const MMirror &mirror = **m;
178
179 // FIXME: Can we speed up using lookup tables or
180 // indexed tables?
181
182 // MirrorShape: Check if this mirror can be hit at all
183 // This is to avoid time consuming calculation if there is no
184 // chance of a coincidence.
185 // FIXME: Inmprove search algorithm (2D Binary search?)
186 if (!mirror.CanHit(p))
187 continue;
188
189 // Make a local copy of position and direction which can be
190 // changed by ExecuteMirror.
191 MQuaternion q(p);
192 MQuaternion v(u);
193
194 // Check if this mirror is hit, and if it is hit return
195 // the reflected position and direction vector.
196 // If the mirror is missed we go on with the next mirror.
197 if (!mirror.ExecuteMirror(q, v))
198 continue;
199
200 // We hit a mirror. Restore the local copy of position and
201 // direction back into p und u.
202 p = q;
203 u = v;
204
205 //arr = &mirror->fNeighbors;
206
207 return m-s;
208 }
209
210 return -1;
211}
212
213// --------------------------------------------------------------------------
214//
215// I/O helper for ReadFile to avoid calling "delete arr" before every return
216//
217MMirror *MLens::EvalTokens(TObjArray &arr, Double_t defpsf) const
218{
219 if (arr.GetEntries()<9)
220 {
221 *fLog << err << "ERROR - Not enough arguments..." << endl;
222 return 0;
223 }
224
225 const TVector3 pos(atof(arr[0]->GetName()),
226 atof(arr[1]->GetName()),
227 atof(arr[2]->GetName()));
228
229 const TVector3 norm(atof(arr[3]->GetName()),
230 atof(arr[4]->GetName()),
231 atof(arr[5]->GetName()));
232
233 UInt_t n = 6;
234
235 TString six = arr[n]->GetName();
236
237 Char_t shape = 'S';
238 if (!six.IsFloat())
239 {
240 shape = six[0];
241 n++;
242 }
243
244 const Double_t F = atof(arr[n++]->GetName());
245
246 const TString val = arr[n++]->GetName();
247
248 const Double_t psf = val.IsFloat() ? val.Atof() : -1;
249
250 n += val.IsFloat() ? 1 : 0;
251
252 TString type = arr[n-1]->GetName();
253 type.Prepend("MMirror");
254
255 for (UInt_t i=0; i<n; i++)
256 delete arr.RemoveAt(i);
257 arr.Compress();
258
259 TString msg;
260 TClass *cls = MParContainer::GetClass(type);
261 if (!cls)
262 {
263 *fLog << err << "ERROR - Class " << type << " not in dictionary." << endl;
264 return 0;
265 }
266
267 if (!cls->InheritsFrom(MMirror::Class()))
268 {
269 *fLog << err << "ERROR - Cannot create new instance of class " << type << ": " << endl;
270 *fLog << "Class doesn't inherit from MMirror." << endl;
271 return 0;
272 }
273
274 MMirror *m = static_cast<MMirror*>(cls->New());
275 if (!m)
276 {
277 *fLog << err << "ERROR - Cannot create new instance of class " << type << ": " << endl;
278 *fLog << " - Class has no default constructor." << endl;
279 *fLog << " - An abstract member functions of a base class is not overwritten." << endl;
280 return 0;
281 }
282
283 m->SetPosition(pos);
284 m->SetNorm(norm);
285 m->SetShape(shape);
286 m->SetFocalLength(F);
287 m->SetSigmaPSF(psf>=0 ? psf : defpsf);
288
289 if (m->ReadM(arr)>=0)
290 return m;
291
292 *fLog << err << "ERROR - " << type << "::ReadM failed." << endl;
293
294 delete m;
295 return 0;
296}
297
298// --------------------------------------------------------------------------
299//
300// Read a reflector setup from a file. This needs improvemtn.
301//
302// The file structur is like:
303//
304// x y z nx ny nz F [psf] Type ...
305//
306// x: x-coordinate of the mirror's center
307// y: y-coordinate of the mirror's center
308// z: z-coordinate of the mirror's center
309// nx: x-component of the normal vecor in the mirror center
310// ny: y-component of the normal vecor in the mirror center
311// nz: z-component of the normal vecor in the mirror center
312// [shape]: S for spherical <default>, P for parabolic
313// F: Focal distance of a spherical mirror
314// [psf]: This number is the psf given in the units of x,y,z and
315// defined at the focal distance F. It can be used to overwrite
316// the second argument given in ReadFile for individual mirrors.
317// Type: A instance of a mirrot of the class Type MMirrorType is created
318// (Type can be, for example, Hex for for MMirrorHex).
319// ...: Additional arguments as defined in MMirrorType::ReadM
320//
321//
322// Coordinate System:
323// The coordinate system is local in the reflectors frame.
324// It is defined viewing from the back side of the reflector
325// towards the camera. (x "right", y "up", z from reflector to camera)
326// Note, that it is left-handed!
327//
328Bool_t MLens::ReadFile(TString fname, Double_t defpsf)
329{
330 SetTitle(fname);
331 fMirrors.Delete();
332
333 gSystem->ExpandPathName(fname);
334
335 ifstream fin(fname);
336 if (!fin)
337 {
338 *fLog << err << "Cannot open file " << fname << ": ";
339 *fLog << (errno!=0?strerror(errno):"Insufficient memory for decompression") << endl;
340 return kFALSE;
341 }
342
343/*
344 Int_t idx[964];
345 Int_t srt[964];
346 for (int i=0; i<964; i++)
347 srt[i] = gRandom->Integer(964);
348
349 TMath::Sort(964, srt, idx);
350 */
351
352 Int_t cnt = 0;
353
354 while (1)
355 {
356 TString line;
357 line.ReadLine(fin);
358 if (!fin)
359 break;
360
361 // Count lines
362 cnt++;
363
364 // Skip comments
365 if (line.BeginsWith("#"))
366 continue;
367
368 // Remove leading and trailing whitespaces
369 line=line.Strip(TString::kBoth);
370
371 // Skip empty lines
372 if (line.IsNull())
373 continue;
374
375 // Tokenize line
376 TObjArray *arr = line.Tokenize(' ');
377
378 // Evaluate tokens
379 MMirror *m = EvalTokens(*arr, defpsf);
380
381 // Delete now obsolete array
382 delete arr;
383
384 // Check if a new mirror could be created successfully
385 if (!m)
386 {
387 *fLog << err << "Error in line " << cnt << ": " << line << endl;
388 return kFALSE;
389 }
390
391 // Add new mirror to array
392 fMirrors.Add(m);
393 }
394
395 InitMaxR();
396
397 return kTRUE;
398
399// fMirrors.Sort();
400/*
401 for (int i=0; i<964; i++)
402 {
403 MMirror &ref = (MMirror&)*fMirrors[i];
404
405 TArrayD dist(964);
406 for (int j=0; j<964; j++)
407 {
408 const MMirror &mir = (MMirror&)*fMirrors[j];
409 dist[j] = (ref-mir).Mod();
410 }
411
412 TArrayI idx(964);
413 TMath::Sort(964, dist.GetArray(), idx.GetArray(), kFALSE);
414
415 for (int j=0; j<964; j++)
416 {
417 ref.fNeighbors.Add(fMirrors[idx[j]]);
418 }
419 }*/
420}
421
422// ------------------------------------------------------------------------
423//
424Bool_t MLens::WriteFile(TString fname) const
425{
426 gSystem->ExpandPathName(fname);
427
428 ofstream fout(fname);
429 if (!fout)
430 {
431 *fLog << err << "Cannot open file " << fname << ": ";
432 *fLog << (errno!=0?strerror(errno):"Insufficient memory for decompression") << endl;
433 return kFALSE;
434 }
435
436 TIter Next(&fMirrors);
437 MMirror *m = 0;
438 while ((m=static_cast<MMirror*>(Next())))
439 {
440 // x: x-coordinate of the mirror's center
441 // y: y-coordinate of the mirror's center
442 // z: z-coordinate of the mirror's center
443 // nx: x-component of the normal vecor in the mirror center
444 // ny: y-component of the normal vecor in the mirror center
445 // nz: z-component of the normal vecor in the mirror center
446 // [shape]: S for spherical <default>, P for parabolic
447 // F: Focal distance of a spherical mirror
448 // [psf]: This number is the psf given in the units of x,y,z and
449 // defined at the focal distance F. It can be used to overwrite
450 // the second argument given in ReadFile for individual mirrors.
451 // Type: A instance of a mirrot of the class Type MMirrorType is created
452 // (Type can be, for example, Hex for for MMirrorHex).
453 // ...: Additional arguments as defined in MMirrorType::ReadM
454
455 fout << setw(12) << m->X() << " ";
456 fout << setw(12) << m->Y() << " ";
457 fout << setw(12) << m->Z() << " ";
458 fout << setw(12) << m->Nx() << " ";
459 fout << setw(12) << m->Ny() << " ";
460 fout << setw(12) << m->Nz() << " ";
461 if (m->GetShape()==1)
462 fout << "P ";
463 fout << m->GetFocalLength() << " ";
464 // cout << m->GetSigmaPSF() << " ";
465 fout << m->ClassName()+7 << " ";
466 m->WriteM(fout);
467 fout << endl;
468 }
469 return kTRUE;
470}
471
472// --------------------------------------------------------------------------
473//
474// Print the collection of mirrors
475//
476void MLens::Print(Option_t *o) const
477{
478 *fLog << all << GetDescriptor() << " (" << GetNumMirrors() << "): " << endl;
479
480 fMirrors.Print(o);
481}
482
483// --------------------------------------------------------------------------
484//
485// Paint the collection of mirrors
486//
487void MLens::Paint(Option_t *o)
488{
489 if (!TString(o).Contains("same", TString::kIgnoreCase))
490 MH::SetPadRange(-fMaxR*1.01, -fMaxR*1.01, fMaxR*1.01, fMaxR*1.01);
491
492 fMirrors.Paint(o);
493
494 TEllipse e;
495 e.SetFillStyle(0);
496 e.SetLineColor(17);
497 e.PaintEllipse(0, 0, fMaxR, fMaxR, 0, 360, 0);
498}
499
500// --------------------------------------------------------------------------
501//
502// SigmaPSF: -1
503// FileName: reflector.txt
504//
505// SigmaPSF can be used to set a default for the psf of the mirrors
506// read from the file. Note, that this can be overwritten for individual
507// mirrors in the file. The SigmaPSF is the sigma of a 1D-Gauss fitted
508// to the radial profile of the light distribution.
509//
510// For details on the file structure see MLens::ReadFile
511//
512Int_t MLens::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
513{
514 Bool_t rc = kFALSE;
515
516 Double_t psf = -1;
517 if (IsEnvDefined(env, prefix, "SetSigmaPSF", print))
518 {
519 rc = kTRUE;
520 psf = GetEnvValue(env, prefix, "SetSigmaPSF", -1);
521 }
522
523 if (IsEnvDefined(env, prefix, "FileName", print))
524 {
525 rc = kTRUE;
526 if (!ReadFile(GetEnvValue(env, prefix, "FileName", ""), psf))
527 return kERROR;
528 }
529
530 return rc;
531}
Note: See TracBrowser for help on using the repository browser.