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