#include "TBDut.h" using namespace std; Rectangle::Rectangle(double lowerLeftX, double lowerLeftY, double upperRightX, double upperRightY){ this->lowerLeftX = lowerLeftX; this->lowerLeftY = lowerLeftY; this->upperRightX = upperRightX; this->upperRightY = upperRightY; this->area = (upperRightX-lowerLeftX) * (upperRightY-lowerLeftY); } bool Rectangle::inside(double x, double y){ return Rectangle::inside(x, y, 0.0, 0.0); } bool Rectangle::inside(double x, double y, double marginX, double marginY) { if ( (x >= lowerLeftX - marginX) && (x < upperRightX + marginX) ){ if ( (y >= lowerLeftY- marginY) && (y < upperRightY + marginY) ){ return true; } } return false; } //Pixel Geometry///////////////////////////////////////////////////// PixelGeometry::PixelGeometry(bool edge, int numElec, int periodMirroringX, std::vector rectanglesConfig){ this->edge = edge; this->numElec = numElec; this->mirroringX = periodMirroringX; this->nPixels = 0; for (vector::iterator it = rectanglesConfig.begin(); it != rectanglesConfig.end(); ++it){ Rectangle r(it->lowerLeftX,it->lowerLeftY,it->upperRightX,it->upperRightY); this->rectangles.push_back(r); } // calculate maxPitch in both directions double minX = (rectangles.begin())->getLowerLeftX(); double minY = (rectangles.begin())->getLowerLeftY(); double maxX = (rectangles.begin())->getUpperRightX(); double maxY = (rectangles.begin())->getUpperRightY(); for (vector::iterator it = rectangles.begin(); it != rectangles.end(); ++it){ if (it->getLowerLeftX()getLowerLeftX(); } if (it->getLowerLeftY()getLowerLeftY(); } if (it->getUpperRightX()>maxX){ maxX = it->getUpperRightX(); } if (it->getUpperRightY()>maxY){ maxY = it->getUpperRightY(); } } this->maxPitchX = maxX - minX; this->maxPitchY = maxY - minY; // calculate area of the Pixel Geometry this->area = 0; for (vector::iterator it = rectangles.begin(); it != rectangles.end(); ++it){ this->area += it->getArea(); } // calculate geometric Center of the Pixel Geometry double weightedX = 0; double weightedY = 0; for (vector::iterator it = rectangles.begin(); it != rectangles.end(); ++it){ weightedX += (it->getUpperRightX() + it->getLowerLeftX()) * 0.5 * it->getArea(); weightedY += (it->getUpperRightY() + it->getLowerLeftY()) * 0.5 * it->getArea(); //weightedX += (it->getUpperRightX() - it->getLowerLeftX()) * it->getArea(); //weightedY += (it->getUpperRightY() - it->getLowerLeftY()) * it->getArea(); } geometricCenterX = weightedX / this->area; geometricCenterY = weightedY / this->area; // construct charge map //todo: make the build during preprocessing and load it before analyseses begin? /* int radius; // radius of electrons' cloud int n = 1; // n bins per mu m int nbinsX = n * (floor(getMaxPitchX()) + 2 * radius); int nbinsY = n * (floor(getMaxPitchY()) + 2 * radius); int offset= -n * radius; // plot is shifted to the lower left, so the rectangle surrounding the pixel begins at (0,0) //todo: aus HistogrammTest.cc kopieren/anpassen chargeMap = new TH2D("?","?",nbinsX,offset,nbinsX+offset,nbinsY,offset,nbinsY+offset); for (int x = offset; x < nbinsX+offset; x++){ for (int y = offset; y < nbinsY+offset; y++){ double ratio = ratioInside(x,y,radius); chargeMap->Fill(x,y,ratio); } }*/ } double PixelGeometry::ratioInside(int x, int y, int radius){ // returns, how much of a circle with radius around x,y is inside the pixel geometry //todo: resolution of 1 mu m. Is that ok? //todo: man könnte ein Profil (Abhängigkeit vom Abstand des Mittelpunkts einbauen)? int count_inside = 0; int count_outside = 0; for (int itX = -radius; itX < radius; itX++){ for (int itY = -radius; itY < radius; itY++){ // check, if (itX,itY) is inside the circle and inside the rectangle if (sqrt((itX*itX)+(itY*itY)) < radius){ if (inside(itX+x, itY+y)) count_inside++; else count_outside++; } } } return (double(count_inside)/(double(count_outside+count_inside))); } bool PixelGeometry::inside(double x, double y){ return PixelGeometry::inside(x, y, 0.0, 0.0); } bool PixelGeometry::inside(double x, double y, double marginX, double marginY) { for (vector< Rectangle >::iterator it = rectangles.begin(); it != rectangles.end(); ++it) { if(it->inside(x,y, marginX, marginY)) { return true; } } return false; } //Pixel as Element of pixelArray///////////////////////////////////// Pixel::Pixel(){ // is called by pixelArray.resize(); this->lowerLeftX = 0; this->lowerLeftY = 0; this->geometry = NULL; mask = 0; nMasks = 16; } void Pixel::setPixel(double lowerLeftX, double lowerLeftY, bool mirroring, PixelGeometry *geometry){ this->lowerLeftX = lowerLeftX; this->lowerLeftY = lowerLeftY; this->geometry = geometry; this->mirroring = mirroring; } bool Pixel::whichMask(int type){ // checks, if mask contains type int mask1 = mask; for (int i=nMasks; i>=type; i/=2){ if (mask1 >= i){ if (i == type){ return true; } mask1 = mask1 - i; } } return false; } void Pixel::addMask(int type){ /* type key (numbers are chosen like below, so that they are summable): mask = 0 : pixel not masked masked during preprocessing: mask = 1 : pixel masked because noisy mask = 2 : pixel masked because neighbouring pixel is noisy mask = 4 : pixel masked because dead masked before preprocessing: mask = 8 : pixel masked because defined in DUT Config mask = 16 : pixel masked because of calibration */ // type must be 0 < 2^x = nMasks < 32 int mask1 = this->mask; bool type_correct = false; // check, if mask is not set already and type is 1,2,4,8,16 for (int i=nMasks; i>0; i/=2){ if (mask1 >= i){ mask1 = mask1 - i; if (type == i){ break; } } else{ if (type == i){ type_correct = true; break; } } } if (type_correct == false) { //todo einkommentieren //TBALOG(kERROR) << "type must equal 1,2,4,8,16 and must not be set already" << endl; } else{ mask+=type; // wieso wird hier die maske um den typ erhoeht ? und nicht ersetze durch den neuen typ; oder gar nichts gemacht ??? } } bool Pixel::inside(double x, double y){ return Pixel::inside(x, y, 0.0, 0.0); } bool Pixel::inside(double x, double y, double marginX, double marginY) { return geometry->inside(x-lowerLeftX, y-lowerLeftY, marginX, marginY); } double Pixel::getGeometricCenterX(){ return (geometry->getGeometricCenterX() + lowerLeftX); } double Pixel::getGeometricCenterY(){ return (geometry->getGeometricCenterY() + lowerLeftY); } //DUT//////////////////////////////////////////////////////////////// DUT::DUT(TBDutConfig &dutConfig) { // TEST delete later this->numElec = dutConfig.numElec; this->name = dutConfig.DUTName; this->iden = dutConfig.iden; this->masks.clear(); this->pixelArray.clear(); this->pixelGeometries.clear(); this->matchX = dutConfig.matchX; //wenn isMatch in der Clusterklasse fertig ist wieder entfernen this->matchY = dutConfig.matchY; //wenn isMatch in der Clusterklasse fertig ist wieder entfernen this->matchPixelMarginX = dutConfig.matchPixelMarginX;// matching radius X around a pixel this->matchPixelMarginY = dutConfig.matchPixelMarginY;// matching radius Y around a pixel this->lv1Min = dutConfig.lv1Min; this->lv1Max = dutConfig.lv1Max; this->noisyNeighborColRadius = dutConfig.noisyNeighborColRadius; this->noisyNeighborRowRadius = dutConfig.noisyNeighborRowRadius; this->maskDeadPixels = dutConfig.maskDeadPixels; this->ncols = dutConfig.cols; this->nrows = dutConfig.rows; this->dutPitchX = dutConfig.DUTsizeX; this->zPos = dutConfig.zPos; this->dutPitchY = dutConfig.DUTsizeY; this->maxTot = dutConfig.maxTot; //todo wenn ToT Kalibration vorliegt, totcalib erzeugen (immer versuchen oder vorher abfangen?) this->totcalib = new ToTCalib(dutConfig.totcalibPath); if (totcalib->hasCalib() == false){ cout << "[ DUT " << this->iden << " ]: ToT Calibration histograms could not be loaded from file " << dutConfig.totcalibPath << " or does not exist." << endl; } int nbinx=0; int nbiny=0; // set size of dut area pixelArray.resize(ncols); for (int i=0; i::iterator it = dutConfig.pixel.begin(); it!=dutConfig.pixel.end(); ++it){ iii++; //just because the code is easier to read: int firstPixelCol = it->firstPixelCol; int firstPixelRow = it->firstPixelRow; double firstPixelX = it->firstPixelX; double firstPixelY = it->firstPixelY; int periodPixelCol = it->periodPixelCol; int periodPixelRow = it->periodPixelRow; double periodPixelX = it->periodPixelX; double periodPixelY = it->periodPixelY; int nPixelX = it->countPixelCol; int nPixelY = it->countPixelRow; // make new pixel geometry and add it PixelGeometry *pixelGeometry = new PixelGeometry(it->edge, it->numElec, it->periodMirroringCol, it->rectangle); pixelGeometries.push_back(pixelGeometry); // allot the pixelArray entries to the pixel geometry for (int i = 0; i < nPixelX; i++){ for (int j = 0; j < nPixelY; j++){ int col = firstPixelCol+i*periodPixelCol; // row and column in which the geometry int row = firstPixelRow+j*periodPixelRow; // is supposed to be added double x = firstPixelX + i*periodPixelX; double y = firstPixelY + j*periodPixelY; if (pixelGeometries.back()->getMirroringX() == 0) { mirroring = false; } else{ if ((i+1) % pixelGeometries.back()->getMirroringX() == 0) mirroring = true; else mirroring = false; } pixelArray.at(col).at(row).setPixel(x, y, mirroring, pixelGeometries.back()); pixelGeometries.back()->nPixels++; if (x + pixelGeometries.back()->getMaxPitchX() > double(nbinx)){ nbinx = ceil(x + pixelGeometries.back()->getMaxPitchX()); } if (y + pixelGeometries.back()->getMaxPitchY() > double(nbiny)){ nbiny = ceil(y + pixelGeometries.back()->getMaxPitchY()); } } } counter++; } nPixelGeometries = counter; // apply masks, that are given by the dutConfig for (std::vector::iterator it = dutConfig.maskRow.begin(); it != dutConfig.maskRow.end(); ++it){ for (int col = 0; col < ncols; col++){ if( *it < nrows) { DUT::addMask(col,*it,8); } } } for (auto& it: dutConfig.maskCol){ for (int row = 0; row < nrows; row++){ if( it < ncols) { DUT::addMask(it,row,8); } } } maxPixelPitchX = 0.0; maxPixelPitchY= 0.0; for(std::vector::iterator it = pixelGeometries.begin(); it != pixelGeometries.end(); it++) { if((*it)->getMaxPitchX() > maxPixelPitchX) { maxPixelPitchX = (*it)->getMaxPitchX(); } if((*it)->getMaxPitchY() > maxPixelPitchY) { maxPixelPitchY = (*it)->getMaxPitchY(); } } } /*DUT::~DUT() { for(auto& pixGeo: DUT::pixelGeometries) { delete pixGeo; } DUT::pixelGeometries.clear(); delete DUT::totcalib; }*/ void DUT::addMaskPair(int col, int row){ // first check, if pixel is masked already // if not --> add it to the list if (pixelArray.at(col).at(row).getMask()==0) { pair mask = make_pair(col,row); masks.push_back(mask); } } void DUT::addMask(int col, int row, int type) { DUT::addMask(col, row, type, DUT::noisyNeighborColRadius, DUT::noisyNeighborRowRadius); } void DUT::addMask(int col, int row, int type, int neighborX, int neighborY) { if (type == 0) { // resetting the masks is not planned } if(type > 0) { // if pixel is not masked yet, add the mask pixelArray.at(col).at(row).addMask(type); addMaskPair(col, row); // if pixel is masked because it's noisy, mask neighbouring pixels if(type == 1) { neighborX = std::abs(neighborX); neighborY = std::abs(neighborY); int startCol = (col - neighborX < 0) ? 0 : col - neighborX; int endCol = (col + neighborX > DUT::ncols-1) ? DUT::ncols-1 : col + neighborX; int startRow = (row - neighborY < 0) ? 0 : row - neighborY; int endRow = (row + neighborY > DUT::nrows-1) ? DUT::nrows-1 : row + neighborY; for(int x = startCol; x <= endCol; x++) { for(int y = startRow; y <= endRow; y++) { if(x == col and y == row) { continue; } addMaskPair(x, y); pixelArray[x][y].addMask(2); } } } } } void DUT::getColRow(double x, double y, int* col, int* row) { DUT::getColRow(x, y, 0.0, 0.0, col, row); } void DUT::getColRow(double x, double y, double marginX, double marginY, int* col, int* row) { if(x < 0 - marginX || y < 0 - marginY || x > DUT::dutPitchX + marginX || y > DUT::dutPitchY + marginY) { *col = -1; *row = -1; return; } int i; int c = (int) (DUT::ncols/2); int r = (int) (DUT::nrows/2); double lowerLeftX; double lowerRightX; double lowerLeftY; double lowerRightY; // find col i = 2; while(true) { lowerLeftX = DUT::pixelArray[c][r].getLowerLeftX(); lowerRightX = (c+1 == DUT::ncols) ? DUT::dutPitchX : DUT::pixelArray[c+1][r].getLowerLeftX(); if((lowerLeftX <= x && lowerRightX >= x) or ((c == 0 && lowerLeftX - marginX <= x) or (c == DUT::ncols-1 && lowerRightX + marginX >= x))) { break; } i *= 2; if(lowerRightX <= x) { c += (((int) (DUT::ncols/i)) == 0 ) ? 1 : (int) (DUT::ncols/i); } else { c -= (((int) (DUT::ncols/i)) == 0 ) ? 1 : (int) (DUT::ncols/i); } } // find row i = 2; while(true) { lowerLeftY = DUT::pixelArray[c][r].getLowerLeftY(); lowerRightY = (r+1 == DUT::nrows) ? DUT::dutPitchY : DUT::pixelArray[c][r+1].getLowerLeftY(); if((lowerLeftY <= y && lowerRightY >= y) or ((r == 0 && lowerLeftY - marginY <= y) or (r == DUT::nrows-1 && lowerRightY + marginY >= y))) { break; } i *= 2; if(lowerRightY <= y) { r += (((int) (DUT::nrows/i)) == 0 ) ? 1 : (int) (DUT::nrows/i); } else { r -= (((int) (DUT::nrows/i)) == 0 ) ? 1 : (int) (DUT::nrows/i); } } if(c == 0 || c == DUT::ncols || r == 0 || r == DUT::nrows) { if(DUT::pixelArray[c][r].inside(x, y, marginX, marginY)) { *col = c; *row = r; return; } } // check located col and row if(DUT::pixelArray[c][r].inside(x, y)) { *col = c; *row = r; return; } else // if col and row wrong search in neighbourhood { int pixelRadius = 3; int count = 0; int startCol, stopCol; int startRow, stopRow; while(true) { startCol = (c - pixelRadius < 0) ? 0 : c - pixelRadius; stopCol = (c + pixelRadius >= DUT::ncols) ? DUT::ncols-1 : c + pixelRadius; startRow = (r - pixelRadius < 0) ? 0 : r - pixelRadius; stopRow = (r + pixelRadius >= DUT::nrows) ? DUT::nrows-1 : r + pixelRadius; for(int cc = startCol; cc <= stopCol; cc = (cc == (c+count*pixelRadius-1)) ? c+count*pixelRadius+1 : cc+1) { for(int rr = startRow; rr <= stopRow; rr = (rr == (r+count*pixelRadius-1)) ? r+count*pixelRadius+1 : rr+1) { if(cc == 0 || cc == DUT::ncols || rr == 0 || rr == DUT::nrows) { if(DUT::pixelArray[cc][rr].inside(x, y, marginX, marginY)) { *col = cc; *row = rr; return; } else { *col = -1; *row = -1; return; } } if(DUT::pixelArray[cc][rr].inside(x, y)) { *col = cc; *row = rr; return; } } } // update radius an search in large area again pixelRadius += pixelRadius; count++; } } } bool DUT::matchNeighborPixel(double x, double y, int col, int row, double marginX, double marginY, int* neighborCol, int* neighborRow, bool allowMask = true) { int c = (col == 0) ? col : col-1; int cMax = (col == DUT::ncols-1) ? col : col+1; int r = (row == 0) ? row : row-1; int rMax = (row == DUT::nrows-1) ? row : row+1; double minDis = std::numeric_limits::max(); *neighborCol = col; *neighborRow = row; for( ; c <= cMax; c++) { for( ; r <= rMax; r++) { if(c == col and r == row) { continue; } if(!allowMask and DUT::pixelArray[c][r].getMask() != 0) { continue; } if(DUT::pixelArray[c][r].inside(x, y, marginX, marginY)) { double disX = std::fabs(DUT::pixelArray[c][r].getGeometricCenterX() - x); double disY = std::fabs(DUT::pixelArray[c][r].getGeometricCenterY() - y); double dis = std::sqrt(disX*disX + disY*disY); if(dis < minDis) { minDis = dis; *neighborCol = c; *neighborRow = r; } } } } if(*neighborCol == col and *neighborRow == row) { return false; } return true; } bool DUT::matchNeighborPixel(double x, double y, double marginX, double marginY, int* neighborCol, int* neighborRow) { int col; int row; DUT::getColRow(x, y, marginX, marginY, &col, &row); return DUT::matchNeighborPixel(x, y, col, row, marginX, marginY, neighborCol, neighborRow); } bool DUT::isEdgePixel(int col, int row){ return pixelArray.at(col).at(row).getGeometry()->isEdgePixel(); } int DUT::getMask(int col, int row) { return pixelArray.at(col).at(row).getMask(); } int DUT::getGeometryNumber(PixelGeometry *pixelGeometry){ for (int i = 0; i < pixelGeometries.size(); i++){ if ((pixelGeometries[i]) == (pixelGeometry)){ return i; } } cout << "Did not find geometry. DUT::getGeometryNumber" << endl; return -1; } double DUT::q(const double& tot, const int& col,const int& row){ return totcalib->q(tot, col, row); } void DUT::initRun(int currentRun){ ecorrs.initRun(currentRun); //todo: wieder einkommentieren?! } void DUT::getFoldedXY(const int col, const int row, const double trackX, const double trackY, double* trackFoldedX, double* trackFoldedY) { // fold the track coordinates into one pixel. If mirroring is wanted, the x value is mirrored. PixelGeometry* geometry = DUT::pixelArray.at(col).at(row).getGeometry(); *trackFoldedX = trackX - DUT::pixelArray.at(col).at(row).getLowerLeftX(); *trackFoldedY = trackY - DUT::pixelArray.at(col).at(row).getLowerLeftY(); if(DUT::pixelArray.at(col).at(row).getMirroring() == true) { *trackFoldedX = geometry->getMaxPitchX() - *trackFoldedX; } } void DUT::getElectrodeDistance(const int col, const int row, const double x, const double y, double* distX, double* distY) { PixelGeometry* geometry = DUT::pixelArray.at(col).at(row).getGeometry(); double foldedX; double foldedY; DUT::getFoldedXY(col, row, x, y, &foldedX, &foldedY); double electrodeSpacingX = geometry->getMaxPitchX()/(double) DUT::numElec; double electrodeSpacingY = geometry->getMaxPitchY(); while(foldedX > electrodeSpacingX) { foldedX -= electrodeSpacingX; } //*distX = std::fabs(foldedX - electrodeSpacingX/2.0); *distX = foldedX - electrodeSpacingX/2.0; while(foldedY > electrodeSpacingY) { foldedY -= electrodeSpacingY; } //*distY = std::fabs(foldedY - electrodeSpacingY/2.0); *distY = foldedY - electrodeSpacingY/2.0; } /*static bool DUT::checkDutConfig(TBDutConfig* dutConfig) { // DUT info check if(dutConfig->DUTName.compare("") == 0) { std::cout << "DUT name does not set." << endl; } if(dutConfig->totcalibPath.compare("") == 0) { std::cout << "DUT ToT calibration path does not set." << endl; } if(dutConfig->DUTsizeX <= 0.0 or dutConfig->DUTsizeY <= 0.0) { std::cout << "DUT size is <= 0.0." << endl; exit(-1); } if(dutConfig->DUTthikness <= 0.0) { std::cout << "DUT thickness <= 0.0" << endl; exit(-1); } if(dutConfig->cols <= 0 || dutConfig->rows <= 0) { std::cout << "DUT col/row is <= 0." << endl; exit(-1); } if(dutConfig->iden < 0) { std::cout << "DUT iden is negative." << endl; exit(-1); } if(dutConfig->lv1Min < 0 || (dutConfig->lv1Min > dutConfig->lv1Max)) { std::cout << "DUT lv1 range is wrong." << endl; exit(-1); } if(dutConfig->matchRadius <= 0.0 or dutConfig->matchX <= 0.0 or dutConfig->matchY <= 0.0) { std::cout << "DUT match values <= 0.0." << endl; exit(-1); } if(dutConfig->maxTot <= 0) { std::cout << "DUT ToT <= 0." << endl; exit(-1); } if(dutConfig->numElec <= 0) { std::cout << "DUT numElec <= 0." << endl; exit(-1); } // Pixel check for(auto pixel: dutConfig->pixel) { } // Rectangle check } */