00001 #include "TrimRangeAlgorithm.h"
00002 #include "AnalysisAlgorithmMap.h"
00003 #include "AnalysisService.h"
00004 #include "Sct/SctParameters.h"
00005 #include "Sct/UnsupportedOperationError.h"
00006 #include "SctData/TrimRangeTestResult.h"
00007 #include "SctData/FitScanResult.h"
00008 #include "SctData/FitObject.h"
00009 #include "SctData/ModuleDefect.h"
00010 #include "SctData/ModuleConfiguration.h"
00011 #include "SctData/ChipConfiguration.h"
00012 #include "SctData/ResponseCurve.h"
00013 #include <boost/shared_ptr.hpp>
00014 #include <algorithm>
00015 #include <memory>
00016
00017 using namespace Sct;
00018 using namespace SctData;
00019 using namespace boost;
00020
00021 namespace SctAnalysis {
00022
00023 bool TrimRangeAlgorithm::inMap = AnalysisAlgorithmMap::instance().setAlgorithm("TrimRangeTest", auto_ptr<AnalysisAlgorithm>(new TrimRangeAlgorithm()));
00024
00025 shared_ptr<AnalysisAlgorithm> TrimRangeAlgorithm::clone(const TestData& testData, const string& moduleName) const throw() {
00026 return shared_ptr<AnalysisAlgorithm>(new TrimRangeAlgorithm(testData, moduleName));
00027 }
00028
00029 bool TrimRangeAlgorithm::s_targetVariation = false;
00030 bool TrimRangeAlgorithm::s_rangeVariation = true;
00031
00032 void TrimRangeAlgorithm::canAddFitScanResult(const string& name) throw(LogicError, IoError) {
00033
00034 bool debug=false;
00035
00036 shared_ptr<TrimRangeTestResult> result = dynamic_pointer_cast<TrimRangeTestResult> ( getTestResult() );
00037
00038 if (result.get()==0){
00039
00040 result = shared_ptr<TrimRangeTestResult> (new TrimRangeTestResult());
00041 setTestResult(result);
00042 initializeTestResult();
00043 }
00044
00045 addFit(name);
00046
00047
00048 if ( !result->hasAllFits() ) return;
00049
00050
00051
00052
00053
00054
00055 std::vector<TrimRange> all_ranges = createRanges(*result);
00056
00057
00058
00059
00060
00061
00062 shared_ptr<SctData::TrimRangeTestResult::ChipTrimData> dataArray[all_ranges.size()][nChipModule];
00063
00064
00065 for (unsigned irange=0; irange<all_ranges.size(); ++irange){
00066
00067 TrimRange& range = all_ranges[irange];
00068
00069
00070 for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00071 dataArray[irange][ichip] =
00072 shared_ptr<TrimRangeTestResult::ChipTrimData>(new TrimRangeTestResult::ChipTrimData());
00073
00074
00075 for (unsigned ipoint=0; ipoint<range.points.size(); ++ipoint){
00076
00077 TrimPoint& this_point = range.points[ipoint];
00078 shared_ptr<const FitScanResult> fitted=result->getFit(this_point.scan);
00079 const ModuleDefectList& fitDefects=fitted->getDefects();
00080
00081
00082 for (unsigned iChanInChip=0; iChanInChip<nChannelChip; ++iChanInChip){
00083 unsigned ichannel=iChanInChip + ichip*nChannelChip;
00084
00085
00086 Stat<TrimRangeTestResult::TrimData>& trdt = dataArray[irange][ichip]
00087 ->channelData.modifyAt(iChanInChip);
00088
00089
00090 if(fitDefects.severeDefectEncompassingElement( Channel(ichannel) )) {
00091 trdt.valid=false;
00092 if (debug) {
00093 cout << "Severe defect on Channel " << ichannel << endl;
00094 fitDefects.getDefectsEncompassingElement( Channel(ichannel))->print(cout);
00095 }
00096 }
00097 if (trdt.valid){
00098 float gr_mean = fitted->getChannelFit(ichannel).getParameter(1);
00099 float gr_value = this_point.value;
00100 trdt.value.graph.push_back(std::make_pair(gr_mean, gr_value));
00101 }
00102 }
00103 }
00104 }
00105 }
00106
00107
00108
00109
00110
00111
00112
00113 std::vector<float> target;
00114 for (unsigned itarg=0; itarg<nTargets(); ++itarg){
00115 target.push_back (firstTarget() + itarg * targetStep());
00116 }
00117
00118 shared_ptr<const TrimRangeTestResult::ChipTrim> trimArray[all_ranges.size()][nChipModule][nTargets()];
00119
00120
00121
00122
00123
00124 for (unsigned irange=0; irange<all_ranges.size(); ++irange){
00125 for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00126
00127 if (dataArray[irange][ichip].get()==0){
00128 throw InvariantViolatedError("TrimRangeAlgorithm: dataArray pointer should not be zero!", __FILE__, __LINE__);
00129 }
00130 doTrimDataFit( *dataArray[irange][ichip] );
00131 for (unsigned itarget=0; itarget<nTargets(); ++itarget){
00132
00133 trimArray[irange][ichip][itarget] = getChipTrim(*dataArray[irange][ichip],
00134 target[itarget],
00135 all_ranges[irange].range);
00136 }
00137 }
00138 }
00139
00140
00141
00142
00143
00144 unsigned best_target_for_chip[nChipModule];
00145 unsigned best_range_for_chip[nChipModule];
00146
00147
00148 if ( !allowTrimTargetVariation() && !allowTrimRangeVariation() ){
00149 unsigned max_trimmed=0;
00150 unsigned target_lo=0, target_hi=0;
00151
00152 for (unsigned irange=0; irange<all_ranges.size(); ++irange){
00153 for( unsigned itarget=0; itarget<nTargets(); ++itarget){
00154 unsigned n_trimmed=0;
00155
00156 for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00157 n_trimmed+=trimArray[irange][ichip][itarget]->channelTrim.n();
00158
00159 }
00160 if (n_trimmed>max_trimmed) {
00161 target_lo=itarget;
00162 best_range_for_chip[0] = irange;
00163 max_trimmed=n_trimmed;
00164 }
00165 if (n_trimmed==max_trimmed && irange==best_range_for_chip[0]) {
00166 target_hi=itarget;
00167 }
00168 }
00169 }
00170 for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00171 best_range_for_chip[ichip]=best_range_for_chip[0];
00172 best_target_for_chip[ichip]=(target_hi+target_lo)/2;
00173 }
00174 } else
00175
00176
00177 if ( allowTrimTargetVariation() && !allowTrimRangeVariation() ){
00178 unsigned target_lo[nChipModule];
00179 unsigned target_hi[nChipModule];
00180 unsigned max_trimmed[nChipModule];
00181 for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00182 target_lo[ichip]=target_hi[ichip]=max_trimmed[ichip]=0;
00183 }
00184
00185 for (unsigned irange=0; irange<all_ranges.size(); ++irange){
00186 for( unsigned itarget=0; itarget<nTargets(); ++itarget){
00187 unsigned n_trimmed=0;
00188
00189 for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00190 n_trimmed = trimArray[irange][ichip][itarget]->channelTrim.n();
00191
00192 if (n_trimmed>max_trimmed[ichip] ) {
00193 target_lo[ichip]=itarget;
00194 best_range_for_chip[ichip] = irange;
00195 }
00196 if (n_trimmed==max_trimmed[ichip] && irange==best_range_for_chip[ichip]) {
00197 target_hi[ichip]=itarget;
00198 }
00199 }
00200 }
00201 }
00202 for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00203 best_target_for_chip[ichip]=(target_hi[ichip]+target_lo[ichip])/2;
00204 }
00205 } else
00206
00207
00208 if ( !allowTrimTargetVariation() && allowTrimRangeVariation() ){
00209
00210 unsigned target_lo=0;
00211 unsigned target_hi=0;
00212 unsigned total_channels_trimmed_max=0;
00213 unsigned total_range_lo=0;
00214
00215 for( unsigned itarget=0; itarget<nTargets(); ++itarget){
00216 if (debug) cout << "TARGET " << itarget << endl;
00217 unsigned total_channels_trimmed=0;
00218 unsigned range_total=0;
00219
00220 for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00221 unsigned best_range=0;
00222 unsigned max = 0;
00223
00224 for (unsigned irange=0; irange<all_ranges.size(); ++irange){
00225 unsigned n_trimmed = trimArray[irange][ichip][itarget]->channelTrim.n();
00226
00227
00228 if (n_trimmed > max ||
00229 ( all_ranges[irange].range < all_ranges[best_range].range
00230 && n_trimmed==max)) {
00231 best_range = irange;
00232 max = n_trimmed;
00233 }
00234 }
00235
00236 total_channels_trimmed+=max;
00237 range_total+=all_ranges[best_range].range ;
00238 }
00239 if (debug) cout << " TOTAL = " << total_channels_trimmed << " for " << range_total << endl;
00240
00241 if (total_channels_trimmed > total_channels_trimmed_max ||
00242 ( total_channels_trimmed == total_channels_trimmed_max &&
00243 range_total < total_range_lo ) ) {
00244 target_lo=itarget;
00245 total_range_lo=range_total;
00246 total_channels_trimmed_max=total_channels_trimmed;
00247 if (debug) cout << " ...... modified lower target" << endl;
00248 }
00249
00250 if (total_channels_trimmed == total_channels_trimmed_max &&
00251 total_range_lo==range_total ){
00252 target_hi=itarget;
00253 if (debug) cout << " ...... modified upper target" << endl;
00254 }
00255
00256 }
00257 for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00258 best_target_for_chip[ichip]=(target_hi+target_lo)/2;
00259
00260 if (debug) cout << endl << " --> CHIP " << ichip << endl;
00261 unsigned max=0;
00262 best_range_for_chip[ichip]=0;
00263
00264 for (unsigned irange=0; irange<all_ranges.size(); ++irange){
00265 unsigned n_trimmed = trimArray[irange][ichip][best_target_for_chip[ichip]]->channelTrim.n();
00266 if (debug) cout << "R" << irange << " -> " << n_trimmed << endl;
00267 if (n_trimmed> max ||
00268 ( all_ranges[irange].range < all_ranges[best_range_for_chip[ichip]].range
00269 && n_trimmed==max)) {
00270 best_range_for_chip[ichip] = irange;
00271 max=n_trimmed;
00272 if (debug) cout << "best range changed to #" << irange << " = " << all_ranges[irange].range << endl;
00273 }
00274 }
00275 }
00276 } else {
00277 throw UnsupportedOperationError("Trim Range Algorithm not implimented for desired options!", __FILE__, __LINE__);
00278 }
00279
00280
00281 if (debug) cout << "stage 6"<<endl;
00282
00283 {
00284
00285 const ChipConfiguration& config=result->getFit(0)->getConfiguration().getChipConfiguration(0);
00286 auto_ptr<ResponseCurve> rc = ResponseCurveMap::getMap().get(config);
00287 float cal_charge_mV = result->getFit(0)->getConfiguration().getChipConfiguration(0).getCalCharge()*2.5 ;
00288 float cal_charge_fC = rc->getFunction()->Eval(cal_charge_mV);
00289
00290 result->charge = cal_charge_fC;
00291 result->type = allowTrimRangeVariation() ? (unsigned)-1 : best_range_for_chip[0] ;
00292 result->algorithm = allowTrimTargetVariation() ? 1 : 0 ;
00293 }
00294
00295 bool pass = true;
00296
00297 for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00298 if (debug) cout << " CHIP " << ichip << endl;
00299 unsigned best_range = best_range_for_chip[ichip];
00300 unsigned best_target = best_target_for_chip[ichip];
00301
00302 if (debug) cout << " optimum range = " << best_range
00303 << ", target #" << best_target
00304 << " = " << target[best_target]
00305 << ", ntrim=" << trimArray[best_range][ichip][best_target_for_chip[ichip]]->channelTrim.n() << endl;
00306
00307 result->chipTrim[ichip] =
00308 trimArray [best_range] [ichip] [best_target];
00309 result->chipTrimData[ichip]=
00310 dataArray[best_range] [ichip];
00311
00312 const Stats<double> offsets = dataArray[best_range][ichip]->getOffsets();
00313 const Stats<double> steps = dataArray[best_range][ichip]->getSteps();
00314
00315 double stepmin=0, stepmax=16;
00316 switch (all_ranges[best_range].range){
00317 case 0 : stepmin = 1.5 ; stepmax = 5.0 ; break;
00318 case 1 : stepmin = 5.0 ; stepmax = 8.5 ; break;
00319 case 2 : stepmin = 8.5 ; stepmax = 12.0; break;
00320 case 3 : stepmin = 12.0; stepmax = 15.5; break;
00321 }
00322
00323 if (steps.mean() < stepmin || steps.mean() > stepmax ){
00324 result->getDefects().addDefect(ModuleDefect::TR_RANGE, Chip(ichip));
00325 }
00326
00327 for (unsigned iChanInChip=0; iChanInChip<nChannelChip ; ++iChanInChip){
00328
00329 if (steps.getAt(iChanInChip).valid &&
00330 ( fabs( steps.getAt(iChanInChip).value - steps.mean() )
00331 > ModuleDefect::TR_STEP.getParameter() * sqrt(steps.var() ) ) ) {
00332 result->getDefects().addDefect(ModuleDefect::TR_STEP,
00333 Channel(ichip*nChannelChip+iChanInChip));
00334 pass = false;
00335 }
00336
00337 if (offsets.getAt(iChanInChip).valid &&
00338 ( fabs( offsets.getAt(iChanInChip).value - offsets.mean() )
00339 > ModuleDefect::TR_OFFSET.getParameter() * sqrt(offsets.var() ) ) ) {
00340 result->getDefects().addDefect(ModuleDefect::TR_OFFSET,
00341 Channel(ichip*nChannelChip+iChanInChip));
00342 pass = false;
00343 }
00344
00345 if (result->chipTrim[ichip]->channelTrim.getAt(iChanInChip).valid==false){
00346 result->getDefects().addDefect(ModuleDefect::TR_NOTRIM, Channel(ichip*nChannelChip + iChanInChip));
00347 pass = false;
00348 }
00349 }
00350 }
00351
00352 result->setPassed(pass);
00353
00354 finish();
00355 }
00356
00357
00358
00359 void TrimRangeAlgorithm::doTrimDataFit(TrimRangeTestResult::ChipTrimData& chipData) throw() {
00360 for (unsigned iChanInChip=0; iChanInChip<nChannelChip; ++iChanInChip){
00361 Stat<TrimRangeTestResult::TrimData>& trimdata = chipData.channelData.modifyAt(iChanInChip);
00362
00363 trimdata.valid=false;
00364 trimdata.value.p0 = 0;
00365 trimdata.value.p1 = 0;
00366
00367 if (trimdata.value.graph.empty()) continue;
00368
00370 float xbar=0, ybar=0, x2bar=0, xybar=0;
00371 const unsigned n=trimdata.value.graph.size();
00372
00373 for (unsigned ipoint = 0; ipoint<n; ++ipoint){
00374 const float& x=trimdata.value.graph[ipoint].first;
00375 const float& y=trimdata.value.graph[ipoint].second;
00376 xbar += x;
00377 ybar += y;
00378 x2bar += x*x;
00379 xybar += x*y;
00380 }
00381
00382 const float det = n*x2bar - xbar*xbar;
00383 if (det>0){
00384 trimdata.value.p0 = (x2bar*ybar - xbar*xybar) / det;
00385 trimdata.value.p1 = (n*xybar - xbar*ybar) / det;
00386 trimdata.valid=trimdata.value.p1>0;
00387 }
00388 }
00389 }
00390
00391
00392 std::vector<TrimRangeAlgorithm::TrimRange> TrimRangeAlgorithm::createRanges(const TestResult& result) throw() {
00393
00394
00395 std::vector<TrimRangeAlgorithm::TrimRange> all_ranges;
00396
00397 bool inputRangeVariesChipToChip=false;
00398
00399 for (unsigned iscan=0; iscan<result.getNScans(); ++iscan){
00400 shared_ptr<const FitScanResult> fitted = result.getFit(iscan);
00401 for (unsigned ichip=1; ichip<nChipModule; ichip++){
00402 if (fitted->getConfiguration().getChipConfiguration(ichip).getTrimRange()
00403 != fitted->getConfiguration().getChipConfiguration(0).getTrimRange()){
00404 inputRangeVariesChipToChip=true;
00405 }
00406 }
00407 }
00408
00409 for (unsigned iscan=0; iscan<result.getNScans(); ++iscan){
00410 shared_ptr<const FitScanResult> fitted = result.getFit(iscan);
00411
00412
00413 int range_value=fitted->getConfiguration().getChipConfiguration(0).getTrimRange();
00414
00415 int trim_value=fitted->getConfiguration().getChipConfiguration(0).getTrim(0);
00416
00417 std::vector<TrimRange>::iterator it = all_ranges.begin();
00418 while (it!=all_ranges.end()){
00419 if ( (*it).range == range_value ) {break;}
00420 ++it;
00421 }
00422 if (it==all_ranges.end() ){
00423
00424 if ( !inputRangeVariesChipToChip || all_ranges.empty() ){
00425 all_ranges.push_back(TrimRange(range_value));
00426 }
00427 it=all_ranges.end()-1;
00428 }
00429
00430
00431 (*it).points.push_back(TrimPoint(trim_value, iscan) );
00432 }
00433
00434 sort(all_ranges.begin(), all_ranges.end());
00435 return all_ranges;
00436 }
00437
00438
00439 shared_ptr<const TrimRangeTestResult::ChipTrim> TrimRangeAlgorithm::getChipTrim(const TrimRangeTestResult::ChipTrimData& data, const float target, const short unsigned range) throw(){
00440
00441 shared_ptr<SctData::TrimRangeTestResult::ChipTrim> chipTrim (new SctData::TrimRangeTestResult::ChipTrim() );
00442 chipTrim->target=target;
00443 chipTrim->range =range;
00444
00445 for (unsigned iChanInChip=0; iChanInChip<nChannelChip; ++iChanInChip){
00446 Stat<TrimRangeTestResult::TrimData> d= data.channelData.getAt(iChanInChip);
00447 Stat<TrimRangeTestResult::Trim>& t= chipTrim->channelTrim.modifyAt(iChanInChip);
00448
00449 if (!d.valid){t.valid=false; continue; }
00450
00451
00452 int i_trim=d.value.getTrim(target);
00453
00454
00455 if ( i_trim>=0 && i_trim<=15) {
00456 t.valid=true;
00457 t.value.trim = i_trim;
00458 } else {
00459 t.valid=false;
00460 if (i_trim<0) t.value.trim = 0;
00461 if (i_trim>15) t.value.trim = 15;
00462 }
00463
00464 t.value.vthr = d.value.getVthr(i_trim);
00465 }
00466 return chipTrim;
00467 }
00468
00469
00470 }