/[PAMELA software]/DarthVader/OrbitalInfo/src/OrbitalInfoCore.cpp
ViewVC logotype

Contents of /DarthVader/OrbitalInfo/src/OrbitalInfoCore.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.7 - (show annotations) (download)
Tue Jan 23 11:52:35 2007 UTC (18 years, 10 months ago) by mocchiut
Branch: MAIN
Changes since 1.6: +151 -12 lines
OrbitalInfo updated, small changes in calo code

1 //
2 // C/C++ headers
3 //
4 #include <fstream>
5 #include <string.h>
6 #include <iostream>
7 #include <cstring>
8 #include <stdio.h>
9 //
10 // ROOT headers
11 //
12 #include <TTree.h>
13 #include <TClassEdit.h>
14 #include <TObject.h>
15 #include <TList.h>
16 #include <TArrayI.h>
17 #include <TSystem.h>
18 #include <TSystemDirectory.h>
19 #include <TString.h>
20 #include <TFile.h>
21 #include <TClass.h>
22 #include <TSQLServer.h>
23 #include <TSQLRow.h>
24 #include <TSQLResult.h>
25 //
26 // YODA headers
27 //
28 #include <PamelaRun.h>
29 #include <PscuHeader.h>
30 #include <PscuEvent.h>
31 #include <EventHeader.h>
32 //
33 // RunInfo header
34 //
35 #include <RunInfo.h>
36 #include <GLTables.h>
37 //
38 // This program headers
39 //
40 #include <OrbitalInfo.h>
41 #include <OrbitalInfoVerl2.h>
42 #include <OrbitalInfoCore.h>
43
44 using namespace std;
45
46 //
47 // CORE ROUTINE
48 //
49 //
50 int OrbitalInfoCore(UInt_t run, TFile *file, TSQLServer *dbc, Int_t OrbitalInfoargc, char *OrbitalInfoargv[]){
51
52 // // Temporary check to use igrf routines. We need dat files in the
53 // // current directory.
54 // fstream igrfdat1("igrf05.dat");
55 // fstream igrfdat2("igrf05s.dat");
56 // if( (!igrfdat1) && (!igrfdat2)) {
57 // cerr<<"\n**************************************\n"
58 // <<"igrf05.dat or igrf05s.dat not in the current directory. Exiting.\n"
59 // <<"**************************************\n";
60 // exit(EXIT_FAILURE);
61 // }
62 // igrfdat1.close();
63 // igrfdat2.close();
64 // // end of temporary code
65 // //
66
67 Int_t i = 0;
68 //
69 TString processFolder = "OrbitalInfoFolder";
70 //
71 // Set these to true to have a very verbose output.
72 //
73 Bool_t debug = false;
74 //
75 Bool_t verbose = false;
76
77 if ( OrbitalInfoargc > 0 ){
78 i = 0;
79 while ( i < OrbitalInfoargc ){
80 if ( !strcmp(OrbitalInfoargv[i],"-processFolder") ) {
81 if ( OrbitalInfoargc < i+1 ){
82 throw -3;
83 };
84 processFolder = (TString)OrbitalInfoargv[i+1];
85 i++;
86 };
87 if ( (!strcmp(OrbitalInfoargv[i],"--debug")) || (!strcmp(OrbitalInfoargv[i],"-g")) ) {
88 verbose = true;
89 };
90 if ( (!strcmp(OrbitalInfoargv[i],"--verbose")) || (!strcmp(OrbitalInfoargv[i],"-v")) ) {
91 verbose = true;
92 };
93 i++;
94 };
95 };
96 //
97 const char* outDir = gSystem->DirName(gSystem->DirName(file->GetPath()));
98 //
99 TTree *OrbitalInfotr = 0;
100 UInt_t nevents = 0;
101 //
102 // variables needed to reprocess data
103 //
104 Long64_t maxsize = 10000000000LL;
105 TTree::SetMaxTreeSize(maxsize);
106 //
107 TString OrbitalInfoversion;
108 ItoRunInfo *runinfo = 0;
109 TArrayI *runlist = 0;
110 TTree *OrbitalInfotrclone = 0;
111 Bool_t reproc = false;
112 Bool_t reprocall = false;
113 UInt_t nobefrun = 0;
114 UInt_t noaftrun = 0;
115 UInt_t numbofrun = 0;
116 stringstream ftmpname;
117 TString fname;
118 UInt_t totfileentries = 0;
119 UInt_t idRun = 0;
120 //
121 // variables needed to handle error signals
122 //
123 Int_t code = 0;
124 Int_t sgnl;
125 //
126 // OrbitalInfo classes
127 //
128 OrbitalInfo *orbitalinfo = new OrbitalInfo();
129 OrbitalInfo *orbitalinfoclone = new OrbitalInfo();
130 //
131 // define variables for opening and reading level0 file
132 //
133 TFile *l0File = 0;
134 TTree *l0tr = 0;
135 // EM: open also header branch
136 TBranch *l0head = 0;
137 pamela::EventHeader *eh = 0;
138 pamela::PscuHeader *ph = 0;
139 // end EM
140 //
141 // Define other basic variables
142 //
143 UInt_t procev = 0;
144 stringstream file2;
145 stringstream file3;
146 stringstream qy;
147 Int_t totevent = 0;
148 UInt_t atime = 0;
149 UInt_t re = 0;
150
151 // Position
152 Float_t lon, lat, alt;
153
154 //
155 // IGRF stuff
156 //
157 float dimo = 0.0; // dipole moment (computed from dat files)
158 float bnorth, beast, bdown, babs;
159 float xl; // L value
160 float icode; // code value for L accuracy (see fortran code)
161 float bab1; // What's the difference with babs?
162 float stps = 0.005; // step size for field line tracing
163 float bdel = 0.01; // required accuracy
164 float bequ; // equatorial b value (also called b_0)
165 bool value = 0; // false if bequ is not the minimum b value
166 float rr0; // equatorial radius normalized to earth radius
167
168 //
169 // Working filename
170 //
171 TString outputfile;
172 stringstream name;
173 name.str("");
174 name << outDir << "/";
175 //
176 // temporary file and folder
177 //
178 TFile *tempfile = 0;
179 TTree *tempOrbitalInfo = 0;
180 stringstream tempname;
181 stringstream OrbitalInfofolder;
182 tempname.str("");
183 tempname << outDir;
184 tempname << "/" << processFolder.Data();
185 OrbitalInfofolder.str("");
186 OrbitalInfofolder << tempname.str().c_str();
187 gSystem->MakeDirectory(OrbitalInfofolder.str().c_str());
188 tempname << "/OrbitalInfotree_run";
189 tempname << run << ".root";
190 //
191 // DB classes
192 //
193 GL_ROOT *glroot = new GL_ROOT();
194 GL_TIMESYNC *dbtime = 0;
195 GL_TLE *gltle = new GL_TLE();
196 // Initialize fortran routines!!!
197 Int_t ltp2 = 0;
198 Int_t ltp3 = 0;
199 Int_t uno = 1;
200 char *niente = " ";
201 GL_PARAM *glparam = new GL_PARAM();
202 Int_t parerror=glparam->Query_GL_PARAM(1,301,dbc); // parameters stored in DB in GL_PRAM table
203 if ( parerror<0 ) {
204 code = parerror;
205 goto closeandexit;
206 };
207 ltp2 = (Int_t)(glparam->PATH+glparam->NAME).Length();
208 if ( verbose ) printf(" Reading Earth's Magnetic Field parameter file: %s \n",(glparam->PATH+glparam->NAME).Data());
209 //
210 GL_PARAM *glparam2 = new GL_PARAM();
211 parerror=glparam2->Query_GL_PARAM(1,302,dbc); // parameters stored in DB in GL_PRAM table
212 if ( parerror<0 ) {
213 code = parerror;
214 goto closeandexit;
215 };
216 ltp3 = (Int_t)(glparam2->PATH+glparam2->NAME).Length();
217 if ( verbose ) printf(" Reading Earth's Magnetic Field parameter file: %s \n",(glparam2->PATH+glparam2->NAME).Data());
218 //
219 initize_((char *)niente,&uno,(char *)(glparam->PATH+glparam->NAME).Data(),&ltp2,(char *)(glparam2->PATH+glparam2->NAME).Data(),&ltp3);
220
221 //
222 // End IGRF stuff//
223 //
224
225 //
226 // Let's start!
227 //
228 // As a first thing we must check what we have to do: if run = 0 we must process all events in the file has been passed
229 // if run != 0 we must process only that run but first we have to check if the tree MyDetector2 already exist in the file
230 // if it exists we are reprocessing data and we must delete that entries, if not we must create it.
231 //
232 if ( run == 0 ) reproc = true;
233 //
234 //
235 // Output file is "outputfile"
236 //
237 if ( !file->IsOpen() ){
238 //printf(" OrbitalInfo - ERROR: cannot open file for writing\n");
239 throw -901;
240 };
241 //
242 // Retrieve GL_RUN variables from the level2 file
243 //
244 OrbitalInfoversion = OrbitalInfoInfo(false); // we should decide how to handle versioning system
245 //
246 // create an interface to RunInfo called "runinfo"
247 //
248 runinfo = new ItoRunInfo(file);
249 //
250 // open "Run" tree in level2 file, if not existing return an error (sngl != 0)
251 //
252 sgnl = 0;
253 sgnl = runinfo->Update(run, "ORB", OrbitalInfoversion);
254 //sgnl = runinfo->Read(run);
255
256 if ( sgnl ){
257 //printf("OrbitalInfo - ERROR: RunInfo exited with non-zero status\n");
258 code = sgnl;
259 goto closeandexit;
260 } else {
261 sgnl = 0;
262 };
263 //
264 // number of events in the file BEFORE the first event of our run
265 //
266 nobefrun = runinfo->GetFirstEntry();
267 //
268 // total number of events in the file
269 //
270 totfileentries = runinfo->GetFileEntries();
271 //
272 // first file entry AFTER the last event of our run
273 //
274 noaftrun = runinfo->GetLastEntry() + 1;
275 //
276 // number of run to be processed
277 //
278 numbofrun = runinfo->GetNoRun();
279 //
280 // Try to access the OrbitalInfo tree in the file, if it exists we are reprocessing data if not we are processing a new run
281 //
282 OrbitalInfotrclone = (TTree*)file->Get("OrbitalInfo");
283 //
284 if ( !OrbitalInfotrclone ){
285 //
286 // tree does not exist, we are not reprocessing
287 //
288 reproc = false;
289 if ( run == 0 ){
290 if (verbose) printf(" OrbitalInfo - WARNING: you are reprocessing data but OrbitalInfo tree does not exist!\n");
291 }
292 if ( runinfo->IsReprocessing() && run != 0 ) {
293 if (verbose) printf(" OrbitalInfo - WARNING: it seems you are not reprocessing data but OrbitalInfo\n versioning information already exists in RunInfo.\n");
294 }
295 } else {
296 //
297 // tree exists, we are reprocessing data. Are we reprocessing a single run or all the file?
298 //
299 OrbitalInfotrclone->SetAutoSave(900000000000000LL);
300 reproc = true;
301 //
302 //
303 if (verbose) printf("\n Preparing the pre-processing...\n");
304 //
305 if ( run == 0 ){
306 //
307 // we are reprocessing all the file
308 // if we are reprocessing everything we don't need to copy any old event and we can just work with the new tree and delete the old one immediately
309 //
310 reprocall = true;
311 //
312 if (verbose) printf("\n OrbitalInfo - WARNING: Reprocessing all runs\n");
313 //
314 } else {
315 //
316 // we are reprocessing a single run, we must copy to the new tree the events in the file which preceed the first event of the run
317 //
318 reprocall = false;
319 //
320 if (verbose) printf("\n OrbitalInfo - WARNING: Reprocessing run number %u \n",run);
321 //
322 // copying old tree to a new file
323 //
324 tempfile = new TFile(tempname.str().c_str(),"RECREATE");
325 tempOrbitalInfo = OrbitalInfotrclone->CloneTree(-1,"fast");
326 tempOrbitalInfo->SetName("OrbitalInfo-old");
327 tempfile->Write();
328 tempfile->Close();
329 }
330 //
331 // Delete the old tree from old file and memory
332 //
333 OrbitalInfotrclone->Delete("all");
334 //
335 if (verbose) printf(" ...done!\n");
336 //
337 };
338 //
339 // create mydetector tree mydect
340 //
341 file->cd();
342 OrbitalInfotr = new TTree("OrbitalInfo-new","PAMELA OrbitalInfo data");
343 OrbitalInfotr->SetAutoSave(900000000000000LL);
344 OrbitalInfotr->Branch("OrbitalInfo","OrbitalInfo",&orbitalinfo);
345 //
346 if ( reproc && !reprocall ){
347 //
348 // open new file and retrieve also tree informations
349 //
350 tempfile = new TFile(tempname.str().c_str(),"READ");
351 OrbitalInfotrclone = (TTree*)tempfile->Get("OrbitalInfo-old");
352 OrbitalInfotrclone->SetAutoSave(900000000000000LL);
353 OrbitalInfotrclone->SetBranchAddress("OrbitalInfo",&orbitalinfoclone);
354 //
355 if ( nobefrun > 0 ){
356 if (verbose){
357 printf("\n Pre-processing: copying events from the old tree before the processed run\n");
358 printf(" Copying %u events in the file which are before the beginning of the run %u \n",nobefrun,run);
359 printf(" Start copying at event number 0, end copying at event number %u \n",nobefrun);
360 }
361 for (UInt_t j = 0; j < nobefrun; j++){
362 //
363 OrbitalInfotrclone->GetEntry(j);
364 //
365 // copy orbitalinfoclone to mydec
366 //
367 orbitalinfo->Clear();
368 //
369 memcpy(&orbitalinfo,&orbitalinfoclone,sizeof(orbitalinfoclone));
370 //
371 // Fill entry in the new tree
372 //
373 OrbitalInfotr->Fill();
374 //
375 };
376 if (verbose) printf(" Finished successful copying!\n");
377 };
378 };
379 //
380 // Get the list of run to be processed, if only one run has to be processed the list will contain one entry only.
381 //
382 runlist = runinfo->GetRunList();
383 //
384 // Loop over the run to be processed
385 //
386 for (UInt_t irun=0; irun < numbofrun; irun++){
387 //
388 // retrieve the first run ID to be processed using the RunInfo list
389 //
390 idRun = runlist->At(irun);
391 if (verbose){
392 printf("\n\n\n ####################################################################### \n");
393 printf(" PROCESSING RUN NUMBER %i \n",(int)idRun);
394 printf(" ####################################################################### \n\n\n");
395 }
396 //
397 runinfo->ID_ROOT_L0 = 0;
398 //
399 // store in the runinfo class the GL_RUN variables for our run
400 //
401 sgnl = 0;
402 sgnl = runinfo->GetRunInfo(idRun);
403 if ( sgnl ){
404 if ( debug ) printf("\n OrbitalInfo - ERROR: RunInfo exited with non-zero status\n");
405 code = sgnl;
406 goto closeandexit;
407 } else {
408 sgnl = 0;
409 };
410 //
411 // now you can access that variables using the RunInfo class this way runinfo->ID_REG_RUN
412 //
413 if ( runinfo->ID_ROOT_L0 == 0 ){
414 if ( debug ) printf("\n OrbitalInfo - ERROR: no run with ID_RUN = %u \n\n Exiting... \n\n",idRun);
415 code = -5;
416 goto closeandexit;
417 };
418 //
419 // prepare the timesync for the db
420 //
421 dbtime = new GL_TIMESYNC(runinfo->ID_ROOT_L0,"ID",dbc);
422 //
423 // Search in the DB the path and name of the LEVEL0 file to be processed.
424 //
425 glroot->Query_GL_ROOT(runinfo->ID_ROOT_L0,dbc);
426 //
427 ftmpname.str("");
428 ftmpname << glroot->PATH.Data() << "/";
429 ftmpname << glroot->NAME.Data();
430 fname = ftmpname.str().c_str();
431 //
432 // print out informations
433 //
434 totevent = runinfo->NEVENTS;
435 if (verbose){
436 printf("\n LEVEL0 data file: %s \n",fname.Data());
437 printf(" RUN HEADER absolute time is: %u \n",runinfo->RUNHEADER_TIME);
438 printf(" RUN TRAILER absolute time is: %u \n",runinfo->RUNTRAILER_TIME);
439 printf(" %i events to be processed for run %u: from %i to %i \n\n",totevent,idRun,runinfo->EV_FROM,runinfo->EV_FROM+totevent);
440 }//
441 // Open Level0 file
442 l0File = new TFile(fname.Data());
443 if ( !l0File ) {
444 if ( debug ) printf(" OrbitalInfo - ERROR: problems opening Level0 file\n");
445 code = -6;
446 goto closeandexit;
447 };
448 l0tr = (TTree*)l0File->Get("Physics");
449 if ( !l0tr ) {
450 if ( debug ) printf(" OrbitalInfo - ERROR: no Physics tree in Level0 file\n");
451 l0File->Close();
452 code = -7;
453 goto closeandexit;
454 };
455 // EM: open header branch as well
456 l0head = l0tr->GetBranch("Header");
457 if ( !l0head ) {
458 if ( debug ) printf(" OrbitalInfo - ERROR: no Header branch in Level0 tree\n");
459 l0File->Close();
460 code = -8;
461 goto closeandexit;
462 };
463 l0tr->SetBranchAddress("Header", &eh);
464 // end EM
465 nevents = l0head->GetEntries();
466 //
467 if ( nevents < 1 ) {
468 if ( debug ) printf(" OrbitalInfo - ERROR: Level0 file is empty\n\n");
469 l0File->Close();
470 code = -11;
471 goto closeandexit;
472 };
473 //
474 if ( runinfo->EV_TO > nevents-1 ) {
475 if ( debug ) printf(" OrbitalInfo - ERROR: too few entries in the registry tree\n");
476 l0File->Close();
477 code = -12;
478 goto closeandexit;
479 };
480 //
481 // run over all the events of the run
482 //
483 if (verbose) printf("\n Ready to start! \n\n Processed events: \n\n");
484 //
485 for ( re = runinfo->EV_FROM; re < (runinfo->EV_FROM+runinfo->NEVENTS); re++){
486 //
487 if ( procev%1000 == 0 && procev > 0 && verbose ) printf(" %iK \n",procev/1000);
488 //
489 l0head->GetEntry(re);
490 //
491 // absolute time of this event
492 //
493 ph = eh->GetPscuHeader();
494 atime = dbtime->DBabsTime(ph->GetOrbitalTime());
495 //
496 // paranoid check
497 //
498 if ( (atime > runinfo->RUNTRAILER_TIME) || (atime < runinfo->RUNHEADER_TIME) ) {
499 if (verbose) printf(" OrbitalInfo - WARNING: event at time outside the run time window, skipping it\n");
500 debug = true;
501 continue;
502 }
503 //
504 procev++;
505 //
506 // start processing
507 //
508 orbitalinfo->Clear();
509 //
510 // CHANGE HERE!!!!
511 //
512 orbitalinfo->absTime = atime;
513 // EM: add OBT and plt_num infos from the header
514 ph = eh->GetPscuHeader();
515 orbitalinfo->pkt_num = ph->GetCounter();
516 orbitalinfo->OBT = ph->GetOrbitalTime();
517
518 // If the absolute time of the event overpass the time of the
519 // tle, get a new tle. GL_TLE::GetToTime() default to zero.
520 //
521 // I also use this condition to compute the dipole moment dimo.
522 // It's really redundant to compute it so often because
523 // probably it will not change at all. But the overhead is
524 // minimum.
525 float jyear=0;
526
527 if(atime >= gltle->GetToTime()) {
528 gltle->Query(atime, dbc);
529
530 // Compute the magnetic dipole moment.
531 UInt_t year, month, day, hour, min, sec;
532
533 TTimeStamp t = TTimeStamp(atime, kTRUE);
534 t.GetDate(kTRUE, 0, &year, &month, &day);
535 t.GetTime(kTRUE, 0, &hour, &min, &sec);
536 jyear = (float) year
537 + (month*31.+ (float) day)/365.
538 + (hour*3600.+min*60.+(float)sec)/(24*3600*365.);
539
540 feldcof_(&jyear, &dimo); // get dipole moment for year
541 }
542
543 // Propagate the orbit from the tle time to atime, using SGP(D)4.
544 cCoordGeo coo = getCoo(atime, gltle->GetFromTime(), gltle->GetTle());
545
546 // Build coordinates in the right range. We want to convert,
547 // longitude from (0, 2*pi) to (-180deg, 180deg). Altitude is
548 // in meters.
549 lon = (coo.m_Lon > M_PI) ? rad2deg(coo.m_Lon - 2*M_PI) : rad2deg(coo.m_Lon);
550 lat = rad2deg(coo.m_Lat);
551 alt = coo.m_Alt;
552
553
554 // if((lon>180) || (lon<-180) || (lat>90) || (lat<-90) || (alt<0))
555 // continue;
556 if( lon<180 && lon>-180 && lat<90 && lat>-90 && alt>0 ){
557
558 orbitalinfo->lon = lon;
559 orbitalinfo->lat = lat;
560 orbitalinfo->alt = alt ;
561
562 // compute mag field components and L shell.
563 feldg_(&lat, &lon, &alt, &bnorth, &beast, &bdown, &babs);
564 shellg_(&lat, &lon, &alt, &dimo, &xl, &icode, &bab1);
565 findb0_(&stps, &bdel, &value, &bequ, &rr0);
566
567 orbitalinfo->Bnorth = bnorth;
568 orbitalinfo->Beast = beast;
569 orbitalinfo->Bdown = bdown;
570 orbitalinfo->Babs = babs;
571 orbitalinfo->BB0 = babs/bequ;
572 orbitalinfo->L = xl;
573
574 // Set Stormer vertical cutoff using L shell.
575 orbitalinfo->cutoff[0] = 14.9/(xl*xl);
576 };
577
578 // end EM
579 OrbitalInfotr->Fill();
580 }
581
582 //
583 // Here you may want to clear some variables before processing another run
584 //
585 delete dbtime;
586 }; // process all the runs
587 //
588 if (verbose) printf("\n Finished processing data \n");
589 //
590 closeandexit:
591 //
592 // we have finished processing the run(s). If we processed a single run now we must copy all the events after our run from the old tree to the new one and delete the old tree.
593 //
594 if ( !reprocall && reproc && code >= 0 ){
595 if ( totfileentries > noaftrun ){
596 if (verbose){
597 printf("\n Post-processing: copying events from the old tree after the processed run\n");
598 printf(" Copying %i events in the file which are after the end of the run %i \n",(int)(totfileentries-noaftrun),(int)run);
599 printf(" Start copying at event number %i end copying at event number %i \n",(int)noaftrun,(int)totfileentries);
600 }
601 for (UInt_t j = noaftrun; j < totfileentries; j++ ){
602 //
603 // Get entry from old tree
604 //
605 OrbitalInfotrclone->GetEntry(j);
606 //
607 // copy orbitalinfoclone to OrbitalInfo
608 //
609 orbitalinfo->Clear();
610 //
611 memcpy(&orbitalinfo,&orbitalinfoclone,sizeof(orbitalinfoclone));
612 //
613 // Fill entry in the new tree
614 //
615 OrbitalInfotr->Fill();
616 };
617 if (verbose) printf(" Finished successful copying!\n");
618 };
619 };
620 //
621 // Close files, delete old tree(s), write and close level2 file
622 //
623 if ( l0File ) l0File->Close();
624 if ( tempfile ) tempfile->Close();
625 gSystem->Unlink(tempname.str().c_str());
626 //
627 if ( runinfo ) runinfo->Close();
628 if ( OrbitalInfotr ) OrbitalInfotr->SetName("OrbitalInfo");
629 if ( file ){
630 file->cd();
631 file->Write();
632 };
633 //
634 gSystem->Unlink(OrbitalInfofolder.str().c_str());
635 //
636 // the end
637 //
638 if (verbose) printf("\n Exiting...\n");
639 if(OrbitalInfotr)OrbitalInfotr->Delete();
640 //
641 if ( orbitalinfo ) delete orbitalinfo;
642 if ( orbitalinfoclone ) delete orbitalinfoclone;
643 if ( glroot ) delete glroot;
644 if ( runinfo ) delete runinfo;
645 //
646 if(code < 0) throw code;
647 return(code);
648 }
649
650
651 //
652 // Returns the cCoordGeo structure holding the geographical
653 // coordinates for the event (see sgp4.h).
654 //
655 // atime is the abstime of the event in UTC unix time.
656 // tletime is the time of the tle in UTC unix time.
657 // tle is the previous and nearest tle (compared to atime).
658 cCoordGeo getCoo(UInt_t atime, UInt_t tletime, cTle *tle)
659 {
660 cEci eci;
661 cOrbit orbit(*tle);
662
663 orbit.getPosition((double) (atime - tletime)/60., &eci);
664
665 return eci.toGeo();
666 }

  ViewVC Help
Powered by ViewVC 1.1.23