From 5c6b2dc7edc97f7cae8a23faeb0fc5818d57a098 Mon Sep 17 00:00:00 2001 From: Loic Marx Date: Sun, 30 Jun 2019 11:22:44 +0200 Subject: [PATCH 1/8] load the input argument --- .../testElectrodePointCloudModelEstimate.m | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 test/suite/testElectrodePointCloudModelEstimate.m diff --git a/test/suite/testElectrodePointCloudModelEstimate.m b/test/suite/testElectrodePointCloudModelEstimate.m new file mode 100644 index 0000000..f1a4fb8 --- /dev/null +++ b/test/suite/testElectrodePointCloudModelEstimate.m @@ -0,0 +1,20 @@ +% The PaCER Toolbox: testElectrodePointCloudModelEstimate.m +% +% Purpose: +% - test the electrodePointCloudModelEstimate function +% +% Author: +% - Loic Marx, June 2019 + +global refDataPath +global inputDataPath + +% save the current path +currentDir = pwd; + +% initialize the test +fileDir = fileparts(which(mfilename)); +cd(fileDir); + +% load the input arguments (obtained from function PaCER implemented only with CT_POSTOP_with_XML.nii.gz) +electrodePointCloudModelEstimate_inputs = load([inputDataPath filesep 'input_ElectrodePointCloudModelEstimate.mat']); From 646c0f62691d2de2d33b9046ff01ab488a3a66b4 Mon Sep 17 00:00:00 2001 From: Loic Marx Date: Sun, 30 Jun 2019 11:47:04 +0200 Subject: [PATCH 2/8] test for nargin < 2 --- .../suite/testElectrodePointCloudModelEstimate.m | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/suite/testElectrodePointCloudModelEstimate.m b/test/suite/testElectrodePointCloudModelEstimate.m index f1a4fb8..670b89b 100644 --- a/test/suite/testElectrodePointCloudModelEstimate.m +++ b/test/suite/testElectrodePointCloudModelEstimate.m @@ -18,3 +18,19 @@ % load the input arguments (obtained from function PaCER implemented only with CT_POSTOP_with_XML.nii.gz) electrodePointCloudModelEstimate_inputs = load([inputDataPath filesep 'input_ElectrodePointCloudModelEstimate.mat']); + +% setup tolerence value for comparison +tol = 1e-6; + +% test if nargin < 2 +%load reference data +refData_elecPointCloudMm = load('refData_testElectrodePointCloudModelEstimate_elecPointCloudMm.mat'); + +% generate the new output +[r3polynomial_new, tPerMm_new, skeleton_new, totalLengthMm_new] = electrodePointCloudModelEstimate(electrodePointCloudModelEstimate_inputs.elecPointCloudMm); + +% compare the reference data and the new outputs +assert(norm(r3polynomial_new - r3polynomial_ref) < tol) +assert(norm(tPerMm_new - tPerMm_ref) < tol) +assert(norm(skeleton_new - skeleton_ref) < tol) +assert(norm(totalLengthMm_new - totalLengthMm_ref) < tol) From 52a647ca46dcdb4a90947580a6cf742b343920ff Mon Sep 17 00:00:00 2001 From: Loic Marx Date: Sun, 30 Jun 2019 12:00:06 +0200 Subject: [PATCH 3/8] test if nargin = 2 --- test/suite/testElectrodePointCloudModelEstimate.m | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/suite/testElectrodePointCloudModelEstimate.m b/test/suite/testElectrodePointCloudModelEstimate.m index 670b89b..fa9ee39 100644 --- a/test/suite/testElectrodePointCloudModelEstimate.m +++ b/test/suite/testElectrodePointCloudModelEstimate.m @@ -34,3 +34,14 @@ assert(norm(tPerMm_new - tPerMm_ref) < tol) assert(norm(skeleton_new - skeleton_ref) < tol) assert(norm(totalLengthMm_new - totalLengthMm_ref) < tol) + +% generate the new output if nargin = 2 +[r3polynomial_var1_new, tPerMm_var1_new, skeleton_var1_new, totalLengthMm_var1_new] = electrodePointCloudModelEstimate(electrodePointCloudModelEstimate_inputs.elecPointCloudMm, electrodePointCloudModelEstimate_inputs.varargin{1, 1}); + + +% compare the reference data and the new outputs +assert(norm(r3polynomial_var1_new - r3polynomial_var1_ref) < tol) +assert(norm(tPerMm_var1_new - tPerMm_var1_ref) < tol) +assert(norm(skeleton_var1_new - skeleton_var1_ref) < tol) +assert(norm(totalLengthMm_var1_new - totalLengthMm_var1_ref) < tol) + From 30ab9c460c1ee7df69a72150df0632a4284060f2 Mon Sep 17 00:00:00 2001 From: Loic Marx Date: Sun, 30 Jun 2019 12:02:18 +0200 Subject: [PATCH 4/8] test if nargin =3 --- test/suite/testElectrodePointCloudModelEstimate.m | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/suite/testElectrodePointCloudModelEstimate.m b/test/suite/testElectrodePointCloudModelEstimate.m index fa9ee39..0a201d9 100644 --- a/test/suite/testElectrodePointCloudModelEstimate.m +++ b/test/suite/testElectrodePointCloudModelEstimate.m @@ -45,3 +45,11 @@ assert(norm(skeleton_var1_new - skeleton_var1_ref) < tol) assert(norm(totalLengthMm_var1_new - totalLengthMm_var1_ref) < tol) +% generate the new output if nargin = 3 +[r3polynomial_var2_new, tPerMm_var2_new, skeleton_var2_new, totalLengthMm_var2_new] = electrodePointCloudModelEstimate(electrodePointCloudModelEstimate_inputs.elecPointCloudMm, electrodePointCloudModelEstimate_inputs.varargin{1, 1}, electrodePointCloudModelEstimate_inputs.varargin{1, 2}); + +% compare the reference data and the new outputs +assert(norm(r3polynomial_var2_new - r3polynomial_var2_ref) < tol) +assert(norm(tPerMm_var2_new - tPerMm_var2_ref) < tol) +assert(norm(skeleton_var2_new - skeleton_var2_ref) < tol) +assert(norm(totalLengthMm_var2_new - totalLengthMm_var2_ref) < tol) From 00d0cb051d9c828903921390829deac4d2381128 Mon Sep 17 00:00:00 2001 From: Loic Marx Date: Sun, 30 Jun 2019 12:21:03 +0200 Subject: [PATCH 5/8] test warning message nargin <2 --- test/suite/testElectrodePointCloudModelEstimate.m | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/suite/testElectrodePointCloudModelEstimate.m b/test/suite/testElectrodePointCloudModelEstimate.m index 0a201d9..7cd44e5 100644 --- a/test/suite/testElectrodePointCloudModelEstimate.m +++ b/test/suite/testElectrodePointCloudModelEstimate.m @@ -53,3 +53,12 @@ assert(norm(tPerMm_var2_new - tPerMm_var2_ref) < tol) assert(norm(skeleton_var2_new - skeleton_var2_ref) < tol) assert(norm(totalLengthMm_var2_new - totalLengthMm_var2_ref) < tol) + +% capture the warning message when nargin < 2 +warningMessage = 'No Reference image for intensity weighting given! Accuracy is thus limited to voxel size!'; +assert(verifyFunctionWarning('electrodePointCloudModelEstimate', warningMessage, 'inputs', {electrodePointCloudModelEstimate_inputs.elecPointCloudMm})); + + +% capture the warning message if ~(length(zPlanes) < length(elecPointCloudMm)) +warningMessage = 'CT planes in Z direction are not exactly aligned. Trying with 0.1 mm tolerance'; +assert(verifyFunctionWarning('electrodePointCloudModelEstimate', warningMessage, 'inputs', {electrodePointCloudModelEstimate_inputs.elecPointCloudMm})); \ No newline at end of file From 3952e7240e64db86841fbe538d1dfa0726fbd5c7 Mon Sep 17 00:00:00 2001 From: Loic Marx Date: Sun, 30 Jun 2019 14:02:20 +0200 Subject: [PATCH 6/8] test warning message --- test/suite/testElectrodePointCloudModelEstimate.m | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/suite/testElectrodePointCloudModelEstimate.m b/test/suite/testElectrodePointCloudModelEstimate.m index 7cd44e5..88f4f3b 100644 --- a/test/suite/testElectrodePointCloudModelEstimate.m +++ b/test/suite/testElectrodePointCloudModelEstimate.m @@ -58,7 +58,16 @@ warningMessage = 'No Reference image for intensity weighting given! Accuracy is thus limited to voxel size!'; assert(verifyFunctionWarning('electrodePointCloudModelEstimate', warningMessage, 'inputs', {electrodePointCloudModelEstimate_inputs.elecPointCloudMm})); +% use another input argument to test error message +[r3polynomial_error_new, tPerMm_error_new, skeleton_error_new, totalLengthMm_error_new] = electrodePointCloudModelEstimate(elecPointCloudMm_error); + +% compare the reference data and the new outputs +assert(norm(r3polynomial_error_new - r3polynomial_error_ref) < tol) +assert(norm(tPerMm_error_new - tPerMm_error_ref) < tol) +assert(norm(skeleton_error_new - skeleton_error_ref) < tol) +assert(norm(totalLengthMm_error_new - totalLengthMm_error_ref) < tol) % capture the warning message if ~(length(zPlanes) < length(elecPointCloudMm)) warningMessage = 'CT planes in Z direction are not exactly aligned. Trying with 0.1 mm tolerance'; -assert(verifyFunctionWarning('electrodePointCloudModelEstimate', warningMessage, 'inputs', {electrodePointCloudModelEstimate_inputs.elecPointCloudMm})); \ No newline at end of file +assert(verifyFunctionWarning('electrodePointCloudModelEstimate', warningMessage, 'inputs', {elecPointCloudMm_error})); + From ee15d14f426a46d579e2386f4b73dcb9bddbb09a Mon Sep 17 00:00:00 2001 From: Loic Marx Date: Sun, 30 Jun 2019 14:56:41 +0200 Subject: [PATCH 7/8] format the code --- .../testElectrodePointCloudModelEstimate.m | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/test/suite/testElectrodePointCloudModelEstimate.m b/test/suite/testElectrodePointCloudModelEstimate.m index 88f4f3b..be59170 100644 --- a/test/suite/testElectrodePointCloudModelEstimate.m +++ b/test/suite/testElectrodePointCloudModelEstimate.m @@ -30,44 +30,46 @@ [r3polynomial_new, tPerMm_new, skeleton_new, totalLengthMm_new] = electrodePointCloudModelEstimate(electrodePointCloudModelEstimate_inputs.elecPointCloudMm); % compare the reference data and the new outputs -assert(norm(r3polynomial_new - r3polynomial_ref) < tol) -assert(norm(tPerMm_new - tPerMm_ref) < tol) -assert(norm(skeleton_new - skeleton_ref) < tol) -assert(norm(totalLengthMm_new - totalLengthMm_ref) < tol) +assert(norm(r3polynomial_new - refData_elecPointCloudMm.r3polynomial_ref) < tol) +assert(norm(tPerMm_new - refData_elecPointCloudMm.tPerMm_ref) < tol) +assert(norm(skeleton_new - refData_elecPointCloudMm.skeleton_ref) < tol) +assert(norm(totalLengthMm_new - refData_elecPointCloudMm.totalLengthMm_ref) < tol) % generate the new output if nargin = 2 [r3polynomial_var1_new, tPerMm_var1_new, skeleton_var1_new, totalLengthMm_var1_new] = electrodePointCloudModelEstimate(electrodePointCloudModelEstimate_inputs.elecPointCloudMm, electrodePointCloudModelEstimate_inputs.varargin{1, 1}); % compare the reference data and the new outputs -assert(norm(r3polynomial_var1_new - r3polynomial_var1_ref) < tol) -assert(norm(tPerMm_var1_new - tPerMm_var1_ref) < tol) -assert(norm(skeleton_var1_new - skeleton_var1_ref) < tol) -assert(norm(totalLengthMm_var1_new - totalLengthMm_var1_ref) < tol) +assert(norm(r3polynomial_var1_new - refData_elecPointCloudMm.r3polynomial_var1_ref) < tol) +assert(norm(tPerMm_var1_new - refData_elecPointCloudMm.tPerMm_var1_ref) < tol) +assert(norm(skeleton_var1_new - refData_elecPointCloudMm.skeleton_var1_ref) < tol) +assert(norm(totalLengthMm_var1_new - refData_elecPointCloudMm.totalLengthMm_var1_ref) < tol) % generate the new output if nargin = 3 [r3polynomial_var2_new, tPerMm_var2_new, skeleton_var2_new, totalLengthMm_var2_new] = electrodePointCloudModelEstimate(electrodePointCloudModelEstimate_inputs.elecPointCloudMm, electrodePointCloudModelEstimate_inputs.varargin{1, 1}, electrodePointCloudModelEstimate_inputs.varargin{1, 2}); % compare the reference data and the new outputs -assert(norm(r3polynomial_var2_new - r3polynomial_var2_ref) < tol) -assert(norm(tPerMm_var2_new - tPerMm_var2_ref) < tol) -assert(norm(skeleton_var2_new - skeleton_var2_ref) < tol) -assert(norm(totalLengthMm_var2_new - totalLengthMm_var2_ref) < tol) +assert(norm(r3polynomial_var2_new - refData_elecPointCloudMm.r3polynomial_var2_ref) < tol) +assert(norm(tPerMm_var2_new - refData_elecPointCloudMm.tPerMm_var2_ref) < tol) +assert(norm(skeleton_var2_new - refData_elecPointCloudMm.skeleton_var2_ref) < tol) +assert(norm(totalLengthMm_var2_new - refData_elecPointCloudMm.totalLengthMm_var2_ref) < tol) % capture the warning message when nargin < 2 warningMessage = 'No Reference image for intensity weighting given! Accuracy is thus limited to voxel size!'; assert(verifyFunctionWarning('electrodePointCloudModelEstimate', warningMessage, 'inputs', {electrodePointCloudModelEstimate_inputs.elecPointCloudMm})); % use another input argument to test error message -[r3polynomial_error_new, tPerMm_error_new, skeleton_error_new, totalLengthMm_error_new] = electrodePointCloudModelEstimate(elecPointCloudMm_error); +[r3polynomial_error_new, tPerMm_error_new, skeleton_error_new, totalLengthMm_error_new] = electrodePointCloudModelEstimate(refData_elecPointCloudMm.elecPointCloudMm_error); % compare the reference data and the new outputs -assert(norm(r3polynomial_error_new - r3polynomial_error_ref) < tol) -assert(norm(tPerMm_error_new - tPerMm_error_ref) < tol) -assert(norm(skeleton_error_new - skeleton_error_ref) < tol) -assert(norm(totalLengthMm_error_new - totalLengthMm_error_ref) < tol) +assert(norm(r3polynomial_error_new - refData_elecPointCloudMm.r3polynomial_error_ref) < tol) +assert(norm(tPerMm_error_new - refData_elecPointCloudMm.tPerMm_error_ref) < tol) +assert(norm(skeleton_error_new - refData_elecPointCloudMm.skeleton_error_ref) < tol) +assert(norm(totalLengthMm_error_new - refData_elecPointCloudMm.totalLengthMm_error_ref) < tol) % capture the warning message if ~(length(zPlanes) < length(elecPointCloudMm)) warningMessage = 'CT planes in Z direction are not exactly aligned. Trying with 0.1 mm tolerance'; -assert(verifyFunctionWarning('electrodePointCloudModelEstimate', warningMessage, 'inputs', {elecPointCloudMm_error})); +assert(verifyFunctionWarning('electrodePointCloudModelEstimate', warningMessage, 'inputs', {refData_elecPointCloudMm.elecPointCloudMm_error})); +% change back to the current directory +cd(currentDir); \ No newline at end of file From da5646fb8b9dcd2fe3aa87e5cfe0d4216d62bce2 Mon Sep 17 00:00:00 2001 From: Loic Marx Date: Sun, 30 Jun 2019 14:57:29 +0200 Subject: [PATCH 8/8] reference data for testElectrodePointCloudModelEstimate --- ...PointCloudModelEstimate_elecPointCloudMm.mat | Bin 0 -> 13158 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/suite/refData_testElectrodePointCloudModelEstimate_elecPointCloudMm.mat diff --git a/test/suite/refData_testElectrodePointCloudModelEstimate_elecPointCloudMm.mat b/test/suite/refData_testElectrodePointCloudModelEstimate_elecPointCloudMm.mat new file mode 100644 index 0000000000000000000000000000000000000000..94794b87e9153b37a9f23a33a3cdaf87ed0857e4 GIT binary patch literal 13158 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 literal 0 HcmV?d00001