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