diff --git a/docs/scripts_md/MRI.md b/docs/scripts_md/MRI.md index 7ef965d7e..14b467a31 100644 --- a/docs/scripts_md/MRI.md +++ b/docs/scripts_md/MRI.md @@ -94,7 +94,7 @@ Inserts scans that do not correspond to any of the defined protocol from the database. INPUTS: - - $dbhr : database handle reference + - $db : database object - $series\_desc : series description of the scan - $minc\_location : location of the MINC file - $patient\_name : patient name of the scan diff --git a/docs/scripts_md/MRIProcessingUtility.md b/docs/scripts_md/MRIProcessingUtility.md index f04d2ae9d..27e748988 100644 --- a/docs/scripts_md/MRIProcessingUtility.md +++ b/docs/scripts_md/MRIProcessingUtility.md @@ -284,6 +284,7 @@ INPUTS: - $visit\_label : visit label associated with the scan - $file : information about the scan - $data\_dir : path to the LORIS MRI data directory + - $scan\_type : scan type associated to the file ### loadAndCreateObjectFile($minc, $upload\_id) diff --git a/docs/scripts_md/MriCandidateErrorsOB.md b/docs/scripts_md/MriCandidateErrorsOB.md new file mode 100644 index 000000000..9edf9c8a1 --- /dev/null +++ b/docs/scripts_md/MriCandidateErrorsOB.md @@ -0,0 +1,106 @@ +# NAME + +NeuroDB::objectBroker::MriCandidateErrorsOB -- An object broker for `MriCandidateErrors` records + +# SYNOPSIS + + use NeuroDB::Database; + use NeuroDB::objectBroker::MriCandidateErrorsOB; + use TryCatch; + + my $db = NeuroDB::Database->new( + userName => 'user', + databaseName => 'my_db', + hostName => 'my_hostname', + password => 'pwd' + ); + + try { + $db->connect(); + } catch(NeuroDB::DatabaseException $e) { + die sprintf( + "User %s failed to connect to %s on %s: %s (error code %d)\n", + 'user', + 'my_db', + 'my_hostname', + $e->errorMessage, + $e->errorCode + ); + } + + . + . + . + + my $mriCandidateErrorsOB = NeuroDB::objectBroker::MriCandidateErrorsOB->new(db => $db); + my $mriCandidateErrorsRef; + try { + $mriCandidateErrorsRef = $mriCandidateErrorsOB->getByTarchiveID( + [ 'TarchiveID' ], 12 + ); + } catch(NeuroDB::objectBroker::ObjectBrokerException $e) { + die sprintf( + "Failed to retrieve MriCandidateErrors records: %s", + $e->errorMessage + ); + } + +# DESCRIPTION + +This class provides a set of methods to either fetch records from the `MRICandidateErrors` +table, insert new entries in it or update existing ones. If an operation cannot +be executed successfully, a `NeuroDB::objectBroker::ObjectBrokerException` is thrown. + +## Methods + +### new(db => $db) >> (constructor) + +Create a new instance of this class. The only parameter to provide is the +`Database` object used to access the database. + +INPUT: the database object used to read/modify the `MRICandidateErrors` table. + +RETURN: new instance of this class. + +### getWithTarchiveID($tarchiveID) + +Fetches the records from the `MRICandidateErrors` table that have a specific `TarchiveID`. + +INPUTS: + - ID of the tarchive used during the search. + +RETURN: a reference to an array of hash references. Every hash contains the values for a given + row returned by the function call: the key/value pairs contain the name of a column + (listed in `@MRICANDIDATEERRORS_FIELDS`) and the value it holds, respectively. + As an example, suppose array `$r` contains the result of a call to this method with + `@$fieldsRef` set to `('TarchiveID', 'MincFile'` one would fetch the `MincFile` + of the 4th record returned using `$r-`\[3\]->{'MincFile'}>. + +### insert($valuesRef) + +Inserts a new record in the `MRICandidateErrors` table with the specified column values. +This method throws a `NeuroDB::objectBroker::ObjectBrokerException` if the operation +could not be completed successfully. + +INPUT: a reference to a hash of the values to insert. The hash contains the column + names and associated record values used during insertion. All the keys of + `%$valuesRef` must exist in `@MRICANDIDATEERRORS_FIELDS` or an exception will be thrown. + +RETURNS: the index of the MRI upload record inserted. + +# TO DO + +Nothing planned. + +# BUGS + +None reported. + +# COPYRIGHT AND LICENSE + +License: GPLv3 + +# AUTHORS + +LORIS community and McGill Centre for Integrative +Neuroscience diff --git a/docs/scripts_md/MriProtocolViolatedScansOB.md b/docs/scripts_md/MriProtocolViolatedScansOB.md new file mode 100644 index 000000000..be4586e81 --- /dev/null +++ b/docs/scripts_md/MriProtocolViolatedScansOB.md @@ -0,0 +1,106 @@ +# NAME + +NeuroDB::objectBroker::MriProtocolViolatedScansOB -- An object broker for `mri_protocol_violated_scans` records + +# SYNOPSIS + + use NeuroDB::Database; + use NeuroDB::objectBroker::MriProtocolViolatedScansOB; + use TryCatch; + + my $db = NeuroDB::Database->new( + userName => 'user', + databaseName => 'my_db', + hostName => 'my_hostname', + password => 'pwd' + ); + + try { + $db->connect(); + } catch(NeuroDB::DatabaseException $e) { + die sprintf( + "User %s failed to connect to %s on %s: %s (error code %d)\n", + 'user', + 'my_db', + 'my_hostname', + $e->errorMessage, + $e->errorCode + ); + } + + . + . + . + + my $mriProtocolViolatedScansOB = NeuroDB::objectBroker::MriProtocolViolatedScansOB->new(db => $db); + my $mriProtocolViolatedScansOBRef; + try { + $mriProtocolViolatedScansOBRef = $mriProtocolViolatedScansOB->getByTarchiveID( + [ 'TarchiveID' ], 12 + ); + } catch(NeuroDB::objectBroker::ObjectBrokerException $e) { + die sprintf( + "Failed to retrieve mri_protocol_violated_scans records: %s", + $e->errorMessage + ); + } + +# DESCRIPTION + +This class provides a set of methods to either fetch records from the `mri_protocol_violated_scans` +table, insert new entries in it or update existing ones. If an operation cannot +be executed successfully, a `NeuroDB::objectBroker::ObjectBrokerException` is thrown. + +## Methods + +### new(db => $db) >> (constructor) + +Create a new instance of this class. The only parameter to provide is the +`Database` object used to access the database. + +INPUT: the database object used to read/modify the `mri_protocol_violated_scans` table. + +RETURN: new instance of this class. + +### getWithTarchiveID($tarchiveID) + +Fetches the records from the `mri_protocol_violated_scans` table that have a specific `TarchiveID`. + +INPUTS: + - ID of the tarchive used during the search. + +RETURN: a reference to an array of hash references. Every hash contains the values for a given + row returned by the function call: the key/value pairs contain the name of a column + (listed in `@MRIPROTOCOLVIOLATEDSCANS_FIELDS`) and the value it holds, respectively. + As an example, suppose array `$r` contains the result of a call to this method with + `@$fieldsRef` set to `('TarchiveID', 'minc_location'` one would fetch the `minc_location` + of the 4th record returned using `$r-`\[3\]->{'minc\_location'}>. + +### insert($valuesRef) + +Inserts a new record in the `mri_protocol_violated_scans` table with the specified column values. +This method throws a `NeuroDB::objectBroker::ObjectBrokerException` if the operation +could not be completed successfully. + +INPUT: a reference to a hash of the values to insert. The hash contains the column + names and associated record values used during insertion. All the keys of + `%$valuesRef` must exist in `@MRIPROTOCOLVIOLATEDSCANS_FIELDS` or an exception will be thrown. + +RETURNS: the index of the MRI upload record inserted. + +# TO DO + +Nothing planned. + +# BUGS + +None reported. + +# COPYRIGHT AND LICENSE + +License: GPLv3 + +# AUTHORS + +LORIS community and McGill Centre for Integrative +Neuroscience diff --git a/docs/scripts_md/MriViolationsLogOB.md b/docs/scripts_md/MriViolationsLogOB.md new file mode 100644 index 000000000..c111330a0 --- /dev/null +++ b/docs/scripts_md/MriViolationsLogOB.md @@ -0,0 +1,106 @@ +# NAME + +NeuroDB::objectBroker::MriViolationsLogOB -- An object broker for `mri_violations_log` records + +# SYNOPSIS + + use NeuroDB::Database; + use NeuroDB::objectBroker::MriViolationsLogOB; + use TryCatch; + + my $db = NeuroDB::Database->new( + userName => 'user', + databaseName => 'my_db', + hostName => 'my_hostname', + password => 'pwd' + ); + + try { + $db->connect(); + } catch(NeuroDB::DatabaseException $e) { + die sprintf( + "User %s failed to connect to %s on %s: %s (error code %d)\n", + 'user', + 'my_db', + 'my_hostname', + $e->errorMessage, + $e->errorCode + ); + } + + . + . + . + + my $mriViolationsLogOB = NeuroDB::objectBroker::MriViolationsLogOB->new(db => $db); + my $mriProtocolViolatedScansOBRef; + try { + $mriViolationsLogOBRef = $mriViolationsLogOB->getByTarchiveID( + [ 'TarchiveID' ], 12 + ); + } catch(NeuroDB::objectBroker::ObjectBrokerException $e) { + die sprintf( + "Failed to retrieve mri_violations_log records: %s", + $e->errorMessage + ); + } + +# DESCRIPTION + +This class provides a set of methods to either fetch records from the `mri_violations_log` +table, insert new entries in it or update existing ones. If an operation cannot +be executed successfully, a `NeuroDB::objectBroker::ObjectBrokerException` is thrown. + +## Methods + +### new(db => $db) >> (constructor) + +Create a new instance of this class. The only parameter to provide is the +`Database` object used to access the database. + +INPUT: the database object used to read/modify the `mri_violations_log` table. + +RETURN: new instance of this class. + +### getWithTarchiveID($tarchiveID) + +Fetches the records from the `mri_violations_log` table that have a specific `TarchiveID`. + +INPUTS: + - ID of the tarchive used during the search. + +RETURN: a reference to an array of hash references. Every hash contains the values for a given + row returned by the function call: the key/value pairs contain the name of a column + (listed in `@MRIVIOLATIONSLOG_FIELDS`) and the value it holds, respectively. + As an example, suppose array `$r` contains the result of a call to this method with + `@$fieldsRef` set to `('TarchiveID', 'MincFile'` one would fetch the `MincFile` + of the 4th record returned using `$r-`\[3\]->{'MincFile'}>. + +### insert($valuesRef) + +Inserts a new record in the `mri_violations_log` table with the specified column values. +This method throws a `NeuroDB::objectBroker::ObjectBrokerException` if the operation +could not be completed successfully. + +INPUT: a reference to a hash of the values to insert. The hash contains the column + names and associated record values used during insertion. All the keys of + `%$valuesRef` must exist in `@MRIVIOLATIONSLOG_FIELDS` or an exception will be thrown. + +RETURNS: the index of the MRI upload record inserted. + +# TO DO + +Nothing planned. + +# BUGS + +None reported. + +# COPYRIGHT AND LICENSE + +License: GPLv3 + +# AUTHORS + +LORIS community and McGill Centre for Integrative +Neuroscience diff --git a/uploadNeuroDB/NeuroDB/MRI.pm b/uploadNeuroDB/NeuroDB/MRI.pm index 7ea00fd5d..3b48a3b5a 100755 --- a/uploadNeuroDB/NeuroDB/MRI.pm +++ b/uploadNeuroDB/NeuroDB/MRI.pm @@ -48,6 +48,7 @@ use FindBin; use Encode; use DICOM::DICOM; +use NeuroDB::objectBroker::MriProtocolViolatedScansOB; use NeuroDB::objectBroker::MriScanTypeOB; use NeuroDB::objectBroker::MriScannerOB; use NeuroDB::objectBroker::PSCOB; @@ -517,15 +518,15 @@ sub identify_scan_db { } # if (@rows==0)....else... # if we got here, we're really clueless: insert scan in mri_protocol_violated_scans - # table. Note that $mriProtocolGroupID will be undef unless exactly one protocol + # table. Note that $mriProtocolGroupID will be undef unless exactly one protocol # group was used to try to identify the scan insert_violated_scans( - $dbhr, $series_description, $minc_location, $patient_name, + $db, $series_description, $minc_location, $patient_name, $candid, $pscid, $tr, $te, $ti, $slice_thickness, $xstep, $ystep, $zstep, $xspace, $yspace, $zspace, $time, $seriesUID, $tarchiveID, $image_type, - $echo_numbers, $phase_enc_dir, $data_dir, $mriProtocolGroupID + $echo_numbers, $phase_enc_dir, $data_dir, $mriProtocolGroupID ); return 'unknown'; @@ -540,7 +541,7 @@ C table into the C table of the database. INPUTS: - - $dbhr : database handle reference + - $db : database object - $series_desc : series description of the scan - $minc_location : location of the MINC file - $patient_name : patient name of the scan @@ -570,45 +571,62 @@ INPUTS: sub insert_violated_scans { - my ($dbhr, $series_description, $minc_location, $patient_name, - $candid, $pscid, $tr, $te, - $ti, $slice_thickness, $xstep, $ystep, - $zstep, $xspace, $yspace, $zspace, - $time, $seriesUID, $tarchiveID, $image_type, + my ($db, $series_description, $minc_location, $patient_name, + $candid, $pscid, $tr, $te, + $ti, $slice_thickness, $xstep, $ystep, + $zstep, $xspace, $yspace, $zspace, + $time, $seriesUID, $tarchiveID, $image_type, $echo_number, $phase_enc_dir, $data_dir, $mriProtocolGroupID) = @_; # determine the future relative path when the file will be moved to # data_dir/trashbin at the end of the script's execution my $file_rel_path = get_trashbin_file_rel_path($minc_location, $data_dir, 1); - (my $query = <prepare($query); - my $success = $sth->execute( - $candid, $pscid, $tarchiveID, $series_description, - $file_rel_path, $patient_name, $tr, $te, - $ti, $slice_thickness, $xspace, $yspace, - $zspace, $xstep, $ystep, $zstep, - $time, $seriesUID, $image_type, $phase_enc_dir, - $echo_number, $mriProtocolGroupID + # determine time run + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); + my $time_run = sprintf("%4d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec); + + my %newMriProtocolViolatedScans = ( + 'CandID' => $candid, + 'PSCID' => $pscid, + 'TarchiveID' => $tarchiveID, + 'time_run' => $time_run, + 'series_description' => $series_description, + 'minc_location' => $file_rel_path, + 'PatientName' => $patient_name, + 'TR_range' => $tr, + 'TE_range' => $te, + 'TI_range' => $ti, + 'slice_thickness_range' => $slice_thickness, + 'xspace_range' => $xspace, + 'yspace_range' => $yspace, + 'zspace_range' => $zspace, + 'xstep_range' => $xstep, + 'ystep_range' => $ystep, + 'zstep_range' => $zstep, + 'time_range' => $time, + 'SeriesUID' => $seriesUID, + 'image_type' => $image_type, + 'PhaseEncodingDirection' => $phase_enc_dir, + 'EchoNumber' => $echo_number, + 'MriProtocolGroupID' => $mriProtocolGroupID ); + my $mriProtocolViolatedScansOB = NeuroDB::objectBroker::MriProtocolViolatedScansOB->new(db => $db); + my $mriProtocolViolatedScansRef = $mriProtocolViolatedScansOB->getWithTarchiveID($tarchiveID); + + my $already_inserted = undef; + foreach my $dbProtViolScan (@$mriProtocolViolatedScansRef) { + if ($dbProtViolScan->{'SeriesUID'} eq $newMriProtocolViolatedScans{'SeriesUID'} + && $dbProtViolScan->{'TE_range'} eq $newMriProtocolViolatedScans{'TE_range'} + && $dbProtViolScan->{'PhaseEncodingDirection'} eq $newMriProtocolViolatedScans{'PhaseEncodingDirection'} + && $dbProtViolScan->{'EchoNumber'} eq $newMriProtocolViolatedScans{'EchoNumber'} + ) { + $already_inserted = 1; + last; + } + } + $mriProtocolViolatedScansOB->insert(\%newMriProtocolViolatedScans) unless defined $already_inserted; } diff --git a/uploadNeuroDB/NeuroDB/MRIProcessingUtility.pm b/uploadNeuroDB/NeuroDB/MRIProcessingUtility.pm index dd8ed7ec3..cfdfc2ee1 100755 --- a/uploadNeuroDB/NeuroDB/MRIProcessingUtility.pm +++ b/uploadNeuroDB/NeuroDB/MRIProcessingUtility.pm @@ -64,6 +64,7 @@ use NeuroDB::Database; use NeuroDB::DatabaseException; use NeuroDB::objectBroker::ObjectBrokerException; +use NeuroDB::objectBroker::MriViolationsLogOB; use NeuroDB::objectBroker::ConfigOB; use NeuroDB::objectBroker::TarchiveOB; use NeuroDB::objectBroker::MriUploadOB; @@ -920,7 +921,7 @@ sub extra_file_checks() { ); if (%validFields) { $this->insert_into_mri_violations_log( - \%validFields, $severity, $pname, $candID, $visitLabel, $file, $data_dir + \%validFields, $severity, $pname, $candID, $visitLabel, $file, $data_dir, $scan_type ); return $severity; } @@ -952,15 +953,23 @@ INPUTS: file handle reference to the NeuroDB::File object sub update_mri_violations_log_MincFile_path { my ($this, $file_ref) = @_; - my $seriesUID = $file_ref->getParameter('series_instance_uid'); - my $file_path = $file_ref->getFileDatum('File'); + # grep file parameters determining a unique file in the DB + my $seriesUID = $file_ref->getParameter('series_instance_uid'); + my $echoTime = $file_ref->getParameter('echo_time'); + my $phEncDir = $file_ref->getParameter('phase_encoding_direction'); + my $echoNumbers = $file_ref->getParameter('echo_numbers'); - # TODO: in a different PR, should add the echo time to the mri_violation table - # TODO: and add the echo time in the where part of the statement - my $query = "UPDATE mri_violations_log SET MincFile = ? WHERE SeriesUID = ?"; + # determine the new file path to use for update + my $file_path = $file_ref->getFileDatum('File'); + + (my $query = <{'dbhr'}}->prepare($query); - $sth->execute($file_path, $seriesUID); + $sth->execute($file_path, $seriesUID, $echoTime, $phEncDir, $echoNumbers); } =pod @@ -1070,68 +1079,77 @@ INPUTS: - $visit_label : visit label associated with the scan - $file : information about the scan - $data_dir : path to the LORIS MRI data directory + - $scan_type : scan type associated to the file =cut sub insert_into_mri_violations_log { - my ($this, $valid_fields, $severity, $pname, $candID, $visit_label, $file, $data_dir) = @_; + my ($this, $valid_fields, $severity, $pname, $candID, $visit_label, $file, $data_dir, $scan_type) = @_; + + my $tarchiveID = $file->getFileDatum('TarchiveSource'); # determine the future relative path when the file will be moved to # data_dir/trashbin at the end of the script's execution my $file_path = $file->getFileDatum('File'); - my $file_rel_path = NeuroDB::MRI::get_trashbin_file_rel_path($file_path, $data_dir, 1); - my $file_ph_enc_dir = $file->getParameter('phase_encoding_direction'); - my $file_echo_number = $file->getParameter('echo_numbers'); - - my $query = "INSERT INTO mri_violations_log" - . "(" - . " SeriesUID, TarchiveID, MincFile, PatientName, " - . " CandID, Visit_label, Scan_type, Severity, " - . " Header, Value, ValidRange, ValidRegex, " - . " PhaseEncodingDirection, EchoNumber, MriProtocolChecksGroupID " - . ") VALUES (" - . " ?, ?, ?, ?, " - . " ?, ?, ?, ?, " - . " ?, ?, ?, ?, " - . " ?, ?, ?" - . ")"; - if ($this->{debug}) { - print $query . "\n"; - } - my $sth = ${$this->{'dbhr'}}->prepare($query); + my $move_file = $severity eq 'exclude' ? 1 : undef; + my $file_rel_path = NeuroDB::MRI::get_trashbin_file_rel_path($file_path, $data_dir, $move_file); + + my %newViolationsLog = ( + 'TarchiveID' => $tarchiveID, + 'SeriesUID' => $file->getFileDatum('SeriesUID'), + 'MincFile' => $file_rel_path, + 'PatientName' => $pname, + 'CandID' => $candID, + 'Visit_label' => $visit_label, + 'Scan_type' => $scan_type, + 'Severity' => $severity, + 'EchoTime' => $file->getParameter('echo_time'), + 'PhaseEncodingDirection' => $file->getParameter('phase_encoding_direction'), + 'EchoNumber' => $file->getParameter('echo_numbers') + ); + + my $mriViolationsLogOB = NeuroDB::objectBroker::MriViolationsLogOB->new(db => $this->{db}); + my $mriViolationsLogRef = $mriViolationsLogOB->getWithTarchiveID($tarchiveID); # foreach header, concatenate arrays of ranges into a string foreach my $header (keys(%$valid_fields)) { + $file->setFileData('Caveat', 1) if ($severity eq 'warning'); + my $valid_range_str = "NULL"; my $valid_regex_str = "NULL"; my @valid_range_list = @{ $valid_fields->{$header}{ValidRanges} }; my @valid_regex_list = @{ $valid_fields->{$header}{ValidRegexs} }; - if (@valid_range_list) { $valid_range_str = join(',', @valid_range_list); } if (@valid_regex_list) { $valid_regex_str = join(',', @valid_regex_list); } - $file->setFileData('Caveat', 1) if ($severity eq 'warning'); - $sth->execute( - $file->getFileDatum('SeriesUID'), - $file->getFileDatum('TarchiveSource'), - $file_rel_path, - $pname, - $candID, - $visit_label, - $valid_fields->{$header}{ScanType}, - $severity, - $header, - $valid_fields->{$header}{HeaderValue}, - $valid_range_str, - $valid_regex_str, - $file_ph_enc_dir, - $file_echo_number, - $valid_fields->{$header}{MriProtocolChecksGroupID} - ); + $newViolationsLog{'Header'} = $header; + $newViolationsLog{'Value'} = $valid_fields->{$header}{HeaderValue}; + $newViolationsLog{'ValidRange'} = $valid_range_str; + $newViolationsLog{'ValidRegex'} = $valid_regex_str; + $newViolationsLog{'MriProtocolChecksGroupID'} = $valid_fields->{$header}{MriProtocolChecksGroupID}; + + my $already_inserted = undef; + foreach my $dbViolLog (@$mriViolationsLogRef) { + if ($dbViolLog->{'SeriesUID'} eq $newViolationsLog{'SeriesUID'} + && $dbViolLog->{'EchoTime'} eq $newViolationsLog{'EchoTime'} + && $dbViolLog->{'EchoNumber'} eq $newViolationsLog{'EchoNumber'} + && $dbViolLog->{'PhaseEncodingDirection'} eq $newViolationsLog{'PhaseEncodingDirection'} + && $dbViolLog->{'Scan_type'} eq $newViolationsLog{'Scan_type'} + && $dbViolLog->{'Severity'} eq $newViolationsLog{'Severity'} + && $dbViolLog->{'Header'} eq $newViolationsLog{'Header'} + && $dbViolLog->{'Value'} eq $newViolationsLog{'Value'} + && $dbViolLog->{'ValidRange'} eq $newViolationsLog{'ValidRange'} + && $dbViolLog->{'ValidRegex'} eq $newViolationsLog{'ValidRegex'} + ) { + $already_inserted = 1; + last; + } + } + $mriViolationsLogOB->insert(\%newViolationsLog) unless defined $already_inserted; } } diff --git a/uploadNeuroDB/NeuroDB/objectBroker/MriCandidateErrorsOB.pm b/uploadNeuroDB/NeuroDB/objectBroker/MriCandidateErrorsOB.pm new file mode 100644 index 000000000..bb6a66e3b --- /dev/null +++ b/uploadNeuroDB/NeuroDB/objectBroker/MriCandidateErrorsOB.pm @@ -0,0 +1,201 @@ +package NeuroDB::objectBroker::MriCandidateErrorsOB; + +=pod + +=head1 NAME + +NeuroDB::objectBroker::MriCandidateErrorsOB -- An object broker for C records + +=head1 SYNOPSIS + + use NeuroDB::Database; + use NeuroDB::objectBroker::MriCandidateErrorsOB; + use TryCatch; + + my $db = NeuroDB::Database->new( + userName => 'user', + databaseName => 'my_db', + hostName => 'my_hostname', + password => 'pwd' + ); + + try { + $db->connect(); + } catch(NeuroDB::DatabaseException $e) { + die sprintf( + "User %s failed to connect to %s on %s: %s (error code %d)\n", + 'user', + 'my_db', + 'my_hostname', + $e->errorMessage, + $e->errorCode + ); + } + + . + . + . + + my $mriCandidateErrorsOB = NeuroDB::objectBroker::MriCandidateErrorsOB->new(db => $db); + my $mriCandidateErrorsRef; + try { + $mriCandidateErrorsRef = $mriCandidateErrorsOB->getByTarchiveID( + [ 'TarchiveID' ], 12 + ); + } catch(NeuroDB::objectBroker::ObjectBrokerException $e) { + die sprintf( + "Failed to retrieve MriCandidateErrors records: %s", + $e->errorMessage + ); + } + +=head1 DESCRIPTION + +This class provides a set of methods to either fetch records from the C +table, insert new entries in it or update existing ones. If an operation cannot +be executed successfully, a C is thrown. + +=head2 Methods + +=cut + +use Moose; +use MooseX::Privacy; + +use NeuroDB::Database; +use NeuroDB::DatabaseException; +use NeuroDB::objectBroker::ObjectBrokerException; + +use File::Basename; + +use TryCatch; + +my @MRICANDIDATEERRORS_FIELDS = qw( + ID TimeRun SeriesUID TarchiveID MincFile PatientName Reason EchoTime + PhaseEncodingDirection EchoNumber +); + +=pod + +=head3 new(db => $db) >> (constructor) + +Create a new instance of this class. The only parameter to provide is the +C object used to access the database. + +INPUT: the database object used to read/modify the C table. + +RETURN: new instance of this class. + +=cut + +has 'db' => (is => 'rw', isa => 'NeuroDB::Database', required => 1); + +=pod + +=head3 getWithTarchiveID($tarchiveID) + +Fetches the records from the C table that have a specific C. + +INPUTS: + - ID of the tarchive used during the search. + +RETURN: a reference to an array of hash references. Every hash contains the values for a given + row returned by the function call: the key/value pairs contain the name of a column + (listed in C<@MRICANDIDATEERRORS_FIELDS>) and the value it holds, respectively. + As an example, suppose array C<$r> contains the result of a call to this method with + C<@$fieldsRef> set to C<('TarchiveID', 'MincFile'> one would fetch the C + of the 4th record returned using C<$r->[3]->{'MincFile'}>. +=cut + +sub getWithTarchiveID { + my ($self, $tarchiveID) = @_; + + my $query = sprintf( + "SELECT %s FROM MRICandidateErrors WHERE TarchiveID = ? ", + join(',', @MRICANDIDATEERRORS_FIELDS) + ); + + try { + return $self->db->pselect( + $query, $tarchiveID + ); + } catch(NeuroDB::DatabaseException $e) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => sprintf( + "Failed to get MRICandidateErrors records by tarchive ID. Reason:\n%s", + $e + ) + ); + } +} + +=head3 insert($valuesRef) + +Inserts a new record in the C table with the specified column values. +This method throws a C if the operation +could not be completed successfully. + +INPUT: a reference to a hash of the values to insert. The hash contains the column + names and associated record values used during insertion. All the keys of + C<%$valuesRef> must exist in C<@MRICANDIDATEERRORS_FIELDS> or an exception will be thrown. + +RETURNS: the index of the MRI upload record inserted. + +=cut + +sub insert { + my($self, $valuesRef) = @_; + + if(!keys %$valuesRef) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => "MRI candidate errors insertion failed: no values specified" + ); + } + + foreach my $v (keys %$valuesRef) { + if(!grep($v eq $_, @MRICANDIDATEERRORS_FIELDS)) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => "MRI candidate errors insertion failed: invalid field $v" + ); + } + } + + try { + print($valuesRef); + my @results = $self->db->insertOne('MRICandidateErrors', $valuesRef); + return $results[0]; + } catch(NeuroDB::DatabaseException $e) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => sprintf( + "Failed to insert MRICandidateErrors record. Reason:\n%s", + $e + ) + ); + } +} + +1; + +__END__ + + +=pod + +=head1 TO DO + +Nothing planned. + +=head1 BUGS + +None reported. + +=head1 COPYRIGHT AND LICENSE + +License: GPLv3 + +=head1 AUTHORS + +LORIS community and McGill Centre for Integrative +Neuroscience + +=cut \ No newline at end of file diff --git a/uploadNeuroDB/NeuroDB/objectBroker/MriProtocolViolatedScansOB.pm b/uploadNeuroDB/NeuroDB/objectBroker/MriProtocolViolatedScansOB.pm new file mode 100644 index 000000000..c18a315a9 --- /dev/null +++ b/uploadNeuroDB/NeuroDB/objectBroker/MriProtocolViolatedScansOB.pm @@ -0,0 +1,204 @@ +package NeuroDB::objectBroker::MriProtocolViolatedScansOB; + +=pod + +=head1 NAME + +NeuroDB::objectBroker::MriProtocolViolatedScansOB -- An object broker for C records + +=head1 SYNOPSIS + + use NeuroDB::Database; + use NeuroDB::objectBroker::MriProtocolViolatedScansOB; + use TryCatch; + + my $db = NeuroDB::Database->new( + userName => 'user', + databaseName => 'my_db', + hostName => 'my_hostname', + password => 'pwd' + ); + + try { + $db->connect(); + } catch(NeuroDB::DatabaseException $e) { + die sprintf( + "User %s failed to connect to %s on %s: %s (error code %d)\n", + 'user', + 'my_db', + 'my_hostname', + $e->errorMessage, + $e->errorCode + ); + } + + . + . + . + + my $mriProtocolViolatedScansOB = NeuroDB::objectBroker::MriProtocolViolatedScansOB->new(db => $db); + my $mriProtocolViolatedScansOBRef; + try { + $mriProtocolViolatedScansOBRef = $mriProtocolViolatedScansOB->getByTarchiveID( + [ 'TarchiveID' ], 12 + ); + } catch(NeuroDB::objectBroker::ObjectBrokerException $e) { + die sprintf( + "Failed to retrieve mri_protocol_violated_scans records: %s", + $e->errorMessage + ); + } + +=head1 DESCRIPTION + +This class provides a set of methods to either fetch records from the C +table, insert new entries in it or update existing ones. If an operation cannot +be executed successfully, a C is thrown. + +=head2 Methods + +=cut + +use Moose; +use MooseX::Privacy; + +use NeuroDB::Database; +use NeuroDB::DatabaseException; +use NeuroDB::objectBroker::ObjectBrokerException; + +use File::Basename; + +use TryCatch; + +my @MRIPROTOCOLVIOLATEDSCANS_FIELDS = qw( + ID CandID PSCID TarchiveID time_run series_description minc_location + PatientName TR_range TE_range TI_range slice_thickness_range + xspace_range yspace_range zspace_range xstep_range ystep_range zstep_range + time_range SeriesUID image_type PhaseEncodingDirection EchoNumber + MriProtocolGroupID +); + +=pod + +=head3 new(db => $db) >> (constructor) + +Create a new instance of this class. The only parameter to provide is the +C object used to access the database. + +INPUT: the database object used to read/modify the C table. + +RETURN: new instance of this class. + +=cut + +has 'db' => (is => 'rw', isa => 'NeuroDB::Database', required => 1); + +=pod + +=head3 getWithTarchiveID($tarchiveID) + +Fetches the records from the C table that have a specific C. + +INPUTS: + - ID of the tarchive used during the search. + +RETURN: a reference to an array of hash references. Every hash contains the values for a given + row returned by the function call: the key/value pairs contain the name of a column + (listed in C<@MRIPROTOCOLVIOLATEDSCANS_FIELDS>) and the value it holds, respectively. + As an example, suppose array C<$r> contains the result of a call to this method with + C<@$fieldsRef> set to C<('TarchiveID', 'minc_location'> one would fetch the C + of the 4th record returned using C<$r->[3]->{'minc_location'}>. +=cut + +sub getWithTarchiveID { + my ($self, $tarchiveID) = @_; + + my $query = sprintf( + "SELECT %s FROM mri_protocol_violated_scans WHERE TarchiveID = ? ", + join(',', @MRIPROTOCOLVIOLATEDSCANS_FIELDS) + ); + + try { + return $self->db->pselect( + $query, $tarchiveID + ); + } catch(NeuroDB::DatabaseException $e) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => sprintf( + "Failed to get mri_protocol_violated_scans records by tarchive ID. Reason:\n%s", + $e + ) + ); + } +} + +=head3 insert($valuesRef) + +Inserts a new record in the C table with the specified column values. +This method throws a C if the operation +could not be completed successfully. + +INPUT: a reference to a hash of the values to insert. The hash contains the column + names and associated record values used during insertion. All the keys of + C<%$valuesRef> must exist in C<@MRIPROTOCOLVIOLATEDSCANS_FIELDS> or an exception will be thrown. + +RETURNS: the index of the MRI upload record inserted. + +=cut + +sub insert { + my($self, $valuesRef) = @_; + + if(!keys %$valuesRef) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => "MRI protocol violated scans insertion failed: no values specified" + ); + } + + foreach my $v (keys %$valuesRef) { + if(!grep($v eq $_, @MRIPROTOCOLVIOLATEDSCANS_FIELDS)) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => "MRI protocol violated scans insertion failed: invalid field $v" + ); + } + } + + try { + print($valuesRef); + my @results = $self->db->insertOne('mri_protocol_violated_scans', $valuesRef); + return $results[0]; + } catch(NeuroDB::DatabaseException $e) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => sprintf( + "Failed to insert mri_protocol_violated_scans record. Reason:\n%s", + $e + ) + ); + } +} + +1; + +__END__ + + +=pod + +=head1 TO DO + +Nothing planned. + +=head1 BUGS + +None reported. + +=head1 COPYRIGHT AND LICENSE + +License: GPLv3 + +=head1 AUTHORS + +LORIS community and McGill Centre for Integrative +Neuroscience + +=cut \ No newline at end of file diff --git a/uploadNeuroDB/NeuroDB/objectBroker/MriViolationsLogOB.pm b/uploadNeuroDB/NeuroDB/objectBroker/MriViolationsLogOB.pm new file mode 100644 index 000000000..90252bf49 --- /dev/null +++ b/uploadNeuroDB/NeuroDB/objectBroker/MriViolationsLogOB.pm @@ -0,0 +1,202 @@ +package NeuroDB::objectBroker::MriViolationsLogOB; + +=pod + +=head1 NAME + +NeuroDB::objectBroker::MriViolationsLogOB -- An object broker for C records + +=head1 SYNOPSIS + + use NeuroDB::Database; + use NeuroDB::objectBroker::MriViolationsLogOB; + use TryCatch; + + my $db = NeuroDB::Database->new( + userName => 'user', + databaseName => 'my_db', + hostName => 'my_hostname', + password => 'pwd' + ); + + try { + $db->connect(); + } catch(NeuroDB::DatabaseException $e) { + die sprintf( + "User %s failed to connect to %s on %s: %s (error code %d)\n", + 'user', + 'my_db', + 'my_hostname', + $e->errorMessage, + $e->errorCode + ); + } + + . + . + . + + my $mriViolationsLogOB = NeuroDB::objectBroker::MriViolationsLogOB->new(db => $db); + my $mriProtocolViolatedScansOBRef; + try { + $mriViolationsLogOBRef = $mriViolationsLogOB->getByTarchiveID( + [ 'TarchiveID' ], 12 + ); + } catch(NeuroDB::objectBroker::ObjectBrokerException $e) { + die sprintf( + "Failed to retrieve mri_violations_log records: %s", + $e->errorMessage + ); + } + +=head1 DESCRIPTION + +This class provides a set of methods to either fetch records from the C +table, insert new entries in it or update existing ones. If an operation cannot +be executed successfully, a C is thrown. + +=head2 Methods + +=cut + +use Moose; +use MooseX::Privacy; + +use NeuroDB::Database; +use NeuroDB::DatabaseException; +use NeuroDB::objectBroker::ObjectBrokerException; + +use File::Basename; + +use TryCatch; + +my @MRIVIOLATIONSLOG_FIELDS = qw( + LogID TimeRun SeriesUID TarchiveID MincFile PatientName CandID Visit_label + CheckID Scan_type Severity Header Value ValidRange ValidRegex + EchoTime PhaseEncodingDirection EchoNumber MriProtocolChecksGroupID +); + +=pod + +=head3 new(db => $db) >> (constructor) + +Create a new instance of this class. The only parameter to provide is the +C object used to access the database. + +INPUT: the database object used to read/modify the C table. + +RETURN: new instance of this class. + +=cut + +has 'db' => (is => 'rw', isa => 'NeuroDB::Database', required => 1); + +=pod + +=head3 getWithTarchiveID($tarchiveID) + +Fetches the records from the C table that have a specific C. + +INPUTS: + - ID of the tarchive used during the search. + +RETURN: a reference to an array of hash references. Every hash contains the values for a given + row returned by the function call: the key/value pairs contain the name of a column + (listed in C<@MRIVIOLATIONSLOG_FIELDS>) and the value it holds, respectively. + As an example, suppose array C<$r> contains the result of a call to this method with + C<@$fieldsRef> set to C<('TarchiveID', 'MincFile'> one would fetch the C + of the 4th record returned using C<$r->[3]->{'MincFile'}>. +=cut + +sub getWithTarchiveID { + my ($self, $tarchiveID) = @_; + + my $query = sprintf( + "SELECT %s FROM mri_violations_log WHERE TarchiveID = ? ", + join(',', @MRIVIOLATIONSLOG_FIELDS) + ); + + try { + return $self->db->pselect( + $query, $tarchiveID + ); + } catch(NeuroDB::DatabaseException $e) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => sprintf( + "Failed to get mri_violations_log records by tarchive ID. Reason:\n%s", + $e + ) + ); + } +} + +=head3 insert($valuesRef) + +Inserts a new record in the C table with the specified column values. +This method throws a C if the operation +could not be completed successfully. + +INPUT: a reference to a hash of the values to insert. The hash contains the column + names and associated record values used during insertion. All the keys of + C<%$valuesRef> must exist in C<@MRIVIOLATIONSLOG_FIELDS> or an exception will be thrown. + +RETURNS: the index of the MRI upload record inserted. + +=cut + +sub insert { + my($self, $valuesRef) = @_; + + if(!keys %$valuesRef) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => "MRI violations log insertion failed: no values specified" + ); + } + + foreach my $v (keys %$valuesRef) { + if(!grep($v eq $_, @MRIVIOLATIONSLOG_FIELDS)) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => "MRI violations log insertion failed: invalid field $v" + ); + } + } + + try { + print($valuesRef); + my @results = $self->db->insertOne('mri_violations_log', $valuesRef); + return $results[0]; + } catch(NeuroDB::DatabaseException $e) { + NeuroDB::objectBroker::ObjectBrokerException->throw( + errorMessage => sprintf( + "Failed to insert mri_violations_log record. Reason:\n%s", + $e + ) + ); + } +} + +1; + +__END__ + + +=pod + +=head1 TO DO + +Nothing planned. + +=head1 BUGS + +None reported. + +=head1 COPYRIGHT AND LICENSE + +License: GPLv3 + +=head1 AUTHORS + +LORIS community and McGill Centre for Integrative +Neuroscience + +=cut \ No newline at end of file diff --git a/uploadNeuroDB/minc_insertion.pl b/uploadNeuroDB/minc_insertion.pl index 0eb4aaeba..ca909fb42 100755 --- a/uploadNeuroDB/minc_insertion.pl +++ b/uploadNeuroDB/minc_insertion.pl @@ -73,6 +73,9 @@ =head2 Methods use FindBin; use Cwd qw/ abs_path /; +use NeuroDB::objectBroker::MriCandidateErrorsOB; + + # These are the NeuroDB modules to be used use lib "$FindBin::Bin"; use NeuroDB::File; @@ -503,11 +506,6 @@ =head2 Methods print LOG " -> WARNING: This candidate was invalid. Logging to MRICandidateErrors table with reason $CandMismatchError"; - my $logQuery = "INSERT INTO MRICandidateErrors". - "(SeriesUID, TarchiveID, MincFile, PatientName, Reason) ". - "VALUES (?, ?, ?, ?, ?)"; - my $candlogSth = $dbh->prepare($logQuery); - # Strip all trailing newlines from the error message. Reason: # you cannot search for records in the LORIS MRI violations # module that have a message (i.e. a rejection reason) containing @@ -520,14 +518,35 @@ =head2 Methods # move the file into trashbin my $file_rel_path = NeuroDB::MRI::get_trashbin_file_rel_path($minc, $data_dir, 1); - $candlogSth->execute( - $file->getParameter('series_instance_uid'), - $studyInfo{'TarchiveID'}, - $file_rel_path, - $studyInfo{'PatientName'}, - $CandMismatchError + my %newMriCandidateErrors = ( + 'TarchiveID' => $studyInfo{'TarchiveID'}, + 'SeriesUID' => $file->getParameter('series_instance_uid'), + 'EchoTime' => $file->getParameter('echo_time'), + 'EchoNumber' => $file->getParameter('echo_numbers'), + 'PhaseEncodingDirection' => $file->getParameter('phase_encoding_direction'), + 'MincFile' => $file_rel_path, + 'PatientName' => $studyInfo{'PatientName'}, + 'Reason' => $CandMismatchError ); + my $mriCandidateErrorsOB = NeuroDB::objectBroker::MriCandidateErrorsOB->new(db => $db); + my $mriCandidateErrorsRef = $mriCandidateErrorsOB->getWithTarchiveID($studyInfo{'TarchiveID'}); + + my $already_inserted = undef; + foreach my $dbMriCandError (@$mriCandidateErrorsRef) { + if ($dbMriCandError->{'SeriesUID'} eq $newMriCandidateErrors{'SeriesUID'} + && $dbMriCandError->{'EchoTime'} eq $newMriCandidateErrors{'EchoTime'} + && $dbMriCandError->{'EchoNumber'} eq $newMriCandidateErrors{'EchoNumber'} + && $dbMriCandError->{'PhaseEncodingDirection'} eq $newMriCandidateErrors{'PhaseEncodingDirection'} + && $dbMriCandError->{'PatientName'} eq $newMriCandidateErrors{'PatientName'} + && $dbMriCandError->{'Reason'} eq $newMriCandidateErrors{'Reason'} + ) { + $already_inserted = 1; + last; + } + } + $mriCandidateErrorsOB->insert(\%newMriCandidateErrors) unless defined $already_inserted; + $notifier->spool('tarchive validation', $message, 0, 'minc_insertion.pl', $upload_id, 'Y', $notify_notsummary);