]> git.uio.no Git - u/mrichter/AliRoot.git/blob - PWG2/SPECTRA/AliAnalysisTaskCentral.cxx
Small correction for AnalysisTaskCentral and corresponding AddTask macro (C.Andrei)
[u/mrichter/AliRoot.git] / PWG2 / SPECTRA / AliAnalysisTaskCentral.cxx
1 /*************************************************************************
2 * Copyright(c) 1998-2008, ALICE Experiment at CERN, All rights reserved. *
3 *                                                                        *
4 * Author: The ALICE Off-line Project.                                    *
5 * Contributors are mentioned in the code where appropriate.              *
6 *                                                                        *
7 * Permission to use, copy, modify and distribute this software and its   *
8 * documentation strictly for non-commercial purposes is hereby granted   *
9 * without fee, provided that the above copyright notice appears in all   *
10 * copies and that both the copyright notice and this permission notice   *
11 * appear in the supporting documentation. The authors make no claims     *
12 * about the suitability of this software for any purpose. It is          *
13 * provided "as is" without express or implied warranty.                  *
14 **************************************************************************/
15
16 //  ------------------------------------------
17 //  analysis task for azimuthal isotropic
18 //  expansion in highly central collisions
19 //  author: Cristian Andrei
20 //          acristian@niham.nipne.ro
21 //  ------------------------------------------
22
23 #include "TChain.h"
24 #include "TTree.h"
25 #include "TH1D.h"
26 #include "TList.h"
27 #include "TObjArray.h"
28 #include "TString.h"
29 #include "TFile.h"
30 #include "TCanvas.h"
31 #include "TLegend.h"
32
33 #include "AliAnalysisManager.h"
34 #include "AliMCEvent.h"
35 #include "AliMCEventHandler.h"
36 #include "AliESDEvent.h"
37 #include "AliESDInputHandler.h"
38 #include "AliESDtrackCuts.h"
39 #include "AliCFContainer.h"
40 #include "AliAnalysisDataContainer.h"
41 #include "AliAnalysisDataSlot.h"
42
43 #include "AliAnalysisCentralCutMC.h"
44 #include "AliAnalysisCentralCutESD.h"
45 #include "AliAnalysisCentralCutEvtMC.h"
46 #include "AliAnalysisCentralCutEvtESD.h"
47 #include "AliAnalysisCentralExtrapolate.h"
48 #include "AliAnalysisTaskCentral.h"
49
50
51 ClassImp(AliAnalysisTaskCentral)
52
53
54 //________________________________________________________________________
55 AliAnalysisTaskCentral::AliAnalysisTaskCentral(const char *name) 
56   : AliAnalysisTask(name, "")
57   ,fESD(0), fMC(0)
58   ,fNoEvt(0)
59   ,fCFContainerPi(0)
60   ,fCFContainerK(0)
61   ,fCFContainerP(0)
62   ,fSim(kFALSE)
63   ,fOutList(NULL)
64
65 {
66   // Constructor
67         printf("AliAnalysisTaskCentral::AliAnalysisTaskCentral(const char *name)\n");
68
69   // Define input and output slots here
70         DefineInput(0, TChain::Class());
71
72         DefineOutput(0, TList::Class()); 
73
74
75         for(Int_t i=0; i<10; i++){
76                 fCutsList[i] = 0;
77     }
78
79         InitCuts(); //initialize the analysis specific cuts     
80     if (!fCutsList) {
81                 Printf("ERROR: fCutsList not available");
82                 return;
83     }
84
85 }
86
87
88 //________________________________________________________________________
89 AliAnalysisTaskCentral::~AliAnalysisTaskCentral() 
90 {
91 // Destructor
92 // Delete the created objects
93
94         if(fESD) delete fESD;
95         if(fMC) delete fMC;
96
97         if(fCutsList){ 
98         delete [] fCutsList;
99         }
100
101         if(fNoEvt) delete fNoEvt;
102
103         if(fCFContainerPi) delete fCFContainerPi;
104         if(fCFContainerPi) delete fCFContainerK;
105         if(fCFContainerPi) delete fCFContainerP;
106
107         if(fOutList) delete fOutList;
108
109
110 }
111
112 //________________________________________________________________________
113 void AliAnalysisTaskCentral::ConnectInputData(Option_t *) {
114 // get the event from the input chain
115
116     TTree* tree = dynamic_cast<TTree*> (GetInputData(0));
117         printf("tree(%p)\n", (void*)tree);
118
119     if (!tree) {
120         Printf("ERROR: Could not read chain from input slot 0");
121     } else {
122         AliESDInputHandler *esdH = dynamic_cast<AliESDInputHandler*> (AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler());
123         if (!esdH) {
124             Printf("ERROR: Could not get ESDInputHandler");
125         }
126         else fESD = esdH->GetEvent();
127
128         AliMCEventHandler *mcH = (AliMCEventHandler*) ((AliAnalysisManager::GetAnalysisManager())->GetMCtruthEventHandler());
129         if (!mcH) {
130             Printf("ERROR: Could not get MCInputHandler");
131             fSim = kFALSE;
132         }
133         else{
134             fMC = mcH->MCEvent();
135             fSim = kTRUE;
136         }
137     }
138 }
139
140 //________________________________________________________________________
141 void AliAnalysisTaskCentral::CreateOutputObjects(){
142 //Creates the output list
143
144 //      fNoEvt = new TH1F(Form("%s_NoEvt",GetName()), "Number of processed events", 1, 0.0, 1.0);
145
146         fNoEvt = new TH1D("TaskCentral_NoEvt", "Number of processed events", 1, 0.0, 1.0);
147 //set here the min and max variable values (to do: move these to a separate cuts class)
148     const Double_t ptmin  = 0.0 ; //bins in pt
149     const Double_t ptmax  = 5.0 ; //bins in y
150     const Double_t etamin  = -0.9 ; //bins in pt
151     const Double_t etamax  = 0.9 ; //bins in y
152     //apropiate number of bins for histos and CF Container
153     const Int_t nbinpt  = 25 ; //bins in pt
154     const Int_t nbineta  = 25 ; //bins in y
155
156 //Correction Framework CONTAINER DEFINITION
157     //the sensitive variables, their indices
158         UInt_t ipt = 0;
159         UInt_t ieta  = 1;
160     //Setting up the container grid...
161     const UInt_t nstep = 2 ; //number of selection steps MC & ESD 
162     const Int_t nvar = 2 ; //number of variables on the grid:pt,eta
163
164     //arrays for the number of bins in each dimension
165     //nbin is defined above
166     Int_t iBin[nvar];
167     iBin[0]=nbinpt;
168     iBin[1]=nbineta;
169
170     //arrays for lower bounds :
171     Double_t *binLim1=new Double_t[nbinpt+1];
172     Double_t *binLim2=new Double_t[nbineta+1];
173
174     //values for bin lower bounds
175     for(Int_t i=0; i<=nbinpt; i++) binLim1[i]=(Double_t)ptmin + (ptmax-ptmin)/nbinpt*(Double_t)i ;
176     for(Int_t i=0; i<=nbineta; i++) binLim2[i]=(Double_t)etamin  + (etamax-etamin)  /nbineta*(Double_t)i ;
177
178         //container creation
179         fCFContainerPi = new AliCFContainer("TaskCentral_CFCont_Pi","container for tracks",nstep,nvar,iBin);
180         fCFContainerK = new AliCFContainer("TaskCentral_CFCont_K","container for tracks",nstep,nvar,iBin);
181         fCFContainerP = new AliCFContainer("TaskCentral_CFCont_P","container for tracks",nstep,nvar,iBin);
182
183     //setting the bin limits
184     fCFContainerPi -> SetBinLimits(ipt,binLim1);
185     fCFContainerPi -> SetBinLimits(ieta,binLim2);
186
187         fCFContainerK -> SetBinLimits(ipt,binLim1);
188         fCFContainerK -> SetBinLimits(ieta,binLim2);
189
190         fCFContainerP -> SetBinLimits(ipt,binLim1);
191         fCFContainerP -> SetBinLimits(ieta,binLim2);
192
193 //outout list creation
194         fOutList = new TList();
195         fOutList->Add(fNoEvt);
196         fOutList->Add(fCFContainerPi);
197         fOutList->Add(fCFContainerK);
198         fOutList->Add(fCFContainerP);
199 }
200
201
202 //________________________________________________________________
203 void AliAnalysisTaskCentral::InitCuts(){
204
205 //Create and set cuts
206
207 //------------------EVENT LEVEL CUTS--------------------
208 //-----------------------MC-----------------------------
209         AliAnalysisCentralCutEvtMC *evMCCuts = new AliAnalysisCentralCutEvtMC();
210         evMCCuts->SetMultiplicityRange(1,100);
211         evMCCuts->SetDirectivityRange(0.0, 1.0);
212     evMCCuts->SetDirUnitRange(0.0, 1.0);
213
214 //-----------------------ESD----------------------------
215         AliAnalysisCentralCutEvtESD *evESDCuts = new AliAnalysisCentralCutEvtESD();
216         evESDCuts->SetMultiplicityRange(1,100);
217         evESDCuts->SetDirectivityRange(0.0, 1.0);
218     evESDCuts->SetSPDMultiplicityRange(1,20000);
219     evESDCuts->SetSPDDirectivityRange(0.0, 1.0);
220
221         TObjArray* mcEventCuts = new TObjArray();
222         mcEventCuts->AddLast(evMCCuts);
223
224         TObjArray* esdEventCuts = new TObjArray();
225         esdEventCuts->AddLast(evESDCuts);
226
227
228 //------------------PARTICLE LEVEL CUTS-----------------
229 //-------------------General MC Cuts--------------------
230         AliAnalysisCentralCutMC *mcCutsGen = new AliAnalysisCentralCutMC();
231         mcCutsGen->SetOnlyPrimaries(kTRUE);
232         mcCutsGen->SetPtRange(0.2,4.0);
233         mcCutsGen->SetEtaRange(-0.2,0.2);
234
235 //-------------------Specific MC Cuts-------------------
236         AliAnalysisCentralCutMC *mcCutsPi = new AliAnalysisCentralCutMC();
237         mcCutsPi->SetPDGCode(211); //211 pion;  321 kaon; 2212 proton
238
239         AliAnalysisCentralCutMC *mcCutsK = new AliAnalysisCentralCutMC();
240         mcCutsK->SetPDGCode(321); //211 pion;  321 kaon; 2212 proton
241
242         AliAnalysisCentralCutMC *mcCutsP = new AliAnalysisCentralCutMC();
243         mcCutsP->SetPDGCode(2212); //211 pion;  321 kaon; 2212 proton
244
245 //--------each task has its own mcList of cuts----------
246         TObjArray *mcListGen = new TObjArray(); //general MC cuts
247         mcListGen->AddLast(mcCutsGen);
248         
249         TObjArray *mcListPi = new TObjArray(); //task pt pions
250         mcListPi->AddLast(mcCutsPi);
251
252         TObjArray *mcListK = new TObjArray(); //task pt kaons
253         mcListK->AddLast(mcCutsK);
254
255         TObjArray *mcListP = new TObjArray(); //task pt protons
256         mcListP->AddLast(mcCutsP);
257
258
259 //-------------------General ESD Cuts-------------------
260         AliESDtrackCuts *esdCutsGen = new AliESDtrackCuts("AliESDtrackCuts", "Loose");
261         esdCutsGen->SetMinNClustersTPC(50);
262         esdCutsGen->SetMaxChi2PerClusterTPC(2.2);
263         esdCutsGen->SetMaxCovDiagonalElements(0.5,0.5,0.5,0.5,0.5);
264         esdCutsGen->SetRequireTPCRefit(kTRUE);
265         esdCutsGen->SetAcceptKinkDaughters(kFALSE);
266         esdCutsGen->SetMaxNsigmaToVertex(2.0);
267         esdCutsGen->SetRequireSigmaToVertex(kTRUE);
268         esdCutsGen->SetPtRange(0.2,4.0);
269         esdCutsGen->SetEtaRange(-0.2,0.2);
270
271 //-------------------Specific ESD Cuts------------------
272         AliAnalysisCentralCutESD *esdCutsPi = new AliAnalysisCentralCutESD("AliAnalysisCentralCutESD","NIHAM");
273         esdCutsPi->SetPIDtype("Custom");
274         esdCutsPi->SetPriorFunctions(kFALSE);
275         esdCutsPi->SetPartType(kPiPlus);
276
277         AliAnalysisCentralCutESD *esdCutsK = new AliAnalysisCentralCutESD("AliAnalysisCentralCutESD","NIHAM");
278         esdCutsK->SetPIDtype("Custom");
279         esdCutsK->SetPriorFunctions(kFALSE);
280         esdCutsK->SetPartType(kKPlus);
281
282         AliAnalysisCentralCutESD *esdCutsP = new AliAnalysisCentralCutESD("AliAnalysisCentralCutESD","NIHAM");
283         esdCutsP->SetPIDtype("Custom");
284         esdCutsP->SetPriorFunctions(kFALSE);
285         esdCutsP->SetPartType(kProton);
286
287 //--------each task has its own esdList of cuts---------
288         TObjArray* esdListGen = new TObjArray(); //general ESD track cuts
289         esdListGen->AddLast(esdCutsGen);
290         
291         TObjArray* esdListPi = new TObjArray();
292         esdListPi->AddLast(esdCutsPi);
293
294         TObjArray* esdListK = new TObjArray();
295         esdListK->AddLast(esdCutsK);
296
297         TObjArray* esdListP = new TObjArray();
298         esdListP->AddLast(esdCutsP);
299
300 //------set the cuts to the RIGHT! fCutsList slots-------
301 // event level cuts
302         SetCuts(0, mcEventCuts);
303         SetCuts(1, esdEventCuts);
304
305 // particle level cuts
306         SetCuts(2, mcListGen);
307         SetCuts(3, mcListPi);
308         SetCuts(4, mcListK);
309         SetCuts(5, mcListP);
310
311         SetCuts(6, esdListGen);
312         SetCuts(7, esdListPi);
313         SetCuts(8, esdListK);
314         SetCuts(9, esdListP);
315
316 }
317
318
319 //_______________________________________________________________________
320 void AliAnalysisTaskCentral::SendEvent(TObject *obj) const{
321
322 // Some cuts (ie MC IsPrimary) need the MC Event info
323
324     if (!fCutsList) {
325                 printf("No particle cut list found!\n\n");
326                 return;
327     }
328     else {
329                 for(Int_t isel=0;isel< 10; isel++){
330                         if(!fCutsList[isel]) continue;
331                         TObjArrayIter iter(fCutsList[isel]);
332                         AliAnalysisCuts *cut = 0;
333         
334                         while ((cut = (AliAnalysisCuts*)iter.Next())) {
335                                 
336                                 TString cutName=cut->GetName();
337                                 if(!cutName){
338                                         printf("No cutname!\n");
339                                         return;
340                                 }
341                 
342                                 Bool_t checkCut=cutName.Contains("AliAnalysisCentralCutMC");
343                                         
344                                 if(checkCut){
345                                         AliAnalysisCentralCutMC *newcut = dynamic_cast<AliAnalysisCentralCutMC *>(cut);
346                                         newcut->ReceiveEvt(obj);
347                                 }
348                         }
349                 }
350     }
351
352 }
353
354
355 //________________________________________________________________________
356 Bool_t AliAnalysisTaskCentral::CheckCuts(Int_t no, TObject *obj) const{ 
357
358 // For each cut run IsSelected();
359 //      printf("AliAnalysisTaskCentral::CheckCuts IN\n");
360
361     if(no > 10){
362                 printf("\nAliAnalysisTaskCentral::CheckCuts -> Cut number is not ok! \n");
363                 return kFALSE;
364     }
365
366     if(!fCutsList[no]){
367                 printf("AliAnalysisTaskCentral::CheckCuts -> cuts list problem! \n");
368                 return kFALSE;
369     }
370
371     TObjArrayIter iter(fCutsList[no]);
372     AliAnalysisCuts *cut = 0;
373
374     while((cut = (AliAnalysisCuts*)iter.Next())){
375                 if(!cut->IsSelected(obj)){
376 //                      printf("AliAnalysisTaskCentral::CheckCuts OUT\n");
377                         return kFALSE;
378                 }
379     }
380
381 //      printf("AliAnalysisTaskCentral::CheckCuts OUT\n");
382     return kTRUE;
383 }
384
385
386 //________________________________________________________________________
387 void AliAnalysisTaskCentral::Exec(Option_t *) {
388
389 // Main loop
390 // Called for each event
391
392         Double_t pt, eta;
393         Double_t w = 1.0;
394         const Int_t nvar=2; //number of variables on the grid:pt,vtx
395         Double_t value[nvar];//used to fill the CF container
396
397         if(fSim){  // if running on simulations -> look at MC Truth
398                 
399                 if (!fMC) {
400                         Printf("ERROR: fMC not available");
401                         return;
402                 }
403
404                 if(CheckCuts(0, fMC)){ //check event level cuts
405         
406                         SendEvent(fMC);
407                 
408                         // MC loop
409                         for (Int_t ipart=0; ipart<fMC->GetNumberOfTracks(); ipart++) {
410                 
411                                 AliMCParticle *particle  = dynamic_cast<AliMCParticle*>(fMC->GetTrack(ipart));
412                                                 
413                                 if(!particle){
414                                                 printf("\nMCParticle pointer is null!!!\n");
415                                                 continue;
416                                 }
417                                 
418                                 if (!CheckCuts(2, particle)) continue; //check the MC general particle cuts 
419                                 
420                                 pt = particle->Pt();
421                                 eta = particle->Eta();
422                                 
423                                 if(pt>0) w = 1.0/pt; //invariant distribution
424                                 
425                                 value[0]=pt;
426                                 value[1]=eta;
427                                 
428                                 if(CheckCuts(3, particle)){  //fill the right container for each particle
429                                         fCFContainerPi->Fill(value,0,w);
430                                 }
431                                 else if(CheckCuts(4, particle)){
432                                         fCFContainerK->Fill(value,0,w);
433                                 }
434                                 else if(CheckCuts(5, particle)){
435                                         fCFContainerP->Fill(value,0,w);
436                                 }
437                         } //end MC particle loop 
438                 }
439         }
440         else{  // if we DONT run in simulated data we fill the MC step of the CFCont with 0
441                 value[0]=0;
442                 value[1]=0;
443                         
444                 fCFContainerPi->Fill(value,0);
445                 fCFContainerK->Fill(value,0);
446                 fCFContainerP->Fill(value,0);
447         }
448         
449         
450     if (!fESD) {
451         Printf("ERROR: fESD not available");
452         return;
453     }
454
455     if(CheckCuts(1, fESD)){
456
457                 Printf("There are %d ESD tracks in this event\n", fESD->GetNumberOfTracks());
458         
459                 // ESD loop 
460                 for (Int_t iTracks = 0; iTracks < fESD->GetNumberOfTracks(); iTracks++) {
461         
462                         AliESDtrack* track = fESD->GetTrack(iTracks);
463                         
464                         if (!track) {
465                                         Printf("ERROR: Could not receive track %d", iTracks);
466                                 continue;
467                         }
468                 
469                         if(!CheckCuts(6, track)) continue; //check general ESD track cuts
470                 
471                         pt = track->Pt();
472                         eta = track->Eta();
473                 
474                         if(pt>0) w = 1.0/pt; // invariant
475                         
476                         value[0]=pt;
477                         value[1]=eta;
478                 
479                         if(CheckCuts(7, track)){
480                                 fCFContainerPi->Fill(value,1,w);
481                         }
482                         else if(CheckCuts(8, track)){
483                                 fCFContainerK->Fill(value,1,w);
484                         }
485                         else if(CheckCuts(9, track)){
486                                 fCFContainerP->Fill(value,1,w);
487                         }
488                         
489                 } //end ESD track loop 
490                 
491                 fNoEvt->Fill(0); //get the number of analyzed events
492         }
493
494   // Post output data.
495         PostData(0, fOutList);
496
497 }
498
499 //________________________________________________________________________
500 void AliAnalysisTaskCentral::Terminate(Option_t *) {
501
502 // Called once at the end of the query
503         printf("\n\n****************************************\n");
504     printf("\tAliAnalysisCentralExtrapolate Terminate... \n");
505
506         TList *outList = dynamic_cast<TList*>(GetOutputData(0));
507         if(!outList){
508                 printf("Unable to get output list! \n");
509                 return;
510         }
511
512         AliAnalysisCentralExtrapolate *extPi = new AliAnalysisCentralExtrapolate("extrapolationpi");
513         extPi->SetInputList(outList);  //send the outlist to the extrapolation class
514         extPi->SetParticle("kPiPlus"); //set the particle type
515         extPi->ApplyEff();             //correct the pt distribution !!HAS TO RUN BEFORE extrapolation!!
516         extPi->BoltzmannFit();         //fit and extrapolate using Boltzmann-Gibbs Blast wave model
517         extPi->TsallisFit();           //fit and extrapolate using Tsallis Blast wave model
518         TList *extOutListPi = extPi->GetOutputList();
519
520         AliAnalysisCentralExtrapolate *extK = new AliAnalysisCentralExtrapolate("extrapolationK");
521         extK->SetInputList(outList);
522         extK->SetParticle("kKPlus");
523         extK->ApplyEff();
524         extK->BoltzmannFit();
525         extK->TsallisFit();
526         TList *extOutListK = extK->GetOutputList();
527
528         AliAnalysisCentralExtrapolate *extP = new AliAnalysisCentralExtrapolate("extrapolationP");
529         extP->SetInputList(outList);
530         extP->SetParticle("kProton");
531         extP->ApplyEff();
532         extP->BoltzmannFit();
533         extP->TsallisFit();
534         TList *extOutListP = extP->GetOutputList();
535
536
537 //----------- Plot the extrapolated spectra -----------------
538         TCanvas *ccorrdata = new TCanvas();
539         ccorrdata->Divide(3,2);
540         
541         ccorrdata->cd(1);
542         ccorrdata->cd(1)->SetLogy();
543         TH1D *extBoltzPi = dynamic_cast<TH1D*>(extOutListPi->FindObject("PtExtBoltzmann"));
544         if(extBoltzPi){
545                 extBoltzPi->Draw("p e1");
546         }
547
548         ccorrdata->cd(4);
549         ccorrdata->cd(4)->SetLogy();
550         TH1D *extTsallisPi = dynamic_cast<TH1D*>(extOutListPi->FindObject("PtExtTsallis"));
551         if(extTsallisPi){
552                 extTsallisPi->Draw("p e1");
553         }
554
555
556         ccorrdata->cd(2);
557         ccorrdata->cd(2)->SetLogy();
558         TH1D *extBoltzK = dynamic_cast<TH1D*>(extOutListK->FindObject("PtExtBoltzmann"));
559         if(extBoltzK){
560                 extBoltzK->Draw("p e1");
561         }
562
563         ccorrdata->cd(5);
564         ccorrdata->cd(5)->SetLogy();
565         TH1D *extTsallisK = dynamic_cast<TH1D*>(extOutListK->FindObject("PtExtTsallis"));
566         if(extTsallisK){
567                 extTsallisK->Draw("p e1");
568         }
569
570
571         ccorrdata->cd(3);
572         ccorrdata->cd(3)->SetLogy();
573         TH1D *extBoltzP = dynamic_cast<TH1D*>(extOutListP->FindObject("PtExtBoltzmann"));
574         if(extBoltzP){
575                 extBoltzP->Draw("p e1");
576         }
577
578         ccorrdata->cd(6);
579         ccorrdata->cd(6)->SetLogy();
580         TH1D *extTsallisP = dynamic_cast<TH1D*>(extOutListP->FindObject("PtExtTsallis"));
581         if(extTsallisP){
582                 extTsallisP->Draw("p e1");
583         }
584
585 // ------------------ Save the results -----------------------
586     AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
587         if(!mgr){
588                 printf("Unable to get AnalysisManager! \n");
589         return;
590         }
591
592         TString anaType;
593         mgr->GetAnalysisTypeString(anaType);
594
595         if(anaType.Contains("local")){
596                 fOutList->Add(extOutListPi);
597                 fOutList->Add(extOutListK);
598                 fOutList->Add(extOutListP);
599         }
600         else{
601                 AliAnalysisDataContainer *cont = GetOutputSlot(0)->GetContainer();
602                 if(!cont){
603                         printf("Unable to get DataContainer! \n");
604                         return;
605                 }
606
607                 printf("file name = %s\n", cont->GetFileName());
608                 TFile file(cont->GetFileName(),"update");
609
610                 file.cd("PWG2Central");
611
612                 gFile->WriteObject(extOutListPi,"pion_list","SingleKey");
613                 gFile->WriteObject(extOutListK,"kaon_list","SingleKey");
614                 gFile->WriteObject(extOutListP,"proton_list","SingleKey");
615                 file.Close();
616         }
617
618 }