21 #include "GaudiKernel/ITHistSvc.h"
42 coerceToIntRange(
double v){
45 auto d = std::clamp(
v, minint, maxint);
47 return {
static_cast<int>(
d),
d !=
v};
53 const std::array<std::regex, NnClusterizationFactory::kNNetworkTypes>
57 std::regex(
"^ImpactPointErrorsX([0-9])(|/|_.*)$"),
58 std::regex(
"^ImpactPointErrorsY([0-9])(|/|_.*)$"),
62 const std::string&
n,
const IInterface*
p)
64 declareInterface<NnClusterizationFactory>(
this);
82 std::smatch match_result;
83 for(
const std::string &nn_name :
m_nnOrder) {
85 for (
unsigned int network_i=0; network_i<
kNNetworkTypes; ++network_i) {
86 if (std::regex_match( nn_name, match_result,
m_nnNames[network_i])) {
92 ATH_MSG_ERROR(
"Regex and match group of particle multiplicity do not coincide (groups=" << match_result.size()
94 <<
"; type=" << network_i <<
")");
97 if (n_particles<=0 or
static_cast<unsigned int>(n_particles)>
m_maxSubClusters) {
100 return StatusCode::FAILURE;
102 if (
static_cast<unsigned int>(n_particles)>=
m_NNId[network_i-1].
size()) {
103 m_NNId[network_i-1].resize( n_particles );
105 m_NNId[network_i-1][n_particles-1] = nn_id;
107 if (
m_NNId[network_i-1].empty()) {
108 m_NNId[network_i-1].resize(1);
110 m_NNId[network_i-1][0] = nn_id;
119 ATH_MSG_ERROR(
"No NN specified to estimate the number of particles.");
120 return StatusCode::FAILURE;
124 unsigned int type_i=0;
125 for (std::vector<unsigned int> &nn_id :
m_NNId) {
129 return StatusCode::FAILURE;
133 return StatusCode::FAILURE;
135 unsigned int n_particles=0;
136 for (
unsigned int &a_nn_id : nn_id ) {
138 if ((a_nn_id==0) or (a_nn_id>
m_nnOrder.size())) {
140 return StatusCode::FAILURE;
149 return StatusCode::SUCCESS;
156 const auto invalidValue{std::numeric_limits<double>::quiet_NaN()};
157 std::vector<double> inputData(vectorSize, invalidValue);
158 size_t vectorIndex{0};
161 inputData[vectorIndex++] = input.matrixOfToT[
u][
s];
165 inputData[vectorIndex++] = input.vectorOfPitchesY[
s];
167 inputData[vectorIndex++] = input.ClusterPixLayer;
168 inputData[vectorIndex++] = input.ClusterPixBarrelEC;
169 inputData[vectorIndex++] = input.phi;
170 inputData[vectorIndex++] = input.theta;
171 if (not input.useTrackInfo) inputData[vectorIndex] = input.etaModule;
178 const auto invalidValue{std::numeric_limits<double>::quiet_NaN()};
179 std::vector<double> inputData(vectorSize, invalidValue);
180 size_t vectorIndex{0};
184 inputData[vectorIndex++] =
norm_rawToT(input.matrixOfToT[
u][
s]);
186 inputData[vectorIndex++] =
norm_ToT(input.matrixOfToT[
u][
s]);
191 const double rawPitch(input.vectorOfPitchesY[
s]);
193 if (std::isnan(normPitch)){
196 inputData[vectorIndex++] = normPitch;
199 inputData[vectorIndex++] =
norm_layerType(input.ClusterPixBarrelEC);
200 if (input.useTrackInfo){
201 inputData[vectorIndex++] =
norm_phi(input.phi);
202 inputData[vectorIndex] =
norm_theta(input.theta);
204 inputData[vectorIndex++] =
norm_phiBS(input.phi);
220 Eigen::VectorXd valuesVector( vecSize );
226 for (
const auto & xvec: input.matrixOfToT){
227 for (
const auto & xyElement : xvec){
228 valuesVector[location++] = xyElement;
231 for (
const auto & pitch : input.vectorOfPitchesY) {
232 valuesVector[location++] = pitch;
234 valuesVector[location] = input.ClusterPixLayer;
236 valuesVector[location] = input.ClusterPixBarrelEC;
238 valuesVector[location] = input.phi;
240 valuesVector[location] = input.theta;
242 if (!input.useTrackInfo) {
243 valuesVector[location] = input.etaModule;
248 std::vector<Eigen::VectorXd> vectorOfEigen;
249 vectorOfEigen.push_back(valuesVector);
250 return vectorOfEigen;
258 if (!input)
return {};
264 if (!nn_collection.
isValid()) {
283 if (!input)
return {};
290 if (!nn_collection.
isValid()) {
303 const std::vector<double>& inputData)
const{
305 std::vector<double> resultNN_TTN{};
312 ATH_MSG_FATAL(
"NnClusterizationFactory::estimateNumberOfParticlesTTN: nullptr returned for TrainedNetwork");
317 ATH_MSG_VERBOSE(
" TTN Prob of n. particles (1): " << resultNN_TTN[0] <<
318 " (2): " << resultNN_TTN[1] <<
319 " (3): " << resultNN_TTN[2]);
326 std::vector<double>
result(3,0.0);
328 if (!lwtnn_collection.
isValid()) {
332 if (lwtnn_collection->empty()){
339 Eigen::VectorXd
discriminant = lwtnn_collection->at(0)->compute(input);
344 const auto inverseSum = 1./(num0+num1+num2);
345 result[0] = num0 * inverseSum;
346 result[1] = num1 * inverseSum;
347 result[2] = num2 * inverseSum;
355 std::vector<Amg::Vector2D>
358 std::vector<Amg::MatrixX> &
errors,
359 int numberSubClusters)
const{
371 if (!nn_collection.
isValid()) {
384 std::vector<Amg::Vector2D>
388 std::vector<Amg::MatrixX> &
errors,
389 int numberSubClusters)
const{
394 if (!input)
return {};
401 if (!nn_collection.
isValid()) {
412 std::vector<Amg::Vector2D>
414 const std::vector<double>& inputData,
417 int numberSubClusters,
418 std::vector<Amg::MatrixX> &
errors)
const{
420 std::vector<Amg::Vector2D> allPositions{};
421 const auto endNnIdx = nn_collection.size();
422 if (numberSubClusters>0 and
static_cast<unsigned int>(numberSubClusters) <
m_maxSubClusters) {
423 const auto subClusterIndex = numberSubClusters-1;
428 if (not(networkIndex < endNnIdx)){
429 ATH_MSG_FATAL(
"estimatePositionsTTN: Requested collection index, "<< networkIndex <<
" is out of range.");
432 auto *
const pNetwork = nn_collection[networkIndex].get();
435 assert( position1P.size() % 2 == 0);
436 for (
unsigned int i=0;
i<position1P.size()/2 ; ++
i) {
440 std::vector<double> inputDataNew=inputData;
441 inputDataNew.reserve( inputDataNew.size() + numberSubClusters*2);
442 assert(
static_cast<unsigned int>(numberSubClusters*2) <= position1P.size() );
443 for (
unsigned int i=0; i<static_cast<unsigned int>(numberSubClusters*2); ++
i) {
444 inputDataNew.push_back(position1P[
i]);
450 if ((not (xNetworkIndex < endNnIdx)) or (not (yNetworkIndex < endNnIdx))){
451 ATH_MSG_FATAL(
"estimatePositionsTTN: A requested collection index, "<< xNetworkIndex <<
" or "<< yNetworkIndex <<
"is out of range.");
454 auto *pxNetwork = nn_collection.at(xNetworkIndex).get();
455 auto *pyNetwork = nn_collection.at(yNetworkIndex).get();
460 std::vector<Amg::MatrixX> errorMatrices1;
462 allPositions.reserve( allPositions.size() + myPosition1.size());
464 for (
unsigned int i=0;
i<myPosition1.size();
i++){
465 allPositions.push_back(myPosition1[
i]);
466 errors.push_back(errorMatrices1[
i]);
473 std::vector<Amg::Vector2D>
477 int numberSubClusters,
478 std::vector<Amg::MatrixX> &
errors)
const {
480 if (not lwtnn_collection.
isValid()) {
484 if (lwtnn_collection->empty()){
490 std::vector<double> positionValues{};
491 std::vector<Amg::MatrixX> errorMatrices;
492 errorMatrices.reserve(numberSubClusters);
493 positionValues.reserve(numberSubClusters * 2);
494 std::size_t outputNode(0);
495 for (
int cluster = 1; cluster < numberSubClusters+1; cluster++) {
498 const auto pNetwork = lwtnn_collection->find(numberSubClusters);
499 const bool validGraph = (pNetwork != lwtnn_collection->end()) and (pNetwork->second !=
nullptr);
500 if (not validGraph) {
501 std::string infoMsg =
"Acceptable numbers of subclusters for the lwtnn collection:\n ";
502 for (
const auto & pair: **lwtnn_collection){
505 infoMsg +=
"\nNumber of subclusters requested : "+
std::to_string(numberSubClusters);
507 ATH_MSG_FATAL(
"estimatePositionsLWTNN: No lwtnn network found for the number of clusters.\n"
508 <<
" If you are outside the valid range for an lwtnn-based configuration, please run with useNNTTrainedNetworks instead.\n Key = "
512 if(numberSubClusters==1) {
514 }
else if(numberSubClusters==2) {
516 }
else if(numberSubClusters==3) {
519 ATH_MSG_FATAL(
"Cannot evaluate LWTNN networks with " << numberSubClusters <<
" numberSubClusters" );
526 Eigen::VectorXd position = lwtnn_collection->at(numberSubClusters)->compute(input, {}, outputNode);
527 ATH_MSG_DEBUG(
"Testing for numberSubClusters " << numberSubClusters <<
" and cluster " << cluster);
528 for (
int i=0;
i<position.rows();
i++) {
531 positionValues.push_back(position[1]);
532 positionValues.push_back(position[2]);
535 const float rawRmsX = std::sqrt(1.0/position[3]);
536 const float rawRmsY = std::sqrt(1.0/position[4]);
540 ATH_MSG_DEBUG(
" Estimated RMS errors (1) x: " << rmsX <<
", y: " << rmsY);
546 errorMatrices.push_back(erm);
550 errors=std::move(errorMatrices);
557 constexpr
double pitch = 0.05;
558 const double corrected = posPixels * pitch;
564 std::vector<float>& pitches)
const{
565 double p = posPixels + (
m_sizeY - 1) * 0.5;
567 double p_center = -100;
570 if (
p >=
i and
p <= (
i + 1)) p_Y = p_actual + (
p -
i + 0.5) * pitches.at(
i);
571 if (
i == (
m_sizeY - 1) / 2) p_center = p_actual + 0.5 * pitches.at(
i);
572 p_actual += pitches.at(
i);
574 return std::abs(p_Y - p_center);
579 std::vector<double>& outputY,
580 std::vector<Amg::MatrixX>& errorMatrix,
581 int nParticles)
const{
582 int sizeOutputX=outputX.size()/nParticles;
583 int sizeOutputY=outputY.size()/nParticles;
590 errorMatrix.reserve( errorMatrix.size() + nParticles);
591 for (
int i=0;
i<nParticles;
i++){
593 for (
int u=0;
u<sizeOutputX;
u++){
594 sumValuesX+=outputX[
i*sizeOutputX+
u];
597 for (
int u=0;
u<sizeOutputY;
u++){
598 sumValuesY+=outputY[
i*sizeOutputY+
u];
600 ATH_MSG_VERBOSE(
" minimumX: " << minimumX <<
" maximumX: " << maximumX <<
" sizeOutputX " << sizeOutputX);
601 ATH_MSG_VERBOSE(
" minimumY: " << minimumY <<
" maximumY: " << maximumY <<
" sizeOutputY " << sizeOutputY);
603 for (
int u=0;
u<sizeOutputX;
u++){
604 RMSx+=outputX[
i*sizeOutputX+
u]/sumValuesX*
std::pow(minimumX+(maximumX-minimumX)/(
double)(sizeOutputX-2)*(
u-1./2.),2);
606 RMSx=std::sqrt(RMSx);
608 double intervalErrorX=3*RMSx;
610 int minBinX=(
int)(1+(-intervalErrorX-minimumX)/(maximumX-minimumX)*(
double)(sizeOutputX-2));
611 int maxBinX=(
int)(1+(intervalErrorX-minimumX)/(maximumX-minimumX)*(
double)(sizeOutputX-2));
612 if (maxBinX>sizeOutputX-1) maxBinX=sizeOutputX-1;
613 if (minBinX<0) minBinX=0;
616 for (
int u=minBinX;
u<maxBinX+1;
u++){
617 RMSx+=outputX[
i*sizeOutputX+
u]/sumValuesX*
std::pow(minimumX+(maximumX-minimumX)/(
double)(sizeOutputX-2)*(
u-1./2.),2);
619 RMSx=std::sqrt(RMSx);
621 for (
int u=0;
u<sizeOutputY;
u++){
622 RMSy+=outputY[
i*sizeOutputY+
u]/sumValuesY*
std::pow(minimumY+(maximumY-minimumY)/(
double)(sizeOutputY-2)*(
u-1./2.),2);
624 RMSy=std::sqrt(RMSy);
626 double intervalErrorY=3*RMSy;
628 int minBinY=(
int)(1+(-intervalErrorY-minimumY)/(maximumY-minimumY)*(
double)(sizeOutputY-2));
629 int maxBinY=(
int)(1+(intervalErrorY-minimumY)/(maximumY-minimumY)*(
double)(sizeOutputY-2));
630 if (maxBinY>sizeOutputY-1) maxBinY=sizeOutputY-1;
631 if (minBinY<0) minBinY=0;
634 for (
int u=minBinY;
u<maxBinY+1;
u++){
635 RMSy+=outputY[
i*sizeOutputY+
u]/sumValuesY*
std::pow(minimumY+(maximumY-minimumY)/(
double)(sizeOutputY-2)*(
u-1./2.),2);
637 RMSy=std::sqrt(RMSy);
638 ATH_MSG_VERBOSE(
"Computed error, sigma(X) " << RMSx <<
" sigma(Y) " << RMSy );
643 errorMatrix.push_back(erm);
648 std::vector<Amg::Vector2D>
657 ATH_MSG_ERROR(
"Dynamic cast failed at line "<<__LINE__<<
" of NnClusterizationFactory.cxx.");
660 int numParticles=output.size()/2;
661 int columnWeightedPosition=input.columnWeightedPosition;
662 int rowWeightedPosition=input.rowWeightedPosition;
663 ATH_MSG_VERBOSE(
" REF POS columnWeightedPos: " << columnWeightedPosition <<
" rowWeightedPos: " << rowWeightedPosition );
664 bool applyRecentering=
false;
666 applyRecentering=
true;
669 applyRecentering=
true;
671 std::vector<Amg::Vector2D> positions;
672 for (
int u=0;
u<numParticles;
u++){
676 posXid=
back_posX(output[2*
u],applyRecentering)+rowWeightedPosition;
677 posYid=
back_posY(output[2*
u+1])+columnWeightedPosition;
679 posXid=output[2*
u]+rowWeightedPosition;
680 posYid=output[2*
u+1]+columnWeightedPosition;
682 ATH_MSG_VERBOSE(
" N. particle: " <<
u <<
" idx posX " << posXid <<
" posY " << posYid );
684 const auto & [posXid_int, coercedX]=coerceToIntRange(posXid+0.5);
685 const auto & [posYid_int, coercedY]=coerceToIntRange(posYid+0.5);
686 if (coercedX or coercedY){
687 ATH_MSG_WARNING(
"X or Y position value has been limited in range; original values are (" << posXid<<
", "<<posYid<<
")");
690 ATH_MSG_VERBOSE(
" N. particle: " <<
u <<
" TO INTEGER idx posX " << posXid_int <<
" posY " << posYid_int );
692 InDetDD::SiCellId cellIdOfPositionDiscrete=design->cellIdOfPosition(siLocalPositionDiscrete);
693 if ( not cellIdOfPositionDiscrete.
isValid()){
694 ATH_MSG_WARNING(
" Cell is outside validity region with index Y: " << posYid_int <<
" and index X: " << posXid_int <<
". Not foreseen... " );
697 double pitchY = diodeParameters.
width().
xEta();
698 double pitchX = diodeParameters.
width().
xPhi();
700 <<
" Translated weighted position : " << siLocalPositionDiscrete.
xEta() );
702 InDetDD::SiLocalPosition siLocalPositionDiscreteOneRowMoreOneColumnMore(design->positionFromColumnRow(posYid_int+1,posXid_int+1));
703 ATH_MSG_VERBOSE(
" Translated weighted position +1col +1row phi: " << siLocalPositionDiscreteOneRowMoreOneColumnMore.
xPhi()
704 <<
" Translated weighted position +1col +1row eta: " << siLocalPositionDiscreteOneRowMoreOneColumnMore.
xEta() );
707 pitchX*(posXid-(
double)posXid_int));
709 if (input.ClusterPixBarrelEC == 0){
710 if (not input.useTrackInfo){
718 siLocalPosition(siLocalPositionDiscrete.
xEta()+pitchY*(posYid-(
double)posYid_int),
719 siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)+lorentzShift);
720 ATH_MSG_VERBOSE(
" Translated final position phi: " << siLocalPosition.
xPhi() <<
" eta: " << siLocalPosition.
xEta() );
721 const auto halfWidth{design->width()*0.5};
722 if (siLocalPositionDiscrete.
xPhi() > halfWidth){
725 ATH_MSG_WARNING(
" Corrected out of boundary cluster from x(phi): " << siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)
726 <<
" to: " << halfWidth-1
e-6);
727 }
else if (siLocalPositionDiscrete.
xPhi() < -halfWidth) {
730 ATH_MSG_WARNING(
" Corrected out of boundary cluster from x(phi): " << siLocalPositionDiscrete.
xPhi()+pitchX*(posXid-(
double)posXid_int)
731 <<
" to: " << -halfWidth+1
e-6);
733 positions.emplace_back(siLocalPosition);
743 const double tanl)
const {
744 input.useTrackInfo=
true;
747 localIntersection *= 0.250/
cos(localIntersection.theta());
748 float trackDeltaX = (
float)localIntersection.x();
749 float trackDeltaY = (
float)localIntersection.y();
750 input.theta=std::atan2(trackDeltaY,0.250);
751 input.phi=std::atan2(trackDeltaX,0.250);
754 ATH_MSG_VERBOSE(
" From track: angle phi: " << input.phi <<
" theta: " << input.theta );
761 double & tanl)
const{
780 const PixelID& pixelID = *pixelIDp;
784 ATH_MSG_ERROR(
"Dynamic cast failed at line "<<__LINE__<<
" of NnClusterizationFactory.cxx.");
789 const std::vector<Identifier>& rdos = pCluster.
rdoList();
790 const size_t rdoSize = rdos.size();
792 const std::vector<float>& chList = pCluster.
chargeList();
793 const std::vector<int>& totList = pCluster.
totList();
794 std::vector<float> chListRecreated{};
795 chListRecreated.reserve(rdoSize);
797 std::vector<int>::const_iterator
tot = totList.begin();
798 std::vector<Identifier>::const_iterator rdosBegin = rdos.begin();
799 std::vector<Identifier>::const_iterator rdosEnd = rdos.end();
800 std::vector<int> totListRecreated{};
801 totListRecreated.reserve(rdoSize);
802 std::vector<int>::const_iterator totRecreated = totListRecreated.begin();
807 for ( ; rdosBegin!= rdosEnd and
tot != totList.end(); ++
tot, ++rdosBegin, ++totRecreated ){
813 std::array<InDetDD::PixelDiodeTree::CellIndexType,2> diode_idx
818 auto diode_type = design->getDiodeType(si_param);
820 && design->numberOfConnectedCells( design->readoutIdOfCell(
InDetDD::SiCellId(diode_idx[0],diode_idx[1])))>1) {
824 float charge = calibData->
getCharge(diode_type, moduleHash, feValue, tot0);
825 chListRecreated.push_back(
charge);
826 totListRecreated.push_back(tot0);
829 rdosBegin = rdos.begin();
830 rdosEnd = rdos.end();
832 tot = totList.begin();
833 totRecreated = totListRecreated.begin();
835 std::vector<float>::const_iterator
charge = chListRecreated.begin();
836 std::vector<float>::const_iterator chargeEnd = chListRecreated.end();
837 tot = totListRecreated.begin();
838 std::vector<int>::const_iterator totEnd = totListRecreated.end();
845 for (; (rdosBegin!= rdosEnd) and (
charge != chargeEnd) and (
tot != totEnd); ++rdosBegin, ++
charge, ++
tot){
851 sumOfWeightedPositions += (*charge)*siLocalPosition;
852 sumOfTot += (*charge);
854 sumOfWeightedPositions += ((
double)(*
tot))*siLocalPosition;
863 sumOfWeightedPositions /= sumOfTot;
866 InDetDD::SiCellId cellIdWeightedPosition=design->cellIdOfPosition(sumOfWeightedPositions);
868 if (!cellIdWeightedPosition.
isValid()){
871 int columnWeightedPosition=cellIdWeightedPosition.
etaIndex();
872 int rowWeightedPosition=cellIdWeightedPosition.
phiIndex();
873 ATH_MSG_VERBOSE(
" weighted pos row: " << rowWeightedPosition <<
" col: " << columnWeightedPosition );
874 int centralIndexX=(
m_sizeX-1)/2;
875 int centralIndexY=(
m_sizeY-1)/2;
876 if (std::abs(rowWeightedPosition-rowMin)>centralIndexX or
877 std::abs(rowWeightedPosition-rowMax)>centralIndexX){
878 ATH_MSG_VERBOSE(
" Cluster too large rowMin" << rowMin <<
" rowMax " << rowMax <<
" centralX " << centralIndexX);
881 if (std::abs(columnWeightedPosition-colMin)>centralIndexY or
882 std::abs(columnWeightedPosition-colMax)>centralIndexY){
883 ATH_MSG_VERBOSE(
" Cluster too large colMin" << colMin <<
" colMax " << colMax <<
" centralY " << centralIndexY);
886 input.matrixOfToT.reserve(
m_sizeX);
888 input.matrixOfToT.emplace_back(
m_sizeY, 0.0);
890 input.vectorOfPitchesY.assign(
m_sizeY, 0.4);
891 rdosBegin = rdos.begin();
892 charge = chListRecreated.begin();
893 chargeEnd = chListRecreated.end();
894 tot = totListRecreated.begin();
895 ATH_MSG_VERBOSE(
" Putting together the n. " << rdos.size() <<
" rdos into a matrix." );
899 input.ClusterPixBarrelEC=(
int)pixelID.
barrel_ec(pixidentif);
900 for (;(
charge != chargeEnd) and (rdosBegin!= rdosEnd); ++rdosBegin, ++
charge, ++
tot){
902 unsigned int absrow = pixelID.
phi_index(rId)-rowWeightedPosition+centralIndexX;
903 unsigned int abscol = pixelID.
eta_index(rId)-columnWeightedPosition+centralIndexY;
914 double pitchY = diodeParameters.
width().
xEta();
916 input.matrixOfToT[absrow][abscol]=*
charge;
918 input.matrixOfToT[absrow][abscol]=(
double)(*
tot);
921 if (
m_addIBL and (input.ClusterPixLayer==0) and (input.ClusterPixBarrelEC==0)){
922 input.matrixOfToT[absrow][abscol]*=3;
926 if ( (input.ClusterPixLayer==0) and (input.ClusterPixBarrelEC==0)){
927 input.matrixOfToT[absrow][abscol]*=3;
932 if (std::abs(pitchY-0.4)>1
e-5){
933 input.vectorOfPitchesY[abscol]=pitchY;
937 ATH_MSG_VERBOSE(
" Layer number: " << input.ClusterPixLayer <<
" Barrel / endcap: " << input.ClusterPixBarrelEC );
938 input.useTrackInfo=
false;
946 float trkphicomp = my_track.dot(my_phiax);
947 float trketacomp = my_track.dot(my_etaax);
948 float trknormcomp = my_track.dot(my_normal);
949 double bowphi = std::atan2(trkphicomp,trknormcomp);
950 double boweta = std::atan2(trketacomp,trknormcomp);
952 if(bowphi > M_PI_2) bowphi -=
M_PI;
953 if(bowphi < -M_PI_2) bowphi +=
M_PI;
954 int readoutside = design->readoutSide();
958 if (boweta>M_PI_2) boweta-=
M_PI;
959 if (boweta<-M_PI_2) boweta+=
M_PI;
962 input.rowWeightedPosition=rowWeightedPosition;
963 input.columnWeightedPosition=columnWeightedPosition;
964 ATH_MSG_VERBOSE(
" RowWeightedPosition: " << rowWeightedPosition <<
" ColWeightedPosition: " << columnWeightedPosition );