From a1312b8339b248b7a8c17650de56f746680fe0f3 Mon Sep 17 00:00:00 2001 From: William Johnson Date: Fri, 14 Jun 2024 16:14:32 -0700 Subject: [PATCH] Improvements to Simple MDA from basic use. Make right-click matching to reference phtoopeak line a little more forgiving. Add button to select DRF if currently blank (provides some instruciton to the user). A few other little things. --- InterSpec/DetectionLimitSimple.h | 3 ++ .../app_text/DetectionLimitSimple.xml | 17 ++++++- src/DetectionLimitSimple.cpp | 38 +++++++++++----- src/DetectionLimitTool.cpp | 45 +++++++++++++++++++ src/PeakSearchGuiUtils.cpp | 28 ++++++++++-- 5 files changed, 117 insertions(+), 14 deletions(-) diff --git a/InterSpec/DetectionLimitSimple.h b/InterSpec/DetectionLimitSimple.h index f0500d35..a6802a20 100644 --- a/InterSpec/DetectionLimitSimple.h +++ b/InterSpec/DetectionLimitSimple.h @@ -156,6 +156,8 @@ class DetectionLimitSimple : public Wt::WContainerWidget void handleFitFwhmRequested(); + void handleSelectDetectorRequested(); + void handleSpectrumChanged(); void handleUserChangedRoi(); @@ -250,6 +252,7 @@ class DetectionLimitSimple : public Wt::WContainerWidget NativeFloatSpinBox *m_fwhm; Wt::WText *m_fwhmSuggestTxt; Wt::WPushButton *m_addFwhmBtn; + Wt::WPushButton *m_selectDetectorBtn; Wt::WLabel *m_continuumPriorLabel; Wt::WComboBox *m_continuumPrior; diff --git a/InterSpec_resources/app_text/DetectionLimitSimple.xml b/InterSpec_resources/app_text/DetectionLimitSimple.xml index 27bbab3b..bcca056e 100644 --- a/InterSpec_resources/app_text/DetectionLimitSimple.xml +++ b/InterSpec_resources/app_text/DetectionLimitSimple.xml @@ -3,6 +3,7 @@ Fit FWHM... + Select detector... further details... Confidence Level: ROI Lower: @@ -57,7 +58,21 @@ Limit Cont. Area DOF - + Upper + Lower + Best + ROI Range (keV) + ROI Channels + ROI Width + Det. Intrinsic Eff. + Solid angle frac. + Air transmission + Gamma Intensity + Error computing limit... + Error computing limit information: {1} + Please select a detector efficiency function. + Distance can't be negative. + Detector efficiency function does not have FWHM info - please fit for FWHM, or change detector. diff --git a/src/DetectionLimitSimple.cpp b/src/DetectionLimitSimple.cpp index fd8881fb..b161276f 100644 --- a/src/DetectionLimitSimple.cpp +++ b/src/DetectionLimitSimple.cpp @@ -210,6 +210,7 @@ DetectionLimitSimple::DetectionLimitSimple( MaterialDB *materialDB, m_fwhm( nullptr ), m_fwhmSuggestTxt( nullptr ), m_addFwhmBtn( nullptr ), + m_selectDetectorBtn( nullptr ), m_continuumPriorLabel( nullptr ), m_continuumPrior( nullptr ), m_continuumTypeLabel( nullptr ), @@ -450,10 +451,18 @@ void DetectionLimitSimple::init() m_fwhmSuggestTxt = new WText( generalInput ); m_fwhmSuggestTxt->addStyleClass( "FwhmSuggest GridThirdCol GridSixthRow GridVertCenter GridSpanTwoCol" ); + m_addFwhmBtn = new WPushButton( WString::tr("dls-fit-fwhm-btn"), generalInput ); m_addFwhmBtn->clicked().connect( this, &DetectionLimitSimple::handleFitFwhmRequested ); m_addFwhmBtn->addStyleClass( "MdaFitFwhm LightButton GridFifthCol GridSixthRow" ); + m_selectDetectorBtn = new WPushButton( WString::tr("dls-select-drf-btn"), generalInput ); + m_selectDetectorBtn->clicked().connect( this, &DetectionLimitSimple::handleSelectDetectorRequested ); + m_selectDetectorBtn->addStyleClass( "MdaFitFwhm LightButton GridFifthCol GridSixthRow" ); + + const shared_ptr drf = m_detectorDisplay->detector(); + m_addFwhmBtn->setHidden( !drf || !drf->isValid() || drf->hasResolutionInfo() ); + m_selectDetectorBtn->setHidden( drf && drf->isValid() ); m_continuumPriorLabel = new WLabel( WString::tr("dls-deon-cont-norm-label"), generalInput ); m_continuumPriorLabel->addStyleClass( "GridFirstCol GridSeventhRow GridVertCenter" ); @@ -631,13 +640,15 @@ void DetectionLimitSimple::setFwhmFromEstimate() float fwhm = 0.1f; const shared_ptr drf = m_detectorDisplay->detector(); + + m_addFwhmBtn->setHidden( !drf || !drf->isValid() || drf->hasResolutionInfo() ); + m_selectDetectorBtn->setHidden( drf && drf->isValid() ); + if( drf && drf->hasResolutionInfo() ) { - m_addFwhmBtn->hide(); fwhm = drf->peakResolutionFWHM( energy ); }else { - m_addFwhmBtn->show(); fwhm = std::max( 0.1f, PeakSearchGuiUtils::estimate_FWHM_of_foreground(energy) ); } @@ -665,11 +676,11 @@ void DetectionLimitSimple::handleUserChangedFwhm() m_fwhm->setValue( fwhm ); }//if( invalid FWHM ) + m_addFwhmBtn->setHidden( !drf || !drf->isValid() || drf->hasResolutionInfo() ); + m_selectDetectorBtn->setHidden( drf && drf->isValid() ); if( drf && drf->hasResolutionInfo() ) { - m_addFwhmBtn->hide(); - const double drf_fwhm = drf->peakResolutionFWHM( energy ); if( fabs(fwhm - drf_fwhm) > 0.1 ) { @@ -683,7 +694,6 @@ void DetectionLimitSimple::handleUserChangedFwhm() } }else { - m_addFwhmBtn->show(); const float est_fwhm = std::max( 0.1f, PeakSearchGuiUtils::estimate_FWHM_of_foreground(energy) ); char text[32] = { '\0' }; @@ -1084,6 +1094,9 @@ void DetectionLimitSimple::handleDetectorChanged( std::shared_ptrsetDetector( new_drf ); + m_addFwhmBtn->setHidden( !new_drf || !new_drf->isValid() || new_drf->hasResolutionInfo() ); + m_selectDetectorBtn->setHidden( new_drf && new_drf->isValid() ); + handleUserChangedFwhm(); m_renderFlags |= DetectionLimitSimple::RenderActions::UpdateLimit; @@ -1102,6 +1115,12 @@ void DetectionLimitSimple::handleFitFwhmRequested() }//void handleFitFwhmRequested() +void DetectionLimitSimple::handleSelectDetectorRequested() +{ + m_detectorDisplay->editDetector(); +}//void handleSelectDetectorRequested() + + void DetectionLimitSimple::handleSpectrumChanged() { m_renderFlags |= DetectionLimitSimple::RenderActions::UpdateLimit; @@ -1578,13 +1597,10 @@ SimpleDialog *DetectionLimitSimple::createDeconvolutionLimitMoreInfo() WTable *table = new WTable( contents ); table->addStyleClass( "DeconvoMoreInfoTable" ); - - - const auto print_result = [table, use_curie, measurement, roi_start, roi_end]( const DetectionLimitCalc::DeconComputeResults &result, const bool is_best, const WString typestr ){ - WString label = WString("{1} {2}").arg(typestr).arg( WString::tr("dls-Limit") ); + WString label = WString("{1} {2}").arg(typestr).arg( WString::tr( (is_best ? "Activity" : "dls-Limit") ) ); WString value = PhysicalUnits::printToBestActivityUnits( result.input.activity, 3, use_curie ); WTableCell *cell = table->elementAt( table->rowCount(), 0 ); @@ -1593,7 +1609,7 @@ SimpleDialog *DetectionLimitSimple::createDeconvolutionLimitMoreInfo() new WText( value, cell ); - label = WString("{1} {2}").arg(typestr).arg( WString::tr("dls-Limit") ); + label = WString("{1} {2}").arg(typestr).arg( WString::tr( (is_best ? "Counts" : "dls-Limit") ) ); double counts = 0.0, uncert = 0.0; for( const auto peak : result.fit_peaks ) { @@ -1762,6 +1778,8 @@ SimpleDialog *DetectionLimitSimple::createDeconvolutionLimitMoreInfo() // " source before any shielding, but accounting for nuclide age," // " per decay of the parent nuclide." ); }//if( branch_ratio > 0.0 ) + + return dialog; }//void createDeconvolutionLimitMoreInfo() diff --git a/src/DetectionLimitTool.cpp b/src/DetectionLimitTool.cpp index 42b33590..c0a5b75d 100644 --- a/src/DetectionLimitTool.cpp +++ b/src/DetectionLimitTool.cpp @@ -2045,6 +2045,51 @@ SimpleDialog *DetectionLimitTool::createCurrieRoiMoreInfoWindow( const SandiaDec " expected to lead to detection." ); + switch( limitType ) + { + case DetectionLimitTool::LimitType::Activity: + { + if( result.source_counts <= result.decision_threshold ) + { + // There is NOT enough excess counts that we would reliably detect this activity, so we + // didnt give nominal activity above, so we'll do that here + WString obs_label; + string lowerstr, upperstr, nomstr; + if( drf && (distance >= 0.0) && (gammas_per_bq > 0.0) ) + { + obs_label = "Activity"; + const float nominal_act = result.source_counts / gammas_per_bq; + + nomstr = PhysicalUnits::printToBestActivityUnits( nominal_act, 2, useCuries ) + + DetectorPeakResponse::det_eff_geom_type_postfix( det_geom ); + if( nominal_act < 0 ) + nomstr = "< " + PhysicalUnits::printToBestActivityUnits( 0.0, 2, useCuries ) + + DetectorPeakResponse::det_eff_geom_type_postfix( det_geom ); + }else + { + obs_label = "Observed counts"; + nomstr = SpecUtils::printCompact(result.source_counts, 4); + + if( result.source_counts < 0 ) + nomstr = "< 0 counts"; + }//if( drf ) / else + + nomstr += " (below Lc)"; + + cell = table->elementAt( table->rowCount(), 0 ); + new WText( obs_label, cell ); + cell = table->elementAt( table->rowCount() - 1, 1 ); + new WText( nomstr, cell ); + addTooltipToRow( "The observed signal counts is less than the "critical level", Lc," + " so a detection can not be declared, but this is the excess over expected counts/activity." ); + }//if( result.source_counts <= result.decision_threshold ) + }//case DetectionLimitTool::LimitType::Activity: + + case DetectionLimitTool::LimitType::Distance: + break; + }//switch( limitType ) + + // Add a blank row cell = table->elementAt( table->rowCount(), 0 ); txt = new WText( " ", TextFormat::XHTMLText, cell ); diff --git a/src/PeakSearchGuiUtils.cpp b/src/PeakSearchGuiUtils.cpp index cd3b0010..933e63e1 100644 --- a/src/PeakSearchGuiUtils.cpp +++ b/src/PeakSearchGuiUtils.cpp @@ -3131,7 +3131,7 @@ std::pair,int> reference_line_near_peak( Inte const double dist = fabs( l.m_energy - mean ); const double w = l.m_normalized_intensity / (0.25*sigma + dist); - if( (w > largest_w) && (l.m_energy < ux) && (l.m_energy > lx) && (dist < 4*sigma) ) + if( (w > largest_w) && (l.m_energy < ux) && (l.m_energy > lx) && (dist < 5*sigma) ) { largest_w = w; best_energy = l.m_energy; @@ -3183,8 +3183,30 @@ float reference_line_energy_near_peak( InterSpec * const interspec, const PeakDe tuple nuclide_reference_line_near( InterSpec *viewer, const float energy ) { - const double sigma = estimate_FWHM_of_foreground( energy ); - + double sigma = estimate_FWHM_of_foreground( energy ); + + // For HPGe zoomed out, its really hard to be within the 5-peak-sigmas of the reference + // line that `reference_line_near_peak(...)` requires, so we'll also take into account + // the number of pixels a peak would show up as. + // Note: `SpectrumChartD3.prototype.updateMouseCoordText(...)` basically requires within 10px + const shared_ptr hist + = viewer->displayedHistogram(SpecUtils::SpectrumType::Foreground); + if( PeakFitUtils::is_high_res(hist) ) + { + double xmin, xmax, ymin, ymax; + viewer->displayedSpectrumRange( xmin, xmax, ymin, ymax ); + + const int ww = viewer->renderedWidth(); + + if( (xmin < xmax) && ((xmax - xmin) > 50.0) && (ww > 200) ) + { + // Will assume chart plot-area is 100px narrower than total window (unchecked). + const double keV_per_pixel = (xmax - xmin) / (ww - 100); + // set peak-sigma to be 2 pixels, giving us to require 10 pixels of accuracy from the user + sigma = std::max( sigma, 2.0*keV_per_pixel ); + }//if( x-range and render size seem reasonable ) + }//if( PeakFitUtils::is_high_res(hist) ) + PeakDef tmppeak( energy, std::max(sigma,0.1), 100.0 ); const pair,int> refline