This MAT LAB program analyzes patient quality assurance data from the DAVID Patient Quality Assurance software. It reads patient data files, analyzes the data for each beam, session and segment, and generates output files and plots showing any warnings or alarms where the measured values exceed thresholds compared to the reference values. Key functions include reading and validating the patient files, analyzing the data, writing output files, and plotting the results.
1. MAT LAB program for DAVID Patient Quality Assurance software
%%%%%% DAVID Patient Quality Assurance software 'DQA' %%%%%%%%%%%%%%
%%% Run the program and key in the date as yyyy-mm-dd and click OK and choose
%%% The patient Data folder to be analyze
clear all;
clc;
if ~exist('Results','dir')
mkdir('Results');
end
date_to_print = datestr(now,'yyyy-mm-dd'); % date of irradiation
prompt = {'Enter Date:'};
dlg_title = 'Enter session date';
num_lines = 1;
def = {date_to_print};
answer = inputdlg(prompt,dlg_title,num_lines,def);
try
dnum = datenum(answer);
while datenum(datestr(now,'yyyy-mm-dd'))< dnum
h=warndlg('Huh! Cannot analyze future session try again!');
uiwait(h);
answer = inputdlg(prompt,dlg_title,num_lines,def);
dnum = datenum(answer);
end
date_to_print=answer{1}; %%%% '2013-10-09';
FolderName= uigetdir(pwd, 'Enter file to read');
F_cell=genpath(FolderName);
date_add='Session Date:';
repstr = [FolderName, ''];
F_cell = strrep(F_cell, repstr, '');
F_cell = strrep(F_cell, FolderName, '');
F_cell=regexp(F_cell, ';','split');
F_cell =F_cell(1:end-1);
%types={'NDD','DD','ED'};% with Electrical data
types={'DD'};% NO Electrical data
%suppressEmpty= false; % To suppress subject without error
suppressEmpty= false; % To show all subject including patients without error
%% directory and save folder structure
num_found=0;
o_tdir='Results';
filename=fullfile(['results_',datestr(now,'DD_mm_YY_HH-MM_SSAM.txt')]);
fid=fopen(fullfile(o_tdir,filename),'w');
fclose(fid);
out_sess =[];
h = waitbar(0,'Please wait...','Name','Analysing DAVID Patient Data');
steps=numel(F_cell);
for i=1:length(F_cell)
if ~isempty(F_cell(i))
fname=F_cell{i};
temp_files=dir(fullfile(FolderName, fname));
for file_num=1:length(temp_files)
2. tfname = temp_files(file_num).name;
if strcmp(tfname, '.')||strcmp(tfname,
'..')||temp_files(file_num).isdir
continue;
end
full_tfname = fullfile(FolderName,fname,tfname);
[pathstr, name, ext] = fileparts(full_tfname);
if ~strcmp(ext, '.dat')||~exist(full_tfname,'file')
continue
end
[isValidfile, data] = checkValidFile(full_tfname);
if ~isValidfile
continue
end
num_found = num_found+1;
out{num_found}.source = full_tfname;
out{num_found}.patientdata = data;
out{num_found}.data =readFile(full_tfname);
disp(['Processing file : ' full_tfname]);
%% Analyze data
% 'NDD' : for Non Deconvoluted,
% 'DD' : for Deconvoluted
% 'ED' : for Electrical Data
if isempty(out{num_found}.data.error)
% o_tfname = [name,'.txt'];
% o_tfname = ['Output.txt'];
% o_tdir=fullfile(tempFolder,fname);
[sess] = getDateSession(full_tfname, date_to_print) ;
if isempty(sess)|| (sess==0)
disp(['Cannot find date in file: ', full_tfname])
else
[out2] =
analyzeData(out{num_found},types,o_tdir,filename,sess,date_to_print,suppressE
mpty);
out_sess = sess;
disp('Processed successfully!');
end
else
disp('Could not process file: the file has an error!');
end
end
end
waitbar(i/steps,h,['Please wait...',num2str(i/steps*100),'%']);
end
close(h);
fid=fopen(fullfile(o_tdir,filename),'a+');
fprintf(fid,'----------------------------------------------------------------
---------');
fprintf(fid,'nn %-20s%40s','Physician/Arzt','Physicist/Physiker');
fclose(fid);
disp('Processing finished ..');
catch
3. errordlg({'Invalid input Date. Program will abort!'});
end
The Function that carry out the analysis
function [out] = analyzeData(Alldata,types,
path_name,filename,sess_num,date_to_print,suppressEmpty)
%ANALYZEDATA Summary of this function goes here
% Detailed explanation goes here
%types={'NDD','DD','ED'};
data=Alldata.data;
info=Alldata.patientdata;
%sess_num=14;
a=exist(path_name, 'dir');
if a ~= 7
mkdir(path_name);
end
out=[];
filename = fullfile(path_name, filename);
fid=fopen(filename,'a+');
if ~suppressEmpty
names = fieldnames(info);
fprintf(fid,'################################################################
####################n');
fprintf(fid,'source : %sn',Alldata.source);
for i=1:numel(names);
f=names{i};
fprintf(fid,[f,' : ',info.(f),'n']);
end
fprintf(fid,'%10s%10s%10s%10s%10s%10sn', 'Info
Type:','Beam','Type','Session','Segment','Leafs');
end
count=0;
for bm=1:data.info.BeamCount
BeamName =['BEAM_',num2str(bm)];
if ~isfield(data.info, BeamName)
continue
end
for tp=1:length(types)
TypeName=types{tp};
for sess=sess_num%1:data.info.SessionCount
if sess > data.info.SessionCount
disp('Session not found');
continue
end
SessionName =['SESSION_',num2str(sess)];
if ~isfield(data.info.(BeamName), TypeName)
continue
end
numSegs = data.info.(BeamName).(TypeName).SegmentCount;
tempData=data.beamData.(BeamName).(TypeName).(SessionName);
Ref=data.beamData.(BeamName).(TypeName).REFERENCE.SEG;
4. % res
for sg=1:numSegs
factorX0 = max(max(Ref(sg,:))).100;
factorX1 = max(max(tempData.SEG(sg,:))).100;
res= factorX1.*tempData.SEG(sg,:)-factorX0.*Ref(sg,:);
% res=factorX1(sg)* tempData.SEG(sg,:)-refs;
out.beamData.(BeamName).(TypeName).(SessionName).SEG(sg,:) =
res;
tempWarn = find((res>=3)&(res<5));
tmm='';
if ~isempty(tempWarn)
count=count+1;
out.AWData.(BeamName).(TypeName).(SessionName).(['SEG_',num2str(sg)]).Warn=te
mpWarn;
tmm='Warning';
if ~isempty(tmm)
if (count ==1)&&suppressEmpty
names = fieldnames(info);
fprintf(fid,'################################################################
####################n');
fprintf(fid,'source : %sn',Alldata.source);
for i=1:numel(names);
f=names{i};
fprintf(fid,[f,' : ',info.(f),'n']);
end
fprintf(fid,'%10s%10s%10s%10s%10s%10sn', 'Info
Type:','Beam','Type','Session','Segment','Leafs');
end
fprintf(fid,'%10s%10d%10s%10d%10d %sn', tmm,bm,
TypeName, sess, sg, ['[',num2str(tempWarn),']']);
end
% fprintf(fid,'%10s%10d%10s%10d%10d%15sn',
'Warning',bm, TypeName, sess, sg, ['[',num2str(tempWarn),']']);
end
tempAlarm = find(res>=5);
if ~isempty(tempAlarm)
count=count+1;
out.AWData.(BeamName).(TypeName).(SessionName).(['SEG_',num2str(sg)]).Alarm=t
empAlarm;
tmm='Alarm';
if ~isempty(tmm)
if (count ==1)&&suppressEmpty
names = fieldnames(info);
fprintf(fid,'################################################################
####################n');
fprintf(fid,'source : %sn',Alldata.source);
for i=1:numel(names);
f=names{i};
fprintf(fid,[f,' : ',info.(f),'n']);
end
fprintf(fid,'%10s%10s%10s%10s%10s%10sn', 'Info
Type:','Beam','Type','Session','Segment','Leafs');
5. end
fprintf(fid,'%10s%10d%10s%10d%10d %sn', tmm,bm,
TypeName, sess, sg, ['[',num2str(tempAlarm),']']);
end
% fprintf(fid,'%10s%10d%10s%10d%10d%15sn',
'Alarm',bm, TypeName, sess, sg, ['[',num2str(tempAlarm),']']);
end
end
end
end
end
if (count == 0)&&(~suppressEmpty)
fprintf(fid,'n++++++++++++++++++++++++++++ NO WARNING NOR ERROR FOUND
++++++++++++++++++++++++++++nn');
end
fprintf(fid,'nTreatment date: %s and session number: %dn',date_to_print,
sess_num);
fclose(fid);
end
Plot Function
function [ output_args ] = plotResults(data, out, types)
%PLOTRESULTS Summary of this function goes here
% Detailed explanation goes here
h=figure(1);
for bm=1:data.info.BeamCount
BeamName =['BEAM_',num2str(bm)];
if isfield(out.AWData, BeamName)
for tp=1:length(types)
TypeName=types{tp};
if isfield(out.AWData.(BeamName), TypeName)
for sess=1:data.info.SessionCount
SessionName =['SESSION_',num2str(sess)];
if isfield(out.AWData.(BeamName).(TypeName), SessionName)
numSegs =
data.info.(BeamName).(TypeName).SegmentCount;
for sg=1:numSegs
SegName = ['SEG_',num2str(sg)];
tt=['Beam: ',num2str(bm),', Type: ',TypeName,',
Session: ',num2str(sess),', Segment: ', num2str(sg)];
if
isfield(out.AWData.(BeamName).(TypeName).(SessionName), SegName)
subplot(2,2,1);
bar(data.beamData.(BeamName).(TypeName).REFERENCE.SEG(sg,:))
legend('Reference Data')
title(tt);
subplot(2,2,2)
segData=data.beamData.(BeamName).(TypeName).(SessionName).SEG(sg,:);
6. bar(segData)
legend('Measured Data')
subplot(2,2,3)
segData=out.beamData.(BeamName).(TypeName).(SessionName).SEG(sg,:);
bar(segData)
legend('Percentage Error');
subplot(2,2,4)
if
isfield(out.AWData.(BeamName).(TypeName).(SessionName).(SegName), 'Alarm')
segData=out.beamData.(BeamName).(TypeName).(SessionName).SEG(sg,:);
idx=
out.AWData.(BeamName).(TypeName).(SessionName).(SegName).Alarm;
bar(segData)
legend('Percentage Error');
hold on;
wd=zeros(size(segData));
wd(idx)=out.beamData.(BeamName).(TypeName).(SessionName).SEG(sg,idx);
bar(wd,'r')
legend('Percentage Error','Alarm');
end
if
isfield(out.AWData.(BeamName).(TypeName).(SessionName).(SegName), 'Warn')
segData=out.beamData.(BeamName).(TypeName).(SessionName).SEG(sg,:);
idx=
out.AWData.(BeamName).(TypeName).(SessionName).(SegName).Warn;
bar(segData)
legend();
hold on;
wd=zeros(size(segData));
wd(idx)=out.beamData.(BeamName).(TypeName).(SessionName).SEG(sg,idx);
bar(wd,'y')
legend('Percentage Error','Warning');
end
hold off;
pause
else
end
end
end
end
end
end
end
end
end
7. Function That Check for Validity of file
function [isValidfile, data] = checkValidFile( filename )
%CHECKVALIDFILE Summary of this function goes here
% detailed explanation goes here
%% Get number of sessions
fid = fopen(filename);
%% Get number of sessions
isValidfile = false;
data=[];
while ~feof(fid)
line=fgetl(fid);
temp=regexp(line,'PATIENT INFO:.*', 'match');
if ~isempty(temp)
data.firstname = fgetl(fid);
data.lastname = fgetl(fid);
data.id = fgetl(fid);
data.sex = fgetl(fid);
data.birthday = fgetl(fid);
while ~feof(fid)
line=fgetl(fid);
temp=regexp(line,'INFO SESSION.*', 'match');
if ~isempty(temp)
isValidfile = true;
break;
end
end
break;
end
end
fclose(fid);
end
Function That Read file from different folders
function data=readFile( filename)
% dataType can be :
% 1: 'NON-DECONVOLUTED DATA'
% 2: 'DECONVOLUTED DATA'
% 3: 'ELECTRICAL DATA'
dataType ={struct('Name','NDD','Value','NON-DECONVOLUTED DATA'),...
struct('Name','DD','Value','DECONVOLUTED DATA'),...
struct('Name','ED','Value','ELECTRICAL DATA')};
%This function generate a -mat binary file for a given patient's data
%NB: Output name must be a .mat file
%eg: readFile('patientfilename.dat','given file name outputfilename.mat');
%load('the given filename.mat')
%filename='I-HKBP1810.dat';
%eg - readFile('I-HKBP1810.dat','Ruthurp.mat');
%to open the file - load('Ruthurp.mat')
%for i=1: length(dataType)
[data.beamData, data.info, data.error] = readData(filename, dataType);
8. %end
%save(outfile, 'data');
end
function [data, info, error] = readData(filename, dataType)
fid = fopen(filename);
%% Get number of sessions
numOfSess = [];
data=[];
info=[];
error=[];
fileIsOk= true;
while ~feof(fid)&&isempty(numOfSess)
line=fgetl(fid);
temp=regexp(line,'# SESS.*', 'match');
if ~isempty(temp)
numOfSess= str2double(getPropValue(line,'SESS'))-1;
break;
end
end
%% Get number of sessions
numOfBeam = [];
while ~feof(fid)&&isempty(numOfBeam)
line=fgetl(fid);
temp=regexp(line,'# BEAMS.*', 'match');
if ~isempty(temp)
numOfBeam= str2double(getPropValue(line,'BEAMS'));
break;
end
end
%data = cell(1,numOfBeam);
info.BeamCount = numOfBeam;
info.SessionCount = numOfSess;
beamCount=0;
while ~feof(fid)
noNextSegError =[];
noNextSegErrorcnt=0;
if ((beamCount == numOfBeam) || (beamCount==0))
if (beamCount== numOfBeam)
beamCount =0;
else
line=fgetl(fid);
end
type=[];
for j=1:length(dataType)
temp=regexp(line,dataType{j}.Value, 'match');
if ~isempty(temp)
type=dataType{j};
break;
end
end
if isempty(type)
continue;
end
else
9. % beamCount= 0;
end
line=fgetl(fid);
temp=regexp(line,'BEAM', 'match');
if ~isempty(temp)
beamCount = beamCount+1;
beamName= ['BEAM_',num2str(beamCount)] ;
end
line=fgetl(fid);
temp=regexp(line,'# SEG.*', 'match');
if ~isempty(temp)
numOfSeg=str2double(getPropValue(line,'SEG'));
end
line=fgetl(fid);
temp=regexp(line,'# VALUES.*', 'match');
if ~isempty(temp)
numOfValues=str2double(getPropValue(line,'VALUES'));
end
info.(beamName).(type.Name).('SegmentCount') =numOfSeg;
info.(beamName).(type.Name).('ValuesCount') =numOfValues;
tempData=[];
noNextSeg = false;
for sessionCountTemp=1:numOfSess+1
if sessionCountTemp==1
sessionName='REFERENCE';
else
sessionCount= sessionCountTemp -1;
sessionName=['SESSION_',num2str(sessionCount)];
end
if ~noNextSeg
line=fgetl(fid);
end
segs=[];
noNextSeg = false;
for segCount=1:numOfSeg
line=fgetl(fid);
if isempty(strfind(line,['SEG ', num2str(segCount)]))
noNextSeg= true;
noNextSegErrorcnt = noNextSegErrorcnt+1;
noNextSegError{noNextSegErrorcnt}.session=sessionCountTemp-
1;
noNextSegError{noNextSegErrorcnt}.seg=segCount-1;
noNextSegError{noNextSegErrorcnt}.segexpected=numOfSeg;
break;
end
value = getPropValue( line,'SEG');
eval(['value=[',value{1},']'';'])
st=length(value)-numOfValues+1;
segs(segCount,:) =value(st:end);
end
% tempData.(sessionName).('Ref') = segs(1,:);
tempData.(sessionName).('SEG') = segs;
end