CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_0/src/RecoParticleFlow/PFClusterTools/src/SpaceManager.cc

Go to the documentation of this file.
00001 #include "RecoParticleFlow/PFClusterTools/interface/SpaceManager.h"
00002 #include <cassert>
00003 #include <algorithm>
00004 #include <cmath>
00005 #include "TROOT.h"
00006 #include <string>
00007 #include "TH3F.h"
00008 #include "TVirtualFitter.h"
00009 #include "TProfile.h"
00010 using namespace pftools;
00011 
00012 SpaceManager::SpaceManager(std::string name) :
00013         name_(name), barrelLimit_(1.4), transitionLimit_(1.4), endcapLimit_(5.0) {
00014         regionsToSVs_[BARREL_POS] = barrelPosRegion_;
00015         regionsToSVs_[ENDCAP_POS] = endcapPosRegion_;
00016 }
00017 
00018 SpaceManager::~SpaceManager() {
00019 
00020 }
00021 
00022 void SpaceManager::clear() {
00023         for (std::map<SpaceVoxelPtr, CalibratorPtr>::iterator it =
00024                         myAddressBook.begin(); it!= myAddressBook.end(); ++it) {
00025                 SpaceVoxelPtr s = (*it).first;
00026                 CalibratorPtr c = (*it).second;
00027         }
00028 }
00029 
00030 void SpaceManager::createCalibrators(const Calibrator& toClone,
00031                 const double etaSeg, const double phiSeg, const double energySeg) {
00032         std::cout << __PRETTY_FUNCTION__
00033                         << ": this method has not yet been implemented!\n";
00034         PFToolsException me("Unimplemented method! Sorry!");
00035         throw me;
00036 
00037 }
00038 
00039 void SpaceManager::createCalibrators(const Calibrator& toClone) {
00040         clear();
00041         std::cout << __PRETTY_FUNCTION__
00042                         << ": creating default calibration schema.\n";
00043 
00044         SpaceVoxelPtr sv(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 0, 3.0));
00045         barrelPosRegion_.push_back(sv);
00046         SpaceVoxelPtr sv1(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 3, 9.0));
00047         barrelPosRegion_.push_back(sv1);
00048         SpaceVoxelPtr sv2(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 9.0, 16.0));
00049         barrelPosRegion_.push_back(sv2);
00050         SpaceVoxelPtr sv3(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 16.0, 25.0));
00051         barrelPosRegion_.push_back(sv3);
00052         SpaceVoxelPtr sv4(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 25.0, 100.0));
00053         barrelPosRegion_.push_back(sv4);
00054         SpaceVoxelPtr sv5(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 100.0, 200.0));
00055         barrelPosRegion_.push_back(sv5);
00056         SpaceVoxelPtr sv6(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 200.0, 400.0));
00057         barrelPosRegion_.push_back(sv6);
00058 
00059         //      SpaceVoxelPtr sv(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 0, 2.0));
00060         //      barrelPosRegion_.push_back(sv);
00061         //      SpaceVoxelPtr sv1(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 1, 1.5));
00062         //      barrelPosRegion_.push_back(sv1);
00063         //      SpaceVoxelPtr sv2(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 1.5, 2.0));
00064         //      barrelPosRegion_.push_back(sv2);
00065         //      SpaceVoxelPtr sv3(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 2.0, 2.5));
00066         //      barrelPosRegion_.push_back(sv3);
00067         //      SpaceVoxelPtr sv4(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 2.5, 4.0));
00068         //      barrelPosRegion_.push_back(sv4);
00069         //      SpaceVoxelPtr sv41(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 4.0, 5.0));
00070         //      barrelPosRegion_.push_back(sv41);
00071         //      SpaceVoxelPtr sv5(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 5.0, 6.5));
00072         //      barrelPosRegion_.push_back(sv5);
00073         //      SpaceVoxelPtr sv51(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 6.5, 8.0));
00074         //      barrelPosRegion_.push_back(sv51);
00075         //      SpaceVoxelPtr sv6(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 8.0, 10.0));
00076         //      barrelPosRegion_.push_back(sv6);
00077         //      SpaceVoxelPtr sv61(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 10.0, 12.0));
00078         //      barrelPosRegion_.push_back(sv61);
00079         //      SpaceVoxelPtr sv7(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 12.0, 16.0));
00080         //      barrelPosRegion_.push_back(sv7);
00081         //      SpaceVoxelPtr sv8(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 16.0, 25.0));
00082         //      barrelPosRegion_.push_back(sv8);
00083         //      SpaceVoxelPtr sv9(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 25.0, 40.0));
00084         //      barrelPosRegion_.push_back(sv9);
00085         //      SpaceVoxelPtr sv10(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 40.0, 60.0));
00086         //      barrelPosRegion_.push_back(sv10);
00087         //      SpaceVoxelPtr sv11(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 60.0, 100.0));
00088         //      barrelPosRegion_.push_back(sv11);
00089         //      SpaceVoxelPtr sv12(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 100.0, 200.0));
00090         //      barrelPosRegion_.push_back(sv12);
00091         //      SpaceVoxelPtr sv13(new SpaceVoxel(-1.0*barrelLimit_, barrelLimit_, -3.2, 3.2, 200.0, 400.0));
00092         //      barrelPosRegion_.push_back(sv13);
00093 
00094         SpaceVoxelPtr sve(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 0, 3.0));
00095         endcapPosRegion_.push_back(sve);
00096         SpaceVoxelPtr sve0(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 3.0, 9.0));
00097         endcapPosRegion_.push_back(sve0);
00098         SpaceVoxelPtr sve1(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 9.0, 16.0));
00099         endcapPosRegion_.push_back(sve1);
00100         SpaceVoxelPtr sve2(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 16.0, 25.0));
00101         endcapPosRegion_.push_back(sve2);
00102         SpaceVoxelPtr sve3(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 25.0, 100.0));
00103         endcapPosRegion_.push_back(sve3);
00104         SpaceVoxelPtr sve4(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 100.0, 200.0));
00105         endcapPosRegion_.push_back(sve4);
00106         SpaceVoxelPtr sve5(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 200.0, 400.0));
00107         endcapPosRegion_.push_back(sve5);
00108 
00109         //      SpaceVoxelPtr sve(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 0, 0.5));
00110         //      endcapPosRegion_.push_back(sve);
00111         //      SpaceVoxelPtr sve0(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 0.5, 1.0));
00112         //      endcapPosRegion_.push_back(sve0);
00113         //      SpaceVoxelPtr sve1(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 1, 1.5));
00114         //      endcapPosRegion_.push_back(sve1);
00115         //      SpaceVoxelPtr sve2(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 1.5, 2.0));
00116         //      endcapPosRegion_.push_back(sve2);
00117         //      SpaceVoxelPtr sve3(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 2.0, 2.5));
00118         //      endcapPosRegion_.push_back(sve3);
00119         //      SpaceVoxelPtr sve4(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 2.5, 4.0));
00120         //      endcapPosRegion_.push_back(sve4);
00121         //      SpaceVoxelPtr sve5(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 4.0, 5.0));
00122         //      endcapPosRegion_.push_back(sve5);
00123         //      SpaceVoxelPtr sve51(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 5.0, 6.5));
00124         //      endcapPosRegion_.push_back(sve51);
00125         //      SpaceVoxelPtr sve6(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 6.5, 8.0));
00126         //      endcapPosRegion_.push_back(sve6);
00127         //      SpaceVoxelPtr sve61(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 8.0, 10.0));
00128         //      endcapPosRegion_.push_back(sve61);
00129         //      SpaceVoxelPtr sve62(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 10.0, 12.0));
00130         //      endcapPosRegion_.push_back(sve62);
00131         //      SpaceVoxelPtr sve7(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 12.0, 16.0));
00132         //      endcapPosRegion_.push_back(sve7);
00133         //      SpaceVoxelPtr sve8(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 16.0, 25.0));
00134         //      endcapPosRegion_.push_back(sve8);
00135         //      SpaceVoxelPtr sve9(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 25.0, 40.0));
00136         //      endcapPosRegion_.push_back(sve9);
00137         //      SpaceVoxelPtr sve10(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 40.0, 60.0));
00138         //      endcapPosRegion_.push_back(sve10);
00139         //      SpaceVoxelPtr sve11(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 60.0, 100.0));
00140         //      endcapPosRegion_.push_back(sve11);
00141         //      SpaceVoxelPtr sve12(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 100.0, 200.0));
00142         //      endcapPosRegion_.push_back(sve12);
00143         //      SpaceVoxelPtr sve13(new SpaceVoxel(barrelLimit_, endcapLimit_, -3.2, 3.2, 200.0, 400.0));
00144         //      endcapPosRegion_.push_back(sve13);
00145 
00146         for (std::vector<SpaceVoxelPtr>::iterator it = barrelPosRegion_.begin(); it
00147                         != barrelPosRegion_.end(); ++it) {
00148                 myKnownSpaceVoxels.push_back(*it);
00149         }
00150 
00151         for (std::vector<SpaceVoxelPtr>::iterator it = endcapPosRegion_.begin(); it
00152                         != endcapPosRegion_.end(); ++it) {
00153                 myKnownSpaceVoxels.push_back(*it);
00154         }
00155 
00156         for (std::vector<SpaceVoxelPtr>::iterator it = myKnownSpaceVoxels.begin(); it
00157                         != myKnownSpaceVoxels.end(); ++it) {
00158                 CalibratorPtr c(toClone.clone());
00159                 myAddressBook[*it] = c;
00160         }
00161         std::cout << "Address book size: \t\t"<< myAddressBook.size() << "\n";
00162         std::cout << "Known space voxels size: \t"<< myKnownSpaceVoxels.size()
00163                         << "\n";
00164         assert(myAddressBook.size() == myKnownSpaceVoxels.size());
00165 
00166 }
00167 
00168 void SpaceManager::createCalibrators(const Calibrator& toClone,
00169                 const unsigned nEta, const double etaMin, const double etaMax,
00170                 const unsigned nPhi, const double phiMin, const double phiMax,
00171                 const unsigned nEnergy, const double energyMin, const double energyMax)
00172                 throw(PFToolsException&) {
00173         clear();
00174 
00175         if (nEta == 0|| nPhi ==0|| nEnergy == 0) {
00176                 PFToolsException
00177                                 me("Can't create calibrators with zero values for nEta, nPhi or nEnergy!");
00178                 throw me;
00179         }
00180 
00181         double etaSeg = (etaMax - etaMin) / nEta;
00182         double phiSeg = (phiMax - phiMin) / nPhi;
00183         double energySeg = (energyMax - energyMin) / nEnergy;
00184 
00185         double eta1, eta2, phi1, phi2, energy1, energy2;
00186         for (unsigned k(0); k < nEta; ++k) {
00187                 for (unsigned l(0); l < nPhi; ++l) {
00188                         for (unsigned m(0); m < nEnergy; ++m) {
00189                                 eta1 = etaMin + k * etaSeg;
00190                                 eta2 = eta1 + etaSeg;
00191 
00192                                 phi1 = phiMin + l * phiSeg;
00193                                 phi2 = phi1 + phiSeg;
00194 
00195                                 energy1 = energyMin + m * energySeg;
00196                                 energy2 = energy1 + energySeg;
00197                                 SpaceVoxelPtr sv(new SpaceVoxel(eta1, eta2, phi1, phi2, energy1, energy2));
00198                                 myKnownSpaceVoxels.push_back(sv);
00199                                 CalibratorPtr c(toClone.clone());
00200                                 myAddressBook[sv] = c;
00201                         }
00202                 }
00203         }
00204         unsigned nCalibrators = nEta * nPhi * nEnergy;
00205         std::cout << "Created "<< nCalibrators << " calibrators.\n";
00206         std::cout << "Address book size: \t\t"<< myAddressBook.size() << "\n";
00207         std::cout << "Known space voxels size: \t"<< myKnownSpaceVoxels.size()
00208                         << "\n";
00209         assert(myAddressBook.size() == myKnownSpaceVoxels.size());
00210         makeInverseAddressBook();
00211 
00212 }
00213 CalibratorPtr SpaceManager::createCalibrator(const Calibrator& toClone,
00214                 SpaceVoxelPtr s) {
00215         CalibratorPtr c;
00216         int known = count(myKnownSpaceVoxels.begin(), myKnownSpaceVoxels.end(), s);
00217         if (known == 0) {
00218                 myKnownSpaceVoxels.push_back(s);
00219                 c.reset(toClone.clone());
00220                 myAddressBook[s] = c;
00221         } else {
00222                 c = myAddressBook[s];
00223         }
00224         assert(c != 0);
00225         return c;
00226 
00227 }
00228 
00229 CalibratorPtr SpaceManager::findCalibrator(const double eta, const double phi,
00230                 const double energy) const {
00231         CalibratorPtr answer;
00232         for (std::vector<SpaceVoxelPtr>::const_iterator cit =
00233                         myKnownSpaceVoxels.begin(); cit != myKnownSpaceVoxels.end(); ++cit) {
00234                 SpaceVoxelPtr s = *cit;
00235                 if (s->contains(eta, phi, energy)) {
00236                         assert(count(myKnownSpaceVoxels.begin(), myKnownSpaceVoxels.end(), s) != 0);
00237                         answer = (*myAddressBook.find(s)).second;
00238                         break;
00239                 } else {
00240                         //assert(count(myKnownSpaceVoxels.begin(), myKnownSpaceVoxels.end(), s) == 0);
00241                 }
00242         }
00243         return answer;
00244 }
00245 
00246 void SpaceManager::assignCalibration(CalibratorPtr c,
00247                 std::map<DetectorElementPtr, double> result) {
00248         calibrationCoeffs_[c] = result;
00249         makeInverseAddressBook();
00250 }
00251 
00252 std::map<DetectorElementPtr, double> SpaceManager::getCalibration(CalibratorPtr c) {
00253         return calibrationCoeffs_[c];
00254 }
00255 
00256 TH1* SpaceManager::extractEvolution(DetectorElementPtr det, Region r, TF1& f1,
00257                 bool useTruth) {
00258 
00259         std::vector<SpaceVoxelPtr> region;
00260         if (r == BARREL_POS)
00261                 region = barrelPosRegion_;
00262         if (r == ENDCAP_POS)
00263                 region = endcapPosRegion_;
00264         //region = regionsToSVs_[r];
00265 
00266         std::sort(region.begin(), region.end(), SpaceVoxel());
00267 
00268         std::string detElName = DetElNames[det->getType()];
00269         std::string name("hDist_");
00270         name.append(RegionNames[r]);
00271         name.append("_");
00272         name.append(DetElNames[det->getType()]);
00273 
00274         double minE(1000);
00275         double maxE(0);
00276 
00277         TH2F hDist(name.c_str(), name.c_str(), 100, 0, 300, 50, 0.0, 2.5);
00278         //      TH3F hSurf(nameSurf.c_str(), nameSurf.c_str(), 30, 0, 50, 10, 0.0, 3.0, 30,
00279         //                      0.0, 2.5);
00280         for (std::vector<SpaceVoxelPtr>::iterator i = region.begin(); i
00281                         != region.end(); ++i) {
00282                 SpaceVoxelPtr s = *i;
00283                 //double midE = (s->maxEnergy() + s->minEnergy()) / 2.0;
00284                 if (s->maxEnergy() > maxE)
00285                         maxE = s->maxEnergy();
00286                 if (s->minEnergy() < minE)
00287                         minE = s->minEnergy();
00288                 CalibratorPtr c = myAddressBook[s];
00289                 double coeff = calibrationCoeffs_[c][det];
00290                 if (coeff != 0.0) {
00291                         std::vector<ParticleDepositPtr> particles = c->getParticles();
00292                         for (std::vector<ParticleDepositPtr>::iterator it =
00293                                         particles.begin(); it != particles.end(); ++it) {
00294                                 if (useTruth)
00295                                         hDist.Fill((*it)->getTruthEnergy(), coeff);
00296                                 else
00297                                         hDist.Fill((*it)->getRecEnergy(), coeff);
00298                         }
00299                 }
00300         }
00301 
00302         hDist.FitSlicesY();
00303         hDist.ProfileX();
00304         hDist.Write();
00305         std::string nameProfile(name);
00306         nameProfile.append("_pfx");
00307         name.append("_1");
00308 
00309         TH1D* slices = (TH1D*) gDirectory->Get(name.c_str());
00310         //TH2D* slicesSurf = (TH2D*) gDirectory->Get(nameSurf.c_str());
00311         TProfile* profile = (TProfile*) gDirectory->Get(nameProfile.c_str());
00312         profile->Fit(&f1);
00313         slices->Fit(&f1);
00314         profile->Write();
00315 
00316         return slices;
00317 
00318 }
00319 
00320 double SpaceManager::evolveCoefficient(DetectorElementPtr det, double energy,
00321                 double eta, double phi) {
00322         if (eta < barrelLimit_) {
00323                 TF1& func = barrelPosEvolutions_[det];
00324                 return func.Eval(energy);
00325         }
00326         TF1& func = endcapPosEvolutions_[det];
00327         return func.Eval(energy);
00328 }
00329 
00330 double SpaceManager::interpolateCoefficient(DetectorElementPtr det,
00331                 double energy, double eta, double phi) {
00332         CalibratorPtr c = findCalibrator(eta, phi, energy);
00333 
00334         SpaceVoxelPtr s = inverseAddressBook_[c];
00335 
00336         double midEnergy = (s->minEnergy() + s->maxEnergy())/2.0;
00337         //interpolate left or right?
00338         double diffEnergy = energy - midEnergy;
00339         double thisCoeff = calibrationCoeffs_[c][det];
00340 
00341         double interpolatedCoeff = thisCoeff;
00342         double adjacentCoeff = 0.0;
00343         double adjacentEnergy = 0.0;
00344         if (diffEnergy > 0) {
00345                 //look to higher energy calibrators
00346                 CalibratorPtr adjC = findCalibrator(eta, phi, s->maxEnergy() + 0.1);
00347                 if (adjC != 0) {
00348                         SpaceVoxelPtr adjS = inverseAddressBook_[adjC];
00349                         adjacentCoeff = calibrationCoeffs_[adjC][det];
00350                         adjacentEnergy = (adjS->minEnergy() + adjS->maxEnergy()) / 2.0;
00351                 }
00352         } else {
00353                 //look to lower energy calibrations
00354                 CalibratorPtr adjC = findCalibrator(eta, phi, s->minEnergy() - 0.1);
00355                 if (adjC != 0) {
00356                         SpaceVoxelPtr adjS = inverseAddressBook_[adjC];
00357                         adjacentCoeff = calibrationCoeffs_[adjC][det];
00358                         adjacentEnergy = (adjS->minEnergy() + adjS->maxEnergy()) / 2.0;
00359                 }
00360         }
00361         if (adjacentCoeff != 0) {
00362                 interpolatedCoeff = thisCoeff + diffEnergy* (adjacentCoeff - thisCoeff)
00363                                 / (adjacentEnergy - midEnergy);
00364         }
00365         return interpolatedCoeff;
00366 }
00367 
00368 std::ostream& SpaceManager::printCalibrations(std::ostream& stream) {
00369         stream << "Calibration results: \n";
00370         //      std::sort(myKnownSpaceVoxels.begin(), myKnownSpaceVoxels.end(),
00371         //                      SpaceVoxel());
00372         stream << "WARNING! Haven't sorted space voxels properly!\n";
00373         for (std::vector<SpaceVoxelPtr>::iterator it = myKnownSpaceVoxels.begin(); it
00374                         != myKnownSpaceVoxels.end(); ++it) {
00375                 SpaceVoxelPtr s = *it;
00376                 CalibratorPtr c = myAddressBook[s];
00377                 stream << *s << "\n";
00378                 stream << "\t[";
00379                 std::map<DetectorElementPtr, double> result = calibrationCoeffs_[c];
00380                 for (std::map<DetectorElementPtr, double>::iterator b = result.begin(); b
00381                                 != result.end(); ++b) {
00382                         DetectorElementPtr d = (*b).first;
00383                         stream << *d << ": ";
00384                         double ans = (*b).second;
00385                         stream << ans << ", ";
00386                 }
00387                 stream << "]\n";
00388         }
00389 
00390         return stream;
00391 }
00392 
00393 void SpaceManager::makeInverseAddressBook() {
00394         inverseAddressBook_.clear();
00395         for (std::map<SpaceVoxelPtr, CalibratorPtr>::iterator it =
00396                         myAddressBook.begin(); it != myAddressBook.end(); ++it) {
00397                 SpaceVoxelPtr s = (*it).first;
00398                 CalibratorPtr c = (*it).second;
00399                 inverseAddressBook_[c] = s;
00400         }
00401 }