[med-svn] [SCM] aghermann branch, master, updated. 551e213a23b59b71cba6a9c3a282d1b60e21b854
Andrei Zavada
johnhommer at gmail.com
Sun Apr 21 23:17:59 UTC 2013
The following commit has been merged in the master branch:
commit 3a0fe747b1fb19cbeae4ef530925540401fdf57a
Author: Andrei Zavada <johnhommer at gmail.com>
Date: Sun Apr 14 20:41:39 2013 +0300
parse and look at individual EDF patient_id fields (patch 2/3)
diff --git a/data/mw.glade b/data/mw.glade
index f27f7f3..78add16 100644
--- a/data/mw.glade
+++ b/data/mw.glade
@@ -1546,72 +1546,6 @@ rm */*/*/.*.{psd,mc,swu}</property>
<property name="column_spacing">40</property>
<property name="row_spacing">40</property>
<child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
<object class="GtkFrame" id="fScoreCodes">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -2468,6 +2402,69 @@ rm */*/*/.*.{psd,mc,swu}</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
+ <child>
+ <object class="GtkFrame" id="fSMP1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="border_width">5</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkTable" id="table10">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">10</property>
+ <property name="n_columns">3</property>
+ <property name="column_spacing">10</property>
+ <property name="row_spacing">10</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="eScanTreeStrict">
+ <property name="label" translatable="yes">Strict EDF header check</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Accept or reject EDF sources with inaccurate DOB or gender</property>
+ <property name="use_action_appearance">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label111">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes"><b><big>Tree scanning</big></b></property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
</object>
</child>
</object>
@@ -7456,6 +7453,12 @@ dragging individual signals with <i>Alt</i>.</small></property
<child>
<placeholder/>
</child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
</object>
</child>
<child>
diff --git a/src/common/subject_id.cc b/src/common/subject_id.cc
index 21b5ac1..be566c6 100644
--- a/src/common/subject_id.cc
+++ b/src/common/subject_id.cc
@@ -106,7 +106,8 @@ str_to_dob( const string& s)
try {
t.tm_mday = stoi( *f++);
t.tm_mon = str_to_english_month(*f++);
- t.tm_year = 1900 + stoi(*f);
+ t.tm_year = stoi(*f);
+ t.tm_isdst = -1;
return mktime( &t);
} catch (...) {
return (time_t)0;
@@ -114,6 +115,36 @@ str_to_dob( const string& s)
}
+
+int
+SSubjectId::
+update_from( const SSubjectId& j)
+{
+ int mismatched_fields = 0;
+ if ( id.empty() or id == "X" )
+ id = j.id;
+ else if ( id != j.id )
+ ++mismatched_fields;
+
+ if ( name.empty() or name == "X" )
+ name = j.name;
+ else if ( name != j.name )
+ ++mismatched_fields;
+
+ if ( gender == TGender::unknown )
+ gender = j.gender;
+ else if ( gender != j.gender )
+ ++mismatched_fields;
+
+ if ( dob == (time_t)0 )
+ dob = j.dob;
+ else if ( dob != j.dob )
+ ++mismatched_fields;
+
+ return mismatched_fields;
+}
+
+
// Local Variables:
// Mode: c++
// indent-tabs-mode: 8
diff --git a/src/common/subject_id.hh b/src/common/subject_id.hh
index 5bfa7b9..49fda92 100644
--- a/src/common/subject_id.hh
+++ b/src/common/subject_id.hh
@@ -36,14 +36,15 @@ struct SSubjectId {
};
TGender gender;
- SSubjectId ( const string& id_ = "", const string& name_ = "",
- time_t dob_ = (time_t)0,
- TGender gender_ = TGender::unknown)
+ SSubjectId (const string& id_ = "", const string& name_ = "",
+ time_t dob_ = (time_t)0,
+ TGender gender_ = TGender::unknown)
: id (id_),
name (name_),
dob (dob_),
gender (gender_)
{}
+
SSubjectId (const SSubjectId& rv)
{
id = rv.id;
@@ -60,11 +61,20 @@ struct SSubjectId {
gender = rv.gender;
}
+
char gender_sign() const
{
return gender_sign(gender);
}
+ bool valid() const
+ {
+ return not id.empty() and not name.empty() and
+ gender != TGender::unknown and
+ dob != 0;
+ }
+ int update_from( const SSubjectId&);
+
static char gender_sign( TGender);
static TGender char_to_gender( char);
static time_t str_to_dob( const string&);
diff --git a/src/expdesign/loadsave.cc b/src/expdesign/loadsave.cc
index 1b93a9a..a836321 100644
--- a/src/expdesign/loadsave.cc
+++ b/src/expdesign/loadsave.cc
@@ -27,8 +27,6 @@ using namespace agh;
-
-
int
agh::CExpDesign::
load_settings()
@@ -98,7 +96,8 @@ load_settings()
int
-agh::CExpDesign::save_settings()
+agh::CExpDesign::
+save_settings()
{
libconfig::Config conf;
diff --git a/src/expdesign/primaries.cc b/src/expdesign/primaries.cc
index b04c3d8..bebb923 100644
--- a/src/expdesign/primaries.cc
+++ b/src/expdesign/primaries.cc
@@ -26,7 +26,6 @@
using namespace std;
-using namespace agh;
using confval::SValidator;
@@ -39,6 +38,7 @@ CExpDesign (const string& session_dir_,
tunables0 (tstep, tlo, thi), // only references here, don't worry
req_percent_scored (80.),
swa_laden_pages_before_SWA_0 (3),
+ strict_subject_id_checks (false),
_id_pool (0),
config_keys_g ({
SValidator<double>("ctl_param.step_size", &ctl_params0.siman_params.step_size),
@@ -59,7 +59,7 @@ CExpDesign (const string& session_dir_,
config_keys_d ({
SValidator<int>("fft_param.welch_window_type", (int*)&fft_params.welch_window_type, SValidator<int>::SVFRangeIn( 0, (int)sigproc::TWinType_total - 1)),
SValidator<int>("fft_param.plan_type", (int*)&fft_params.plan_type, SValidator<int>::SVFRangeIn( 0, (int)metrics::psd::TFFTWPlanType_total - 1)),
- SValidator<int>("artifacts.dampen_window_type",(int*)&af_dampen_window_type, SValidator<int>::SVFRangeIn( 0, (int)sigproc::TWinType_total - 1)),
+ SValidator<int>("artifacts.dampen_window_type", (int*)&af_dampen_window_type, SValidator<int>::SVFRangeIn( 0, (int)sigproc::TWinType_total - 1)),
SValidator<int>("ctl_param.iters_fixed_t", &ctl_params0.siman_params.iters_fixed_T, SValidator<int>::SVFRangeIn( 1, 1000000)),
SValidator<int>("ctl_param.n_tries", &ctl_params0.siman_params.n_tries, SValidator<int>::SVFRangeIn( 1, 10000)),
}),
@@ -77,10 +77,11 @@ CExpDesign (const string& session_dir_,
SValidator<bool>("ctl_param.AZAmendment1", &ctl_params0.AZAmendment1),
SValidator<bool>("ctl_param.AZAmendment2", &ctl_params0.AZAmendment2),
SValidator<bool>("profile.score_unscored_as_wake",
- &score_unscored_as_wake),
+ &score_unscored_as_wake),
+ SValidator<bool>("StrictSubjectIdChecks", &strict_subject_id_checks),
}),
config_keys_s ({
- SValidator<string>("LastUsedVersion", &last_used_version),
+ SValidator<string>("LastUsedVersion", &last_used_version),
})
{
char *tmp = canonicalize_file_name(session_dir_.c_str());
@@ -396,14 +397,21 @@ used_samplerates( sigfile::SChannel::TType type) const
float
agh::CSubject::
-age_rel( time_t rel) const
+age() const
{
time_t now = time(NULL);
if ( unlikely (now == -1) ) {
perror( "What's wrong with localtime? ");
return 21.;
}
- return (now - dob)/365.25/24/60/60;
+ return age_rel(now);
+}
+
+float
+agh::CSubject::
+age_rel( time_t rel) const
+{
+ return (difftime(rel, dob))/365.25/24/60/60;
}
diff --git a/src/expdesign/primaries.hh b/src/expdesign/primaries.hh
index ff1322d..85e416b 100644
--- a/src/expdesign/primaries.hh
+++ b/src/expdesign/primaries.hh
@@ -48,17 +48,6 @@ class CSubject : public SSubjectId {
CSubject () = delete;
public:
- float age( const string& d) const
- {
- return age_rel(
- measurements.at(d).episodes.front().start_time());
- }
- float age_rel( time_t) const;
-
- const string&
- dir() const
- { return _dir; }
-
CSubject (const CSubject& rv)
: agh::SSubjectId (rv),
_status (rv._status),
@@ -73,6 +62,43 @@ class CSubject : public SSubjectId {
_dir (dir)
{}
+ // identification
+ const string&
+ dir() const
+ { return _dir; }
+
+ int try_update_subject_details( const agh::SSubjectId& j)
+ {
+ return SSubjectId::update_from( j);
+ }
+
+
+ float age( const string& d) const // age when recordings in this session were made
+ {
+ if ( measurements.find(d) != measurements.end() &&
+ measurements.at(d).episodes.size() > 0 )
+ return age_rel(
+ measurements.at(d).episodes.front().start_time());
+ else
+ return -1.;
+ }
+ float age() const; // now
+ float age_rel( time_t) const;
+
+ bool operator==( const CSubject &o) const
+ {
+ return id == o.id;
+ }
+ bool operator==( const string& n) const
+ {
+ return SSubjectId::id == n;
+ }
+ bool operator==( sid_type id) const
+ {
+ return _id == id;
+ }
+
+ // contents
class SEpisodeSequence;
class SEpisode {
public:
@@ -228,19 +254,6 @@ class CSubject : public SSubjectId {
}
}
- bool operator==( const CSubject &o) const
- {
- return id == o.id;
- }
- bool operator==( const string& n) const
- {
- return SSubjectId::id == n;
- }
- bool operator==( sid_type id) const
- {
- return _id == id;
- }
-
private:
int _status;
sid_type
@@ -445,7 +458,8 @@ class CExpDesign {
ctl_params0;
double req_percent_scored;
size_t swa_laden_pages_before_SWA_0;
- bool score_unscored_as_wake;
+ bool score_unscored_as_wake,
+ strict_subject_id_checks;
int load_settings();
int save_settings();
diff --git a/src/expdesign/tree-scanner.cc b/src/expdesign/tree-scanner.cc
index d2333c8..25b88c8 100644
--- a/src/expdesign/tree-scanner.cc
+++ b/src/expdesign/tree-scanner.cc
@@ -187,6 +187,18 @@ register_intree_source( sigfile::CTypedSource&& F,
} else
J = &*Ji;
+ // check/update CSubject::SSubjectId fields against those in the file being added
+ // printf( "Update subject details: [%s, %s, %c, %s] <- [%s, %s, %c, %s]\n",
+ // J->id.c_str(), J->name.c_str(), J->gender_sign(), ctime(&J->dob),
+ // F().subject().id.c_str(), F().subject().name.c_str(), F().subject().gender_sign(), ctime(&F().subject().dob));
+ if ( J->try_update_subject_details( F().subject()) ) {
+ if ( strict_subject_id_checks ) {
+ fprintf( stderr, "%s: subject details mismatch", F().filename());
+ return -1;
+ } else
+ fprintf( stderr, "%s: keeping previously recorded subject details", F().filename());
+ }
+
// insert/update episode observing start/end times
printf( "\nCExpDesign::register_intree_source( file: \"%s\", J: %s (\"%s\"), E: \"%s\", D: \"%s\")\n",
F().filename(), F().subject().id.c_str(), F().subject().name.c_str(), F().episode(), F().session());
@@ -249,7 +261,7 @@ edf_file_processor( const char *fname, const struct stat*, int flag, struct FTW
sigfile::CTypedSource f_tmp {fname, __expdesign->fft_params.pagesize};
string st = f_tmp().explain_status();
if ( not st.empty() )
- __expdesign->log_message( "%s: %s\n", fname, st.c_str());
+ __expdesign->log_message( "In %s:\n%s\n", fname, st.c_str());
__expdesign -> register_intree_source( move(f_tmp));
} catch ( invalid_argument ex) {
@@ -324,6 +336,7 @@ scan_tree( TMsmtCollectProgressIndicatorFun user_progress_fun)
}
list<string> complete_session_set = enumerate_sessions();
+
// calculate average episode times
for ( auto &G : groups ) {
map <string, map<string, vector <TTimePair>>> tms;
diff --git a/src/libsigfile/edf.cc b/src/libsigfile/edf.cc
index 5004b6b..9c98118 100644
--- a/src/libsigfile/edf.cc
+++ b/src/libsigfile/edf.cc
@@ -548,17 +548,18 @@ _parse_header()
{
auto subfields = agh::str::tokens( _patient_id, " ");
if ( unlikely (_patient_id.empty()) ) {
- fprintf( stderr, "%s: Missing patient_id\n", filename());
- _subject.id = _subject.name = "Fafa";
+ _status |= missing_patient_id;
} else if ( subfields.size() != 4 ) {
- fprintf( stderr, "%s: Nonconforming patient_id\n", filename());
- _subject.id = _subject.name = subfields.front();
+ _subject.id = subfields.front();
+ _status |= nonconforming_patient_id;
} else {
auto i = subfields.begin();
_subject.id = *i++;
_subject.gender = agh::SSubjectId::char_to_gender((*i++)[0]);
_subject.dob = agh::SSubjectId::str_to_dob(*i++);
_subject.name = agh::str::join( agh::str::tokens(*i++, "_"), " ");
+ if ( not _subject.valid() )
+ _status |= invalid_subject_details;
}
}
@@ -860,6 +861,8 @@ sigfile::CEDFFile::explain_edf_status( int status)
recv.emplace_back( "* Ill-formed header");
if ( status & bad_version )
recv.emplace_back( "* Bad Version signature (i.e., not an EDF file)");
+ if ( status & missing_patient_id )
+ recv.emplace_back( "* Missing PatientId");
if ( status & bad_numfld )
recv.emplace_back( "* Garbage in numerical fields");
if ( status & date_unparsable )
@@ -872,6 +875,8 @@ sigfile::CEDFFile::explain_edf_status( int status)
recv.emplace_back( "* Channel designation not following the 10-20 system");
if ( status & nonconforming_patient_id )
recv.emplace_back( "* PatientId not conforming to section 2.1.3.3 of EDF spec");
+ if ( status & invalid_subject_details )
+ recv.emplace_back( "* PatientId has incomplete or ill-formed subject details");
if ( status & nonkemp_signaltype )
recv.emplace_back( "* Signal type not listed in Kemp et al");
if ( status & dup_channels )
diff --git a/src/libsigfile/edf.hh b/src/libsigfile/edf.hh
index f20fc5d..a9a5194 100644
--- a/src/libsigfile/edf.hh
+++ b/src/libsigfile/edf.hh
@@ -125,7 +125,7 @@ class CEDFFile
int set_reserved( const char*);
int set_comment( const char* s)
{ return set_reserved( s); }
-
+
int set_start_time( time_t);
// channels
size_t n_channels() const
@@ -485,7 +485,7 @@ class CEDFFile
}
- enum TStatus : int {
+ enum TStatus : int_least32_t {
ok = 0,
bad_header = (1 << 0),
bad_version = (1 << 1),
@@ -497,11 +497,13 @@ class CEDFFile
noepisode = (1 << 7),
nonkemp_signaltype = (1 << 8),
non1020_channel = (1 << 9),
- dup_channels = (1 << 11),
- nogain = (1 << 12),
- sysfail = (1 << 13),
- too_many_channels = (1 << 14),
- nonconforming_patient_id = (1 << 15),
+ dup_channels = (1 << 10),
+ nogain = (1 << 11),
+ sysfail = (1 << 12),
+ too_many_channels = (1 << 13),
+ nonconforming_patient_id = (1 << 14),
+ missing_patient_id = (1 << 15),
+ invalid_subject_details = (1 << 16),
inoperable = (bad_header
| bad_version
| bad_numfld
diff --git a/src/ui/mw/construct.cc b/src/ui/mw/construct.cc
index 786cc1d..7f731bd 100644
--- a/src/ui/mw/construct.cc
+++ b/src/ui/mw/construct.cc
@@ -373,7 +373,8 @@ SExpDesignUIWidgets ()
!AGH_GBGETOBJ (GtkSpinButton, eDAMsmtTLHeight) ||
!AGH_GBGETOBJ (GtkSpinButton, eDAPageHeight) ||
!AGH_GBGETOBJ (GtkSpinButton, eDAHypnogramHeight) ||
- !AGH_GBGETOBJ (GtkSpinButton, eDAEMGHeight) )
+ !AGH_GBGETOBJ (GtkSpinButton, eDAEMGHeight) ||
+ !AGH_GBGETOBJ (GtkCheckButton, eScanTreeStrict) )
throw runtime_error ("Failed to construct widgets");
if ( !AGH_GBGETOBJ (GtkEntry, eBrowseCommand) )
diff --git a/src/ui/mw/mw.cc b/src/ui/mw/mw.cc
index 5389505..c84100b 100644
--- a/src/ui/mw/mw.cc
+++ b/src/ui/mw/mw.cc
@@ -232,15 +232,16 @@ SExpDesignUI (aghui::SSessionChooser *parent,
// bind fields to widgets
// tab 1
W_V1.reg( eSMPMaxThreads, &ED->num_threads);
+ W_V1.reg( eScanTreeStrict, &ED->strict_subject_id_checks);
W_V1.reg( eArtifDampenWindowType, (int*)&ED->af_dampen_window_type);
- W_V1.reg( eArtifDampenFactor, &ED->af_dampen_factor);
- W_V1.reg( eFFTParamsWindowType, (int*)&ED->fft_params.welch_window_type);
- W_V1.reg( eMCParamIIRBackpolate, &ED->mc_params.iir_backpolate);
- W_V1.reg( eMCParamMCGain, &ED->mc_params.mc_gain);
- W_V1.reg( eMCParamBandWidth, &ED->mc_params.bandwidth);
- W_V1.reg( eMCParamFreqInc, &ED->mc_params.freq_inc);
- W_V1.reg( eMCParamNBins, &ED->mc_params.n_bins);
- W_V1.reg( eSWUParamMinUpswingDuration, &ED->swu_params.min_upswing_duration);
+ W_V1.reg( eArtifDampenFactor, &ED->af_dampen_factor);
+ W_V1.reg( eFFTParamsWindowType, (int*)&ED->fft_params.welch_window_type);
+ W_V1.reg( eMCParamIIRBackpolate, &ED->mc_params.iir_backpolate);
+ W_V1.reg( eMCParamMCGain, &ED->mc_params.mc_gain);
+ W_V1.reg( eMCParamBandWidth, &ED->mc_params.bandwidth);
+ W_V1.reg( eMCParamFreqInc, &ED->mc_params.freq_inc);
+ W_V1.reg( eMCParamNBins, &ED->mc_params.n_bins);
+ W_V1.reg( eSWUParamMinUpswingDuration, &ED->swu_params.min_upswing_duration);
W_V1.reg( eFFTParamsPageSize, &pagesize_item);
W_V1.reg( eFFTParamsBinSize, &binsize_item);
@@ -279,12 +280,12 @@ SExpDesignUI (aghui::SSessionChooser *parent,
W_V2.reg( eCtlParamAnnlTInitialMantissa,&ctl_params0_siman_params_t_initial_mantissa);
W_V2.reg( eCtlParamAnnlTInitialExponent,&ctl_params0_siman_params_t_initial_exponent);
- W_V2.reg( eCtlParamDBAmendment1, &ED->ctl_params0.DBAmendment1);
- W_V2.reg( eCtlParamDBAmendment2, &ED->ctl_params0.DBAmendment2);
- W_V2.reg( eCtlParamAZAmendment1, &ED->ctl_params0.AZAmendment1);
- W_V2.reg( eCtlParamNSWAPpBeforeSimStart, (int*)&ED->swa_laden_pages_before_SWA_0);
- W_V2.reg( eCtlParamReqScoredPercent, &ED->req_percent_scored);
- W_V2.reg( eCtlParamScoreUnscoredAsWake, &ED->score_unscored_as_wake);
+ W_V2.reg( eCtlParamDBAmendment1, &ED->ctl_params0.DBAmendment1);
+ W_V2.reg( eCtlParamDBAmendment2, &ED->ctl_params0.DBAmendment2);
+ W_V2.reg( eCtlParamAZAmendment1, &ED->ctl_params0.AZAmendment1);
+ W_V2.reg( eCtlParamNSWAPpBeforeSimStart, (int*)&ED->swa_laden_pages_before_SWA_0);
+ W_V2.reg( eCtlParamReqScoredPercent, &ED->req_percent_scored);
+ W_V2.reg( eCtlParamScoreUnscoredAsWake, &ED->score_unscored_as_wake);
// tunables are isolated so they can be reset separately
for ( size_t t = 0; t < agh::ach::TTunable::_basic_tunables; ++t ) {
diff --git a/src/ui/mw/mw.hh b/src/ui/mw/mw.hh
index 2d694f1..38391b3 100644
--- a/src/ui/mw/mw.hh
+++ b/src/ui/mw/mw.hh
@@ -233,6 +233,8 @@ class SExpDesignUI
agh::SProfileParamSet make_active_profile_paramset() const;
// own variables aka saved settings
+ bool strict_subject_id_checks;
+
double uc_accuracy_factor;
static const array<unsigned, 4>
FFTPageSizeValues;
diff --git a/src/ui/mw/widgets.hh b/src/ui/mw/widgets.hh
index 521b867..4f1f9ea 100644
--- a/src/ui/mw/widgets.hh
+++ b/src/ui/mw/widgets.hh
@@ -229,6 +229,8 @@ struct SExpDesignUIWidgets {
GtkRadioButton
*eCtlParamScoreUnscoredAsWake;
+ GtkCheckButton
+ *eScanTreeStrict;
GtkSpinButton
*eTunable[agh::ach::TTunable::_basic_tunables][4];
--
Sleep experiment manager
More information about the debian-med-commit
mailing list