Main Page   Modules   Namespace List   Class Hierarchy   Data Structures   File List   Namespace Members   Data Fields   Globals   Related Pages  

TrimRangeAlgorithm.cpp

Go to the documentation of this file.
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     //Create and initialize an TrimRangeTestResult
00040     result = shared_ptr<TrimRangeTestResult> (new TrimRangeTestResult());
00041     setTestResult(result);
00042     initializeTestResult();
00043     }
00044     
00045     addFit(name);
00046 
00047     // we need all of the fits
00048     if ( !result->hasAllFits() ) return;
00049     
00050     /* 
00051        STAGE 1 : make sense of the incoming data.
00052        make a vector of all ranges, all points in those ranges and the 
00053        appropriate scan number.
00054     */
00055     std::vector<TrimRange> all_ranges = createRanges(*result);
00056     
00057     /* 
00058        STAGE 2 : make graphs of trim against vt50 for each chip
00059        and each channel and each range
00060     */
00061     
00062     shared_ptr<SctData::TrimRangeTestResult::ChipTrimData> dataArray[all_ranges.size()][nChipModule];
00063     
00064     // loop over trim ranges
00065     for (unsigned irange=0; irange<all_ranges.size(); ++irange){
00066     
00067     TrimRange& range = all_ranges[irange];
00068     
00069     // loop over chips
00070     for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00071         dataArray[irange][ichip] =
00072         shared_ptr<TrimRangeTestResult::ChipTrimData>(new TrimRangeTestResult::ChipTrimData());
00073         
00074         // loop over trim-scan points
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         // loop over channels in that chip.
00082         for (unsigned iChanInChip=0; iChanInChip<nChannelChip; ++iChanInChip){
00083             unsigned ichannel=iChanInChip + ichip*nChannelChip;
00084             
00085             // get the relevant TrimData object
00086             Stat<TrimRangeTestResult::TrimData>& trdt = dataArray[irange][ichip]
00087             ->channelData.modifyAt(iChanInChip);
00088             
00089             // channel is valid if there are no defects on it.
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             } // if channel is valid
00102         } // loop over channels 
00103         } // loop over scan-points
00104     } // loop over chips
00105     } // loop over ranges
00106     
00107     
00108     /*
00109       STAGE 3:
00110       create a vector of target s starting from firstTarget in uniform steps
00111       to a total of ntargets
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       STAGE 4a: fit the graphs 
00122       STAGE 4b: find the number of trimmable channels for each in a series of targets
00123     */
00124     for (unsigned irange=0; irange<all_ranges.size(); ++irange){
00125     for (unsigned ichip=0; ichip<nChipModule; ++ichip){
00126         // 4a:
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         //4b:
00133         trimArray[irange][ichip][itarget] = getChipTrim(*dataArray[irange][ichip], 
00134                                 target[itarget],
00135                                 all_ranges[irange].range);
00136         }       
00137     }
00138     }
00139     
00140     /*
00141       STAGE 5 select the best trim target which trims the maximum number of channels
00142     */
00143     
00144     unsigned best_target_for_chip[nChipModule];       // index of vector targets
00145     unsigned best_range_for_chip[nChipModule];        // index of vector all_ranges
00146     
00147     // 5a no chip-to-chip variation:
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         /* find number of channels which are trimmable in the module */
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     // 5b chip-to-chip target variation:
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         /* find number of channels which are trimmable in the module */
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     // 5c chip-to-chip range variation:
00208     if ( !allowTrimTargetVariation() && allowTrimRangeVariation() ){
00209 //  cout << "stage 5c"<<endl;
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             // if this is the lowest range with the maximum number of channels:
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         // find the total number of channels trimmed
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         // know the target, get the ranges again:
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     /* STAGE 6 fill output TestResult data */
00281     if (debug) cout << "stage 6"<<endl;
00282 
00283     {
00284     // get a chip configuration for an example chip:
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 // Chip Defects:
00323     if (steps.mean() < stepmin || steps.mean() > stepmax ){
00324         result->getDefects().addDefect(ModuleDefect::TR_RANGE, Chip(ichip));
00325     }
00326 // Channel Defects:
00327     for (unsigned iChanInChip=0; iChanInChip<nChannelChip ; ++iChanInChip){
00328 // Step Defects:
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 // Offset Defects:
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 // Untrimmable Defects:
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         } // if valid
00349     }// Channel loop
00350     }// chip loop
00351     
00352     result->setPassed(pass);
00353     
00354     finish();
00355 }
00356 
00357     
00358     /* fit the trim data with a line */
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     /* interpreet the incoming data as a series of scans over different ranges */
00392     std::vector<TrimRangeAlgorithm::TrimRange> TrimRangeAlgorithm::createRanges(const TestResult& result) throw() {
00393     // Check all chips in each scan have the same range.
00394     // if they don't, then analyse all ranges together.
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         // find the trim range for module 0 
00413         int range_value=fitted->getConfiguration().getChipConfiguration(0).getTrimRange();
00414         // find the trim for channel 0
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() ){ // new trim range?
00423         // if there is chip to chip range variation, treat it all as one range
00424         if ( !inputRangeVariesChipToChip || all_ranges.empty() ){
00425             all_ranges.push_back(TrimRange(range_value));
00426         }
00427         it=all_ranges.end()-1;
00428         }
00429         
00430         // store in that range the trim value and the scan identifier.  
00431         (*it).points.push_back(TrimPoint(trim_value, iscan) );
00432     }
00433     // sort by range value.
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         // record the trim value.
00452         int i_trim=d.value.getTrim(target);
00453         
00454         // check if trimmable - if not, then do your best
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 } // end of namespace SctAnalysis

Generated on Mon Dec 15 19:36:22 2003 for SCT DAQ/DCS Software by doxygen1.3-rc3