function [status,message] = measureSCase(varargin) % MEASURESCASE Update the entire SCase DB with anatimical measurements. % The script measureSCase will replace 3 prevvious functions % 1) rebuildDatabaseScapulaMeasurements.m --> list of all sCases --> execute scapula_measure.m % 2) scapula_measure.m --> execute scapula_calculation and save results in Excel and SQL % 3) scapula_calculation.m --> perform anatomical analysis --> results varaiable % Currently, the script should be run for the entire DB % Run from lbovenus % The script can be run from (lbovenus) server as follows % cd /home/shoulder/methods/matlab/database % matlab -nojvm -nodisplay -nosplash -r "measureSCase;quit" % The log file can be checked with shell command % tail -f log/measureSCase.log % It take ~30 min for 700 cases when run from server. % After run from server, the output file % /shoulder/data/Excel/xlsFromMatlab/anatomy.csv % must be open from Excel and saved % as xls at the same location. % Input % No output yet % Output % File /shoulder/data/Excel/xlsFromMatlab/anatomy.csv % File /shoulder/data/Excel/xlsFromMatlab/anatomy.xls (only windows) % File /home/shoulder/data/matlab/SCaseDB.mat % File {SCaseId}.mat in each {SCaseId}/{CT}/matlab directory % logs in /log/measureSCase.log % Example: measureSCase % Author: Alexandre Terrier, EPFL-LBO % Creation date: 2018-07-01 % Revision date: 2018-08-15 % TO DO: % Read first last anatomy.csv and/or SCaseDB.mat % Fill with patient and clinical data, from excel or MySQL % use argument to redo or update % Save csv within the main loop (not sure it's a good idea) % Add more message in log % Add more test to assess validity of data % Update MySQL % Rename all objects with a capital % Make it faster by not loading scapula surface if already in SCaseDB.mat % Add argument 'load' to force reload files even if they are alerady in DB % Add argument 'measure' to force re-measuring event if measurement is already in DB % Add "scapula_addmeasure.m" --> should be coded in ShoulderCase class tic; % Start stopwatch timer %% Initialisation of paths % Should be replaced by a function dataDir = '../../../data'; % location of data logDir = 'log'; % log file in xls folder xlsDir = [dataDir '/Excel/xlsFromMatlab']; matlabDir = [dataDir '/matlab']; %% Add path to ShoulderCase class addpath('ShoulderCase'); %% Open log file filename = 'measureSCase.log'; filename = [logDir '/' filename]; logFileId = fopen(filename, 'w'); fprintf(logFileId, 'measureSCase log file'); fprintf(logFileId, ['\nDate: ' datestr(datetime)]); %% Instance of a ShoulderCase object if (exist('sCase','var') > 0) clear sCase; % Check for delete method end sCase = ShoulderCase; % Instanciate a ShoulderCase object %% Get list of all SCase sCaseList = listSCase(); % get list of sCases ('N', 'P', no arg for all) % For debuging, sCaseList is reduced to the first 5 cases % sCaseList = sCaseList(1:5); % For debuging, sCaseList is reduced to 1 element % sCaseList(1) = struct('id', 'P313', 'dir', 'toto'); % sCaseList(2) = struct('id', 'P315', 'dir', 'toto'); %% Start loop over sCases in sCaseList sCaseN = length(sCaseList); % Number of sCases for sCaseIdx = 1:sCaseN sCaseId = sCaseList(sCaseIdx).id; % fprintf(logFileId, ['\n' num2str(sCaseIdx) '/' num2str(sCaseN) '. ' sCaseId ': ']); sCase(sCaseIdx).id = sCaseId; output = sCase(sCaseIdx).path; % Set data path of this sCase if output % Continue if sCase amira path exist % Load scapula data from amira folder and set scapular coordinate system output = sCase(sCaseIdx).shoulder.scapula.load; % Load data from amira directory if output sCase(sCaseIdx).shoulder.scapula.coordSysSet; % Set scapular coordinate system % Load glenoid data from amira folder and set glenoid morphology output = sCase(sCaseIdx).shoulder.scapula.glenoid.load; % Load data from amira directory if output sCase(sCaseIdx).shoulder.scapula.glenoid.morphology; % Perform morphological measurements % Load humerus data from amira folder and set subluxation output = sCase(sCaseIdx).shoulder.humerus.load; % load data from amira directory if output sCase(sCaseIdx).shoulder.humerus.subluxation; % Calcul subluxation % Acromion morphology sCase(sCaseIdx).shoulder.scapula.acromion.morphology; % Should be run after sCase.shoulder.humerus % Save sCase object in file sCase.id/matlab/sCase_CNNN.m sCase(sCaseIdx).matlabSave; % We might add here the cvs save fprintf(logFileId, 'OK'); else fprintf(logFileId, 'humerus.load problem'); end else fprintf(logFileId, 'glenoid.load problem'); end else fprintf(logFileId, 'scapula.load problem'); end else fprintf(logFileId, 'No amira folder'); end end %% Save the entire SCase array as a matlab file filename = 'SCaseDB'; filename = [matlabDir '/' filename '.mat']; try SCaseDB = sCase; save(filename, 'SCaseDB'); fprintf(logFileId, ['\nSaved dat file: ' filename]); outputArg = 1; catch fprintf(logFileId, '\nError saving SCaseDB matlab file \n'); outputArg = -1; end %% Write csv file % This might be a function (SCase.csvSave()). The input would be a filename and a structure % data % Replace header and data by structure. Currently not working %{ txtFilename = [xlsDir, '/anatomy.txt']; % Name of the txt file DataStruc = struc(... 'sCase_id', sCase.id, ... 'shoulder_side', sCase.shoulder.side,... 'glenoid_radius', sCase.shoulder.scapula.glenoid.radius,... 'glenoid_sphereRMSE', sCase.shoulder.scapula.glenoid.sphereRMSE,... 'glenoid_depth', sCase.shoulder.scapula.glenoid.depth,... 'glenoid_width', sCase.shoulder.scapula.glenoid.width,... 'glenoid_height', sCase.shoulder.scapula.glenoid.height,... 'glenoid_centerPA', sCase.shoulder.scapula.glenoid.centerLocal(1),... 'glenoid_centerIS', sCase.shoulder.scapula.glenoid.centerLocal(2),... 'glenoid_centerML', sCase.shoulder.scapula.glenoid.centerLocal(3),... 'glenoid_versionAmpl', sCase.shoulder.scapula.glenoid.versionAmpl,... 'glenoid_versionOrient', sCase.shoulder.scapula.glenoid.versionOrient,... 'glenoid_version', sCase.shoulder.scapula.glenoid.version,... 'glenoid_inclination', sCase.shoulder.scapula.glenoid.inclination,... 'humerus_jointRadius', sCase.shoulder.humerus.jointRadius,... 'humerus_headRadius', sCase.shoulder.humerus.radius,... 'humerus_GHSAmpl', sCase.shoulder.humerus.GHSAmpl,... 'humerus_GHSOrient', sCase.shoulder.humerus.GHSOrient,... 'humerus_SHSAmpl', sCase.shoulder.humerus.SHSAmpl,... 'humerus_SHSOrient', sCase.shoulder.humerus.SHSOrient,... 'humerus_SHSAngle', sCase.shoulder.humerus.SHSAngle,... 'humerus_SHSPA', sCase.shoulder.humerus.SHSPA,... 'humerus_SHSIS', sCase.shoulder.humerus.SHSIS,... 'acromion_AI', sCase.shoulder.scapula.acromion.AI,... 'acromion_CSA', sCase.shoulder.scapula.acromion.CSA,... 'acromion_PS', sCase.shoulder.scapula.acromion.PS... ); DataTable = strct2table(Data); writetable(DataTable,filename); %} % Header of the csv file dataHeader = [... 'sCase_id,' ... 'shoulder_side,' ... 'glenoid_radius,' ... 'glenoid_sphereRMSE,' ... 'glenoid_depth,' ... 'glenoid_width,' ... 'glenoid_height,' ... 'glenoid_centerPA,' ... 'glenoid_centerIS,' ... 'glenoid_centerML,' ... 'glenoid_versionAmpl,' ... 'glenoid_versionOrient,' ... 'glenoid_version,' ... 'glenoid_inclination,' ... 'humerus_jointRadius,' ... 'humerus_headRadius,' ... 'humerus_GHSAmpl,' ... 'humerus_GHSOrient,' ... 'humerus_SHSAmpl,' ... 'humerus_SHSOrient,' ... 'humerus_SHSAngle,' ... 'humerus_SHSPA,' ... 'humerus_SHSIS,' ... 'acromion_AI,' ... 'acromion_CSA,' ... 'acromion_PS,'... 'acromion_IE'... ]; csvFilename = [xlsDir, '/anatomy.csv']; % Name of the csv file csvFileId = fopen(csvFilename, 'w'); fprintf(csvFileId,dataHeader); % Write header for sCaseIdx = 1:length(sCaseList) % Loop on sCaseList to write data in csv fprintf(csvFileId,['\n'... sCase(sCaseIdx).id ','... % sCase_id sCase(sCaseIdx).shoulder.side ','... % shoulder_side num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.radius) ','... % glenoid_radius num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.sphereRMSE) ','... % glenoid_sphereRMSE num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.depth) ','... % glenoid_depth num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.width) ','... % glenoid_width num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.height) ','... % glenoid_height num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.centerLocal(1)) ','... % glenoid_centerPA num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.centerLocal(2)) ','... % glenoid_centerIS num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.centerLocal(3)) ','... % glenoid_centerML num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.versionAmpl) ','... % glenoid_versionAmpl num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.versionOrient) ','... % glenoid_versionOrient num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.version) ','... % glenoid_version num2str(sCase(sCaseIdx).shoulder.scapula.glenoid.inclination) ','... % glenoid_inclination num2str(sCase(sCaseIdx).shoulder.humerus.jointRadius) ','... % humerus_jointRadius num2str(sCase(sCaseIdx).shoulder.humerus.radius) ','... % humerus_headRadius num2str(sCase(sCaseIdx).shoulder.humerus.GHSAmpl) ','... % humerus_GHSAmpl num2str(sCase(sCaseIdx).shoulder.humerus.GHSOrient) ','... % humerus_GHSOrient num2str(sCase(sCaseIdx).shoulder.humerus.SHSAmpl) ','... % humerus_SHSAmpl num2str(sCase(sCaseIdx).shoulder.humerus.SHSOrient) ','... % humerus_SHSOrient num2str(sCase(sCaseIdx).shoulder.humerus.SHSAngle) ','... % humerus_SHSAgle num2str(sCase(sCaseIdx).shoulder.humerus.SHSPA) ','... % humerus_SHSPA num2str(sCase(sCaseIdx).shoulder.humerus.SHSIS) ','... % humerus_SHSIS num2str(sCase(sCaseIdx).shoulder.scapula.acromion.AI) ','... % acromion_AI num2str(sCase(sCaseIdx).shoulder.scapula.acromion.CSA) ','... % acromion_CSA num2str(sCase(sCaseIdx).shoulder.scapula.acromion.PS) ','... % acromion_PS num2str(sCase(sCaseIdx).shoulder.scapula.acromion.IE)... % acromion_IE ]); end fclose(csvFileId); fprintf(logFileId, ['\nSaved csv file: ' csvFilename]); %% Write xls file (Windows only) [~,message] = csv2xlsSCase(csvFilename); fprintf(logFileId, message); % If run from non-windows system, only csv will be produced. The xls can be % produced by opening the csv from Excel and save as xls. % Could be a function with 1 input (cvsFilenames %{ xlsFilename = strrep(csvFilename, '.csv', '.xls'); % Replace .csv by .xls if ispc % Check if run from windows! % Read cvs file as table and write the table as xls cvsTable = readtable(csvFilename); % Get table from csv (only way to read non-numeric data) cvsCell = table2cell(cvsTable); % Tranform table cell array dataHeader = cvsTable.Properties.VariableNames; % Get header cvsCell = [dataHeader; cvsCell]; % Add header sheet = 'anatomy'; % Sheet name of the xls file [status,message] = xlswrite(xlsFilename, cvsCell, sheet); % Save xls if status fprintf(logFileId, ['\nSaved ' xlsFilename]); else fprintf(logFileId, ['\nCould not save ' xlsFilename]); fprintf(logFileId, ['\n' message.identifier]); fprintf(logFileId, ['\n' message.message]); end else fprintf(logFileId, ['\n' xlsFilename ' not saved. Open and save as xls from Excel']); end %} %% Close log file fprintf(logFileId, '\n\nsCases measured: %s', num2str(length(sCaseList))); % Number of sCases measured fprintf(logFileId, '\nElapsed time (s): %s', num2str(toc)); % stopwatch timer fprintf(logFileId, '\n\n'); fclose(logFileId); % Close log file %% Output of the sCase if required by argument % sCase.output % inputArg = abaqus/density/references/ % update mySQL % sCase.sqlSave status = 1; message = 'OK'; end