classdef PULSE < matlab.apps.AppBase

    % Properties that correspond to app components
    properties (Access = public)
        UIFigure                    matlab.ui.Figure
        RunEditField                matlab.ui.control.NumericEditField
        RunEditFieldLabel           matlab.ui.control.Label
        AnalysisButton              matlab.ui.control.Button
        xaxiscalButton              matlab.ui.control.Button
        instepsofEditField          matlab.ui.control.NumericEditField
        instepsofEditFieldLabel     matlab.ui.control.Label
        topoleEditField             matlab.ui.control.NumericEditField
        topoleEditFieldLabel        matlab.ui.control.Label
        FrompoleEditField           matlab.ui.control.NumericEditField
        FrompoleEditFieldLabel      matlab.ui.control.Label
        OperatorEditField           matlab.ui.control.EditField
        OperatorEditFieldLabel      matlab.ui.control.Label
        LowerJawLabel               matlab.ui.control.Label
        UpperJawLabel               matlab.ui.control.Label
        PrecisionUndulatorLocationSystemEvaluationPULSELabel  matlab.ui.control.Label
        STATUSEditField             matlab.ui.control.EditField
        STATUSEditFieldLabel        matlab.ui.control.Label
        CommentsTextArea            matlab.ui.control.TextArea
        CommentsTextAreaLabel       matlab.ui.control.Label
        NominalgapmmEditField       matlab.ui.control.NumericEditField
        NominalgapmmEditFieldLabel  matlab.ui.control.Label
        UndulatorEditField          matlab.ui.control.EditField
        UndulatorEditFieldLabel     matlab.ui.control.Label
        MeasurepolesButton          matlab.ui.control.Button
        UndulatortypeButtonGroup    matlab.ui.container.ButtonGroup
        SXUButton                   matlab.ui.control.RadioButton
        HESXUButton                 matlab.ui.control.RadioButton
        LocateundulatorButton       matlab.ui.control.Button
        UIAxes2                     matlab.ui.control.UIAxes
        UIAxes                      matlab.ui.control.UIAxes
    end

    
    properties (Access = private)
        ioFilesPath % Description
    end
    

    % Callbacks that handle component events
    methods (Access = private)

        % Code that executes after component creation
        function startupFcn(app)
            app.ioFilesPath = 'S:\magdata\DOVER BENCH\Dover bench touch probe IO files';
            pause(1.0);
            cd (app.ioFilesPath);
            runNum=importdata("runNum.txt");
            app.RunEditField.Value = runNum;
            

        end

        % Button pushed function: LocateundulatorButton
        function LocateundulatorButtonPushed(app, event)
            % List of things to do:
            % Define clearance for x
            % Create a function to enable or dissable all
            % Manage file names
            % When measuring the poles, print information about run,
            % undulator, operator, and time
            % save data output raw 
            
            
            
            cd (app.ioFilesPath)
            app.LocateundulatorButton.Enable = "off";
            app.MeasurepolesButton.Enable = "off";
            app.NominalgapmmEditField.Enable = "off";
            app.UndulatorEditField.Enable = "off";
            app.UndulatortypeButtonGroup.Enable = "off";
            app.CommentsTextArea.Enable = "off";
            app.OperatorEditField.Enable = "off";
            app.FrompoleEditField.Enable = "off";
            app.topoleEditField.Enable = "off";
            app.instepsofEditField.Enable = "off";
            app.xaxiscalButton.Enable = "off";
            app.AnalysisButton.Enable = "off";
            app.RunEditField.Enable = "off";

            runNum = app.RunEditField.Value;
            idNum = app.UndulatorEditField.Value;
            sel = app.UndulatortypeButtonGroup.SelectedObject;  % the selected radio button
            selText = sel.Text;
            operator = app.OperatorEditField.Value;

            % Format today’s date as YYYY-MM-DD
            todayStr = datestr(datetime('now'),'yyyy-mm-dd HH-MM-SS');
            todayStrColon = datestr(datetime('now'),'yyyy-mm-dd HH:MM:SS');

            % Zero-pad the ID to 3 digits (if not already)
            idStr = sprintf('%03d', str2double(idNum));   

            % Build the filename
            fileName = sprintf('LOC_%s-%s_Run%d_%s', selText, idStr, runNum, todayStr);


            fid=fopen('GapChange.inp',"w");
            fprintf(fid,'%.4f %.4f', 10, 0);
            fclose(fid);

            fid=fopen('GapRequest.flg',"w");
            fclose(fid);

            pauseTime = 0.5;
            delete('Reply.txt');
            format long eng

            
    
            app.STATUSEditField.Value = 'Starting lateral pole face location...';
            pause(5);
            app.STATUSEditField.Value = '---';
            pause(5);

            outfilename='Dover.inp';





            %%%%%%%%%%%%%%%%%%%%

            clpclear_x = -80;
            usZ_BlockFace_x = -30; % big tolerance
            usZ_BlockFace_y = -32; % big tolerance

            % Find and measure the reference block
            usZ_BlockFace_z = 4147.592; % z position of the US side of the reference block face in a Z plane (i.e., Z=cte plane)
            

            X_BlockFace_x = -74.5455; % !

            BlockGapUpper_y = -7.1305; % !

            BlockGapLower_y = -17.1355; % !

            L = 25.4; % ! reference block length, in mm

            BlockCenter_y = (BlockGapUpper_y + BlockGapLower_y)/2;
   

            % Measure face z us

            fid=fopen(outfilename,"w");
    
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', clpclear_x, usZ_BlockFace_y,  usZ_BlockFace_z - 10);
            
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usZ_BlockFace_x, usZ_BlockFace_y,  usZ_BlockFace_z - 10);

            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   0   -1   0\n', usZ_BlockFace_x, usZ_BlockFace_y,  usZ_BlockFace_z);

            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usZ_BlockFace_x, usZ_BlockFace_y,  usZ_BlockFace_z - 10);

            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usZ_BlockFace_x, BlockCenter_y,  usZ_BlockFace_z - 10);

            fclose(fid);
            

            fid=fopen('Request.flg',"w");
            fclose(fid);

            % Update usZ_BlockFace_z
            % Matlab waits until Q-Server is ready
            flag = 0;
            while flag == 0
                app.STATUSEditField.Value = 'Locating the lateral pole face - measurement in progress...';
                fid = fopen('Reply.txt', 'r');
                if fid ~= -1
                    str = fgetl(fid);
                    fclose(fid);
                    if ischar(str) && contains(str, 'DONE=1')
                        flag = 1;
                        disp('Process complete: DONE=1 found.');
                    else
                        pause(1); % wait for 1 second before checking again
                    end
                else
                    pause(1);
                end
            end
            delete('Reply.txt');
            pause(1);

            fid = fopen('Kugler.out', 'r');
            str = fgetl(fid);
            str = fgetl(fid);
            fclose(fid);

            usZ_BlockFace_z = sscanf(str, '%f');
            usZ_BlockFace_z = usZ_BlockFace_z(3) * 1e3;

            BlockCenter_z = usZ_BlockFace_z + L/2;


            fid=fopen(outfilename,"w");

            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usZ_BlockFace_x, BlockCenter_y,  BlockCenter_z);

            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   -1   0   0\n', usZ_BlockFace_x, BlockGapUpper_y,  BlockCenter_z);

            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   +1   0   0\n', usZ_BlockFace_x, BlockGapLower_y,  BlockCenter_z);

            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', clpclear_x, BlockCenter_y,  BlockCenter_z);

            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', clpclear_x, usZ_BlockFace_y,  BlockCenter_z);

            fclose(fid);
            

            fid=fopen('Request.flg',"w");
            fclose(fid);

            % Matlab waits until Q-Server is ready
            flag = 0;
            while flag == 0
                app.STATUSEditField.Value = 'Locating the lateral pole face - measurement in progress...';
                fid = fopen('Reply.txt', 'r');
                if fid ~= -1
                    str = fgetl(fid);
                    fclose(fid);
                    if ischar(str) && contains(str, 'DONE=1')
                        flag = 1;
                        disp('Process complete: DONE=1 found.');
                    else
                        pause(1); % wait for 1 second before checking again
                    end
                else
                    pause(1);
                end
            end
            delete('Reply.txt');
            pause(1);




            fid = fopen('Kugler.out', 'r');
            D = textscan(fid, '%f %f %f', 'HeaderLines', 1, 'CommentStyle', '$');
            fclose(fid);

            locateRefBlock = cell2mat(D) * 1e3;

            BlockGapUpper_y = locateRefBlock(1,2);
            BlockGapLower_y = locateRefBlock(2,2);

            BlockGap = BlockGapUpper_y - BlockGapLower_y;



            % fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', clpclear_x, usZ_BlockFace_y,  BlockCenter_z);


            fid=fopen(outfilename,"w");

            % Move to BlockCenter_z and measure x face

            fprintf(fid,'PRB %11.4f %11.4f %11.4f   -1   0   0   0\n', X_BlockFace_x, usZ_BlockFace_y,  BlockCenter_z);

            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', X_BlockFace_x - 10, usZ_BlockFace_y,  BlockCenter_z);

            fclose(fid);
            

            fid=fopen('Request.flg',"w");
            fclose(fid);

            % Update X_BlockFace_x

            % Matlab waits until Q-Server is ready
            flag = 0;
            while flag == 0
                app.STATUSEditField.Value = 'Locating the lateral pole face - measurement in progress...';
                fid = fopen('Reply.txt', 'r');
                if fid ~= -1
                    str = fgetl(fid);
                    fclose(fid);
                    if ischar(str) && contains(str, 'DONE=1')
                        flag = 1;
                        disp('Process complete: DONE=1 found.');
                    else
                        pause(1); % wait for 1 second before checking again
                    end
                else
                    pause(1);
                end
            end
            delete('Reply.txt');
            pause(1);

            fid = fopen('Kugler.out', 'r');
            str = fgetl(fid);
            str = fgetl(fid);
            fclose(fid);

            X_BlockFace_x = sscanf(str, '%f');
            X_BlockFace_x = X_BlockFace_x(1) * 1e3;

           



            

            % Five extra constants need to be defined to calculate the following:
            % usLowerJawFace_x 
            % usLowerPole_y 
            % usUpperPole_y 
            % usLateralPoleFace_x 
            % usLateralPoleFace_y 
            % They are called Delta1, Delta2, ..., Delta6

            % Use this code when Deltas need to be calculated again
            % Delta1 = -147561 * 0.5 / 1000 + 2.5 - X_BlockFace_x;
            % Delta2 = -33809 * 0.5 / 1000 - 2.5 - BlockGapLower_y;
            % Delta3 = -23415 * 0.5 / 1000 + 2.5 - BlockGapLower_y;
            % Delta4 = -59.139 - X_BlockFace_x;
            % Delta5 = -29.376 - BlockGapLower_y;
            % Delta6 = 381.05 - usZ_BlockFace_z;

            %save refBlockData X_BlockFace_x BlockGap BlockGapUpper_y BlockGapLower_y usZ_BlockFace_z Delta1 Delta2 Delta3 Delta4 Delta5 Delta6

            save refBlockData.mat X_BlockFace_x BlockGap BlockGapUpper_y BlockGapLower_y usZ_BlockFace_z

            % This deltas should be constants related to SXU. They should
            % not be calculated and saved.


            if sel == app.SXUButton
                Delta1 = 3.25050000000000e+000;
                Delta2 = -2.23950000000000e+000;
                Delta3 = 7.95750000000000e+000;
                Delta4 = 15.3920000000000e+000;
                Delta5 = -12.2110000000000e+000;
                Delta6 = -3.76678100000000e+003;

            else % sel == app.HESXUButton
                % HESXU selected

            end


            usLowerJawFace_x    = X_BlockFace_x + Delta1;
            usLowerPole_y       = BlockGapLower_y + Delta2;
            usUpperPole_y       = BlockGapLower_y + Delta3;
            usLateralPoleFace_x = X_BlockFace_x + Delta4;
            usLateralPoleFace_y = BlockGapLower_y + Delta5;
            usLateralPoleFace_z = usZ_BlockFace_z + Delta6;







            % usLowerJawFace_x = -147561 * 0.5 / 1000 + 2.5;
            % usLowerPole_y = -33809 * 0.5 / 1000 - 2.5;
            % usUpperPole_y = -23415 * 0.5 / 1000 + 2.5;
            % usLateralPoleFace_x = -59.139;
            % usLateralPoleFace_y = -29.376;
            %usLateralPoleFace_z = 381.05;

            %usLateralPoleFace_z = 379.013 + 2.5 - 0.5;
            %usLateralPoleFace_z = importdata("usLateralPoleFace_z.txt");
            

            axis_y = (usLowerPole_y + usUpperPole_y)/2; % Fix

            
            fid=fopen(outfilename,"w");

            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', X_BlockFace_x - 10,  usZ_BlockFace_y,     usLateralPoleFace_z - 10);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usLateralPoleFace_x, axis_y,              usLateralPoleFace_z - 10);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usLateralPoleFace_x, usLateralPoleFace_y, usLateralPoleFace_z - 10);
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   0   -1   0\n',usLateralPoleFace_x, usLateralPoleFace_y, usLateralPoleFace_z);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usLateralPoleFace_x, usLateralPoleFace_y, usLateralPoleFace_z - 10);

            fclose(fid);
            

            fid=fopen('Request.flg',"w");
            fclose(fid);

            app.STATUSEditField.Value = 'Dover.inp input file and Request.flg created';
            pause(5);
            app.STATUSEditField.Value = '---';
            pause(5);

            % Matlab waits until Q-Server is ready
            flag = 0;
            while flag == 0
                app.STATUSEditField.Value = 'Locating the lateral pole face - measurement in progress...';
                fid = fopen('Reply.txt', 'r');
                if fid ~= -1
                    str = fgetl(fid);
                    fclose(fid);
                    if ischar(str) && contains(str, 'DONE=1')
                        flag = 1;
                        disp('Process complete: DONE=1 found.');
                    else
                        pause(1); % wait for 1 second before checking again
                    end
                else
                    pause(1);
                end
            end
            delete('Reply.txt');
            pause(1);

            fid = fopen('Kugler.out', 'r');
            str = fgetl(fid);
            str = fgetl(fid);
            fclose(fid);

            usLateralPoleFaceCoord = sscanf(str, '%f');
            usLateralPoleFace_z = usLateralPoleFaceCoord(3) * 1e3;

            % fid = fopen('usLateralPoleFace_z.txt', 'w');
            % fprintf(fid, '%.4f', usLateralPoleFace_z);
            % fclose(fid);

            app.STATUSEditField.Value = sprintf('Lateral pole face z position: %.3f mm', usLateralPoleFace_z);
            pause(5);

            % Part 2: Locate the undulator

            app.STATUSEditField.Value = 'Beginning undulator location sequence...';
            pause(5);
            app.STATUSEditField.Value = '---';
            pause(5);

            if sel == app.SXUButton
                % SXU selected
                % SXU parameters (mm)
                Delta_lateralPoleFace_PoleFace = 1.197; % Note on pole face: The pole is more negative in z then the lateral pole face by about 1mm
                halfPeriod = 19.5;
                Delta_pole_jaw_y = 22; % This number was estimated by averaging the distance between the pole position and face position in y for upper and lower jaws
                Delta_poleFace_1stPole = 3.9; % Distance in z from the first pole face to the first pole center
                Delta_jawFace_poleCenter_x = 58;
                Delta_poleFace_LowerPole_y = 4.3185; % usLowerPole_y - (-40850 * 0.5 / 1000), Distance in y between the face pole measurement and the lower pole position. By eye, it looks about 5 mm
                margin = 3.608; % abs(usPoleFace_z - usPoleFaceEntrance_z) + 0.5, margin from pole face to move the probe rod to be capable of entering the tight space
                poleFace2poleFace = 3381.300; % Nominal

            else % sel == app.HESXUButton
                % HESXU selected
                
            end

            usPoleFace_z = usLateralPoleFace_z-Delta_lateralPoleFace_PoleFace;
            






            %%%%%%%%%%%%%%%%%%%%%%%


            fid=fopen(outfilename,"w");

            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usLowerJawFace_x + Delta_jawFace_poleCenter_x, axis_y,                                   usPoleFace_z - margin);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usLowerJawFace_x + Delta_jawFace_poleCenter_x, usLowerPole_y-Delta_poleFace_LowerPole_y, usPoleFace_z - margin);

            % US Pole Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   0   -1   0\n',usLowerJawFace_x + Delta_jawFace_poleCenter_x, usLowerPole_y-Delta_poleFace_LowerPole_y, usPoleFace_z);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n', usLowerJawFace_x + Delta_jawFace_poleCenter_x, usLowerPole_y-Delta_poleFace_LowerPole_y, usPoleFace_z - margin);

            fclose(fid);


            fid=fopen('Request.flg',"w");
            fclose(fid);

            app.STATUSEditField.Value = 'Dover.inp input file and Request.flg created';
            pause(5);
            app.STATUSEditField.Value = '---';
            pause(5);

            % Matlab waits until Q-Server is ready
            flag = 0;
            while flag == 0
                app.STATUSEditField.Value = 'Locating the lateral pole face - measurement in progress...';
                fid = fopen('Reply.txt', 'r');
                if fid ~= -1
                    str = fgetl(fid);
                    fclose(fid);
                    if ischar(str) && contains(str, 'DONE=1')
                        flag = 1;
                        disp('Process complete: DONE=1 found.');
                    else
                        pause(1); % wait for 1 second before checking again
                    end
                else
                    pause(1);
                end
            end
            delete('Reply.txt');
            pause(1);

            fid = fopen('Kugler.out', 'r');
            str = fgetl(fid);
            str = fgetl(fid);
            fclose(fid);

            usPoleFaceCoord = sscanf(str, '%f');
            usPoleFace_z = usPoleFaceCoord(3) * 1e3;

            %%%%%%%%%%%%%%%%%%%%%%%


            dsPoleFace_z = usPoleFace_z + poleFace2poleFace;


            % Approx coordinates. They correspond to absolute position of the sphere center, in mm
            ap=[usLowerJawFace_x + Delta_jawFace_poleCenter_x    usLowerPole_y-Delta_poleFace_LowerPole_y    usPoleFace_z                                           %US Pole Face
                usLowerJawFace_x                                 usLowerPole_y-Delta_pole_jaw_y              usPoleFace_z + Delta_poleFace_1stPole + 3*halfPeriod   %US Lower Jaw Face
                usLowerJawFace_x                                 usUpperPole_y+Delta_pole_jaw_y              usPoleFace_z + Delta_poleFace_1stPole + 3*halfPeriod   %US Upper Jaw Face
                usLowerJawFace_x + Delta_jawFace_poleCenter_x    usLowerPole_y                               usPoleFace_z + Delta_poleFace_1stPole + 3*halfPeriod   %US Lower Pole
                usLowerJawFace_x + Delta_jawFace_poleCenter_x    usUpperPole_y                               usPoleFace_z + Delta_poleFace_1stPole + 3*halfPeriod   %US Upper Pole
                usLowerJawFace_x + Delta_jawFace_poleCenter_x    usLowerPole_y                               usPoleFace_z + Delta_poleFace_1stPole + 170*halfPeriod %DS Lower Pole
                usLowerJawFace_x + Delta_jawFace_poleCenter_x    usUpperPole_y                               usPoleFace_z + Delta_poleFace_1stPole + 170*halfPeriod %DS Upper Pole
                usLowerJawFace_x                                 usLowerPole_y-Delta_pole_jaw_y              usPoleFace_z + Delta_poleFace_1stPole + 170*halfPeriod %DS Lower Jaw Face
                usLowerJawFace_x                                 usUpperPole_y+Delta_pole_jaw_y              usPoleFace_z + Delta_poleFace_1stPole + 170*halfPeriod %DS Lower Jaw Face
                usLowerJawFace_x + Delta_jawFace_poleCenter_x    usLowerPole_y-Delta_poleFace_LowerPole_y    dsPoleFace_z];                                         %DS Pole Face



            apOriginal = ap; %Make a copy because ap will be changed later

            clpclear_x=usLowerJawFace_x - 5; % Used the jaw face minus 5mm

            outfilename='Dover.inp';

            fid=fopen(outfilename,"w");

            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(1,1),(ap(4,2)+ap(5,2))/2,ap(1,3) - margin);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(1,1),ap(1,2),ap(1,3) - margin);

            % US Pole Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   0   -1   0\n',ap(1,1),ap(1,2),ap(1,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(1,1),ap(1,2),ap(1,3) - margin);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(1,1),(ap(4,2)+ap(5,2))/2,ap(1,3) - margin);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,(ap(4,2)+ap(5,2))/2,ap(1,3) - margin);
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(2,2),ap(2,3));

            % US Lower Jaw Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   -1   0   0   0\n',ap(2,1),ap(2,2),ap(2,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(2,2),ap(2,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(3,2),ap(3,3));

            % US Upper Jaw Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   -1   0   0   0\n',ap(3,1),ap(3,2),ap(3,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(3,2),ap(3,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(4,1),(ap(4,2)+ap(5,2))/2,ap(4,3));

            %U S Lower Pole
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  +1   0   0\n',ap(4,1),ap(4,2),ap(4,3));

            % US Upper Pole
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   -1   0   0\n',ap(4,1),ap(5,2),ap(4,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(6,1),(ap(6,2)+ap(7,2))/2,ap(6,3));

            % DS Lower Pole
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  +1   0   0\n',ap(6,1),ap(6,2),ap(6,3));

            % DS Upper Pole
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   -1   0   0\n',ap(6,1),ap(7,2),ap(6,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,(ap(6,2)+ap(7,2))/2,ap(6,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(8,2),ap(8,3));

            % DS Lower Jaw Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   -1   0   0   0\n',ap(8,1),ap(8,2),ap(8,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(8,2),ap(8,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(9,2),ap(9,3));

            % DS Upper Jaw Face
            fprintf(fid,'PRB %11.4f %11.4f %11.4f   -1   0   0   0\n',ap(9,1),ap(9,2),ap(9,3));
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,ap(9,2),ap(9,3));

            % Bring the carriage back to the US side
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,(ap(6,2)+ap(7,2))/2,300);

            %fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(10,1),(ap(6,2)+ap(7,2))/2,ap(10,3) + margin);
            %fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(10,1),ap(10,2),ap(10,3) + margin);

            % DS Pole Face
            %fprintf(fid,'PRB %11.4f %11.4f %11.4f   0   0  +1   0\n',ap(10,1),ap(10,2),ap(10,3));
            %fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',ap(10,1),ap(10,2), ap(10,3) + margin);

            

            fclose(fid);

            fid=fopen('Request.flg',"w");
            fclose(fid);

            app.STATUSEditField.Value = 'Dover.inp input file and Request.flg created';
            pause(5);
            app.STATUSEditField.Value = '---';
            pause(5);

            % Matlab waits until Q-Server is ready
            flag = 0;
            while flag == 0
                fid = fopen('Reply.txt', 'r');
                if fid ~= -1
                    str = fgetl(fid);
                    fclose(fid);
                    if ischar(str) && contains(str, 'DONE=1')
                        flag = 1;
                        disp('Process complete: DONE=1 found.');
                    else
                        pause(1); % wait for 1 second before checking again

                    end
                else
                    if isfile("Kugler.out")
                        fid = fopen('Kugler.out', 'r');
                        D = textscan(fid, '%f %f %f', 'HeaderLines', 1, 'CommentStyle', '$');
                        fclose(fid);

                        clear locateUndData;
                        locateUndData = cell2mat(D) * 1e3;
                        pointsMeas = size(locateUndData);
                        pointsMeas = pointsMeas(1);
                        pause(1);

                    end
                    if pointsMeas>0
                        app.STATUSEditField.Value = sprintf('Locating the undulator: Point #%d/9 measured', pointsMeas);
                    end
                    pause(1);
                end
            end
            delete('Reply.txt');

            if isfile("Kugler.out")
                fid = fopen('Kugler.out', 'r');
                C = textscan(fid, '%f %f %f', 'HeaderLines', 1, 'CommentStyle', '$');
                fclose(fid);

                clear ap;
                ap = cell2mat(C) * 1e3;
            end
            
            ap(pointsMeas+1, 1)=ap(1,1);
            ap(pointsMeas+1, 2)=ap(1,2);
            ap(pointsMeas+1, 3)=dsPoleFace_z;

            pointsMeas = pointsMeas+1;

            
            save measurementMatrix.mat ap apOriginal selText idStr runNum todayStr todayStrColon operator BlockGap; % Saves the measured data, the undulator type selection, the undulator SN, the run number, and today's date

            

            app.LocateundulatorButton.Enable = "on";
            app.MeasurepolesButton.Enable = "on";
            app.NominalgapmmEditField.Enable = "on";
            app.UndulatorEditField.Enable = "on";
            app.UndulatortypeButtonGroup.Enable = "on";
            app.CommentsTextArea.Enable = "on";
            app.OperatorEditField.Enable = "on";
            app.FrompoleEditField.Enable = "on";
            app.topoleEditField.Enable = "on";
            app.instepsofEditField.Enable = "on";
            app.xaxiscalButton.Enable = "on";
            app.AnalysisButton.Enable = "on";
            app.RunEditField.Enable = "on";

            if pointsMeas~=10
                app.STATUSEditField.Value = 'ERROR! Output data file has points missing!';
                error('Output data file has points missing');
            else
                app.STATUSEditField.Value = 'Pole faces, poles, and jaws have been located!';
            end

            

           





        end

        % Button pushed function: MeasurepolesButton
        function MeasurepolesButtonPushed(app, event)


            app.LocateundulatorButton.Enable = "off";
            app.MeasurepolesButton.Enable = "off";
            app.NominalgapmmEditField.Enable = "off";
            app.UndulatorEditField.Enable = "off";
            app.UndulatortypeButtonGroup.Enable = "off";
            app.CommentsTextArea.Enable = "off";
            app.OperatorEditField.Enable = "off";
            app.FrompoleEditField.Enable = "off";
            app.topoleEditField.Enable = "off";
            app.instepsofEditField.Enable = "off";
            app.xaxiscalButton.Enable = "off";
            app.AnalysisButton.Enable = "off";
            app.RunEditField.Enable = "off";

            % Parameters
            sel = app.UndulatortypeButtonGroup.SelectedObject;  % the selected radio button
            delete('Reply.txt');
            load measurementMatrix.mat

            







            questdlgText = sprintf('The existing datum reference frame file was created on %s for the %s-%s undulator (Run %d) by %s. This file is going to be used to measure the poles. Would you like to proceed?', todayStrColon, selText, idStr, runNum, operator);


            answer = questdlg(questdlgText, ...
            	'Datum reference frame', ...
            	'Yes','No', 'Yes');
            % Handle response
            switch answer
                case 'No'
                    app.STATUSEditField.Value = 'Measure poles canceled by user';
                    app.LocateundulatorButton.Enable = "on";
                    app.MeasurepolesButton.Enable = "on";
                    app.NominalgapmmEditField.Enable = "on";
                    app.UndulatorEditField.Enable = "on";
                    app.UndulatortypeButtonGroup.Enable = "on";
                    app.CommentsTextArea.Enable = "on";
                    app.OperatorEditField.Enable = "on";
                    app.FrompoleEditField.Enable = "on";
                    app.topoleEditField.Enable = "on";
                    app.instepsofEditField.Enable = "on";
                    app.xaxiscalButton.Enable = "on";
                    app.AnalysisButton.Enable = "on";
                    app.RunEditField.Enable = "on";
                    return;
            end

            % Information about Pole Measurement (should be used in the
            % report)
            runNum = app.RunEditField.Value;
            idNum = app.UndulatorEditField.Value;
            sel = app.UndulatortypeButtonGroup.SelectedObject;  % the selected radio button
            selText = sel.Text;
            operator = app.OperatorEditField.Value;
            comments = app.CommentsTextArea.Value;

            % Format today’s date as YYYY-MM-DD
            todayStrDay = datestr(datetime('now'),'yyyy-mm-dd');
            todayStrColon = datestr(datetime('now'),'yyyy-mm-dd HH:MM:SS');
            todayStrHour = datestr(datetime('now'),'HH:MM:SS');

            % Zero-pad the ID to 3 digits (if not already)
            idStr = sprintf('%03d', str2double(idNum));   % '018'

            % Build the filename (e.g.,
            % POLES_HE-SXU-017_Run1_2025-11-07_10-17-42)
            fileName = sprintf('POLES_%s-%s_Run%d_%s_%s', selText, idStr, runNum, todayStrDay, todayStrHour);

            

            cla(app.UIAxes);
            cla(app.UIAxes2);

            app.STATUSEditField.Value = 'Beginning pole-location sequence...';
            pause(5);

            clpclear_x = ap(2,1) - 5;

            %HE_undulator=0; %if it is an HE undulator this value should be 1, if it is an SXU undulator it should be 0

            Gap = app.NominalgapmmEditField.Value;

            fid=fopen('GapChange.inp',"w");
            fprintf(fid,'%.4f %.4f', Gap, 0);
            fclose(fid);

            fid=fopen('GapRequest.flg',"w");
            fclose(fid);

            Probetip_diameter=5; % mm
            xProbeDistBtwMeas=20; % mm

            midp=[mean(ap([2 3 8 9],1)), mean(ap([4 5 6 7],2)), mean(ap([1 10],3))];
            % midp is an array of 3 elements: x, y, and z
            % x is the average of x position lower/upper jaw face on US and DS plus the sphere radius
            % (Q1) Why to add the sphere radius? Pressumably (or idealy), the points
            % should be with respect to the sphere center
            % y is the average between the vertical center of US and DS pole
            yaw_l=(ap(8,1)-ap(2,1))/(ap(8,3)-ap(2,3));
            yaw_u=(ap(9,1)-ap(3,1))/(ap(9,3)-ap(3,3));
            yaw=(yaw_l+yaw_u)/2;
            pitch_l=(ap(6,2)-ap(4,2))/(ap(6,3)-ap(4,3));
            pitch_u=(ap(7,2)-ap(5,2))/(ap(7,3)-ap(5,3));
            pitch=(pitch_l+pitch_u)/2;

            TopJawYaw = yaw_u;
            BottomJawYaw = yaw_l;



            % poleloc seems to have a pole number, a z position, and a distance in x
            % from the jaw face.
            % Q2: if the midp is at the center of the undulator in z, why does it start
            % at 5.19 mm? I would expect a large negative number.
            % Answer: it is compensante later
            ynom=(Gap-Probetip_diameter)/2;
            if sel == app.HESXUButton
                poleloc=[1	5.19	66.75
                    2	30.69	66.75
                    3	57.44	66.75
                    4	85.44	66.75
                    5	113.44	66.75
                    6	141.44	66.75
                    7	169.44	66.75
                    8	197.44	66.75
                    9	225.44	66.75
                    10	253.44	66.75
                    11	281.44	66.75
                    12	309.44	66.75
                    13	337.44	66.75
                    14	365.44	66.75
                    15	393.44	66.75
                    16	421.44	66.75
                    17	449.44	66.75
                    18	477.44	66.75
                    19	505.44	66.75
                    20	533.44	66.75
                    21	561.44	66.75
                    22	589.44	66.75
                    23	617.44	66.75
                    24	645.44	66.75
                    25	673.44	66.75
                    26	701.44	66.75
                    27	729.44	66.75
                    28	757.44	66.75
                    29	785.44	66.75
                    30	813.44	66.75
                    31	841.44	66.75
                    32	869.44	66.75
                    33	897.44	66.75
                    34	925.44	66.75
                    35	953.44	66.75
                    36	981.44	66.75
                    37	1009.44	66.75
                    38	1037.44	66.75
                    39	1065.44	66.75
                    40	1093.44	66.75
                    41	1121.44	66.75
                    42	1149.44	66.75
                    43	1177.44	66.75
                    44	1205.44	66.75
                    45	1233.44	66.75
                    46	1261.44	66.75
                    47	1289.44	66.75
                    48	1317.44	66.75
                    49	1345.44	66.75
                    50	1373.44	66.75
                    51	1401.44	66.75
                    52	1429.44	66.75
                    53	1457.44	66.75
                    54	1485.44	66.75
                    55	1513.44	66.75
                    56	1541.44	66.75
                    57	1569.44	66.75
                    58	1597.44	66.75
                    59	1625.44	66.75
                    60	1653.44	66.75
                    61	1681.44	66.75
                    62	1709.44	66.75
                    63	1737.44	66.75
                    64	1765.44	66.75
                    65	1793.44	66.75
                    66	1821.44	66.75
                    67	1849.44	66.75
                    68	1877.44	66.75
                    69	1905.44	66.75
                    70	1933.44	66.75
                    71	1961.44	66.75
                    72	1989.44	66.75
                    73	2017.44	66.75
                    74	2045.44	66.75
                    75	2073.44	66.75
                    76	2101.44	66.75
                    77	2129.44	66.75
                    78	2157.44	66.75
                    79	2185.44	66.75
                    80	2213.44	66.75
                    81	2241.44	66.75
                    82	2269.44	66.75
                    83	2297.44	66.75
                    84	2325.44	66.75
                    85	2353.44	66.75
                    86	2381.44	66.75
                    87	2409.44	66.75
                    88	2437.44	66.75
                    89	2465.44	66.75
                    90	2493.44	66.75
                    91	2521.44	66.75
                    92	2549.44	66.75
                    93	2577.44	66.75
                    94	2605.44	66.75
                    95	2633.44	66.75
                    96	2661.44	66.75
                    97	2689.44	66.75
                    98	2717.44	66.75
                    99	2745.44	66.75
                    100	2773.44	66.75
                    101	2801.44	66.75
                    102	2829.44	66.75
                    103	2857.44	66.75
                    104	2885.44	66.75
                    105	2913.44	66.75
                    106	2941.44	66.75
                    107	2969.44	66.75
                    108	2997.44	66.75
                    109	3025.44	66.75
                    110	3053.44	66.75
                    111	3081.44	66.75
                    112	3109.44	66.75
                    113	3137.44	66.75
                    114	3165.44	66.75
                    115	3193.44	66.75
                    116	3221.44	66.75
                    117	3249.44	66.75
                    118	3277.44	66.75
                    119	3305.44	66.75
                    120	3333.44	66.75
                    121	3360.19	66.75
                    122	3385.69	66.75];
                    lastPoleNuMAX = 122;
            else
                poleloc=[1	3.9	58
                    2	23.4	58
                    3	42.9	58
                    4	62.4	58
                    5	81.9	58
                    6	101.4	58
                    7	120.9	58
                    8	140.4	58
                    9	159.9	58
                    10	179.4	58
                    11	198.9	58
                    12	218.4	58
                    13	237.9	58
                    14	257.4	58
                    15	276.9	58
                    16	296.4	58
                    17	315.9	58
                    18	335.4	58
                    19	354.9	58
                    20	374.4	58
                    21	393.9	58
                    22	413.4	58
                    23	432.9	58
                    24	452.4	58
                    25	471.9	58
                    26	491.4	58
                    27	510.9	58
                    28	530.4	58
                    29	549.9	58
                    30	569.4	58
                    31	588.9	58
                    32	608.4	58
                    33	627.9	58
                    34	647.4	58
                    35	666.9	58
                    36	686.4	58
                    37	705.9	58
                    38	725.4	58
                    39	744.9	58
                    40	764.4	58
                    41	783.9	58
                    42	803.4	58
                    43	822.9	58
                    44	842.4	58
                    45	861.9	58
                    46	881.4	58
                    47	900.9	58
                    48	920.4	58
                    49	939.9	58
                    50	959.4	58
                    51	978.9	58
                    52	998.4	58
                    53	1017.9	58
                    54	1037.4	58
                    55	1056.9	58
                    56	1076.4	58
                    57	1095.9	58
                    58	1115.4	58
                    59	1134.9	58
                    60	1154.4	58
                    61	1173.9	58
                    62	1193.4	58
                    63	1212.9	58
                    64	1232.4	58
                    65	1251.9	58
                    66	1271.4	58
                    67	1290.9	58
                    68	1310.4	58
                    69	1329.9	58
                    70	1349.4	58
                    71	1368.9	58
                    72	1388.4	58
                    73	1407.9	58
                    74	1427.4	58
                    75	1446.9	58
                    76	1466.4	58
                    77	1485.9	58
                    78	1505.4	58
                    79	1524.9	58
                    80	1544.4	58
                    81	1563.9	58
                    82	1583.4	58
                    83	1602.9	58
                    84	1622.4	58
                    85	1641.9	58
                    86	1661.4	58
                    87	1680.9	58
                    88	1700.4	58
                    89	1719.9	58
                    90	1739.4	58
                    91	1758.9	58
                    92	1778.4	58
                    93	1797.9	58
                    94	1817.4	58
                    95	1836.9	58
                    96	1856.4	58
                    97	1875.9	58
                    98	1895.4	58
                    99	1914.9	58
                    100	1934.4	58
                    101	1953.9	58
                    102	1973.4	58
                    103	1992.9	58
                    104	2012.4	58
                    105	2031.9	58
                    106	2051.4	58
                    107	2070.9	58
                    108	2090.4	58
                    109	2109.9	58
                    110	2129.4	58
                    111	2148.9	58
                    112	2168.4	58
                    113	2187.9	58
                    114	2207.4	58
                    115	2226.9	58
                    116	2246.4	58
                    117	2265.9	58
                    118	2285.4	58
                    119	2304.9	58
                    120	2324.4	58
                    121	2343.9	58
                    122	2363.4	58
                    123	2382.9	58
                    124	2402.4	58
                    125	2421.9	58
                    126	2441.4	58
                    127	2460.9	58
                    128	2480.4	58
                    129	2499.9	58
                    130	2519.4	58
                    131	2538.9	58
                    132	2558.4	58
                    133	2577.9	58
                    134	2597.4	58
                    135	2616.9	58
                    136	2636.4	58
                    137	2655.9	58
                    138	2675.4	58
                    139	2694.9	58
                    140	2714.4	58
                    141	2733.9	58
                    142	2753.4	58
                    143	2772.9	58
                    144	2792.4	58
                    145	2811.9	58
                    146	2831.4	58
                    147	2850.9	58
                    148	2870.4	58
                    149	2889.9	58
                    150	2909.4	58
                    151	2928.9	58
                    152	2948.4	58
                    153	2967.9	58
                    154	2987.4	58
                    155	3006.9	58
                    156	3026.4	58
                    157	3045.9	58
                    158	3065.4	58
                    159	3084.9	58
                    160	3104.4	58
                    161	3123.9	58
                    162	3143.4	58
                    163	3162.9	58
                    164	3182.4	58
                    165	3201.9	58
                    166	3221.4	58
                    167	3240.9	58
                    168	3260.4	58
                    169	3279.9	58
                    170	3299.4	58
                    171	3318.9	58
                    172	3338.4	58
                    173	3357.9	58
                    174	3377.4	58];

                    lastPoleNuMAX = 174;
            end

            poleloc_und(:,3)=poleloc(:,2)-(poleloc(end,2)+poleloc(1,2))/2;
            poleloc_und(:,1:2)=0;
            % poleloc_und creates a matrix with 3 columns. 1st and 2nd columns are
            % zerod. Third has z positions distributed symmetrically around 0 (center)

            Ru=[1 0 -yaw;
                0 1 -pitch_u;
                yaw pitch_u 1];
            Rl=[1 0 -yaw;
                0 1 -pitch_l;
                yaw pitch_l 1];

            R = [1 0 -yaw;
                0 1 -pitch;
                yaw pitch 1];

            probe_u=poleloc_und*Ru;
            probe_l=poleloc_und*Rl;

            % Matrices need to be reviews. probe_l will have the poleloc_und rotated
            % according to the undulator

            probepu=[poleloc(:,3)+probe_u(:,1)+midp(1) probe_u(:,2)+midp(2) probe_u(:,3)+midp(3)];
            probepl=[poleloc(:,3)+probe_l(:,1)+midp(1) probe_l(:,2)+midp(2) probe_l(:,3)+midp(3)];

            % probepu is the points where the probe should measure
            % For x: it takes the known distance from the jaw face to the center (66.75
            % mm for HE, 58 mm for SXU) + the rotated array probe_u + the mid point +
            % the sphere radius
            % For y: it is the rotated array probe_u + the mid point.
            % For z: as it is for y
            % probeu and probel are essentially points in the undulator axis

            clear indexPole p

            firstPoleNum = round(app.FrompoleEditField.Value);
            lastPoleNu   = round(app.topoleEditField.Value);
            poleDistIndx = round(app.instepsofEditField.Value);

            if firstPoleNum<1
                firstPoleNum = 1;
            end

            if lastPoleNu>lastPoleNuMAX;
                lastPoleNu = lastPoleNuMAX;
            end

            if poleDistIndx<1
                poleDistIndx = 1;
            end

            app.FrompoleEditField.Value = firstPoleNum;
            app.topoleEditField.Value = lastPoleNu;
            app.instepsofEditField.Value = poleDistIndx;

            %firstPoleNum = 3;
            %lastPoleNu = 170; %Max 174
            %poleDistIndx = 167;
            indexPole = [firstPoleNum : poleDistIndx : lastPoleNu];
            timePerPole = 150; % s

            for n=1:4*length(indexPole)
                p(n) = indexPole(floor((n - 1)/4) + 1);
            end

            fid=fopen('Dover.inp',"w");
            %first clearance point outside undulator at location of first pole
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,probepu(1,2),probepu(1,3));
            for i=[firstPoleNum : poleDistIndx : lastPoleNu]
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',probepu(i,1) - xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  -1   0   0\n',probepu(i,1) - xProbeDistBtwMeas/2, probepu(i,2)+Gap/2, probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   0   1   0   0\n',probepu(i,1) - xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',probepu(i,1) + xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  -1   0   0\n',probepu(i,1) + xProbeDistBtwMeas/2, probepu(i,2)+Gap/2, probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   0   1   0   0\n',probepu(i,1) + xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  +1   0   0\n',probepl(i,1) + xProbeDistBtwMeas/2, probepl(i,2)-Gap/2,probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   0   1   0   0\n',probepu(i,1) + xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',probepu(i,1) - xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
                fprintf(fid,'PRB %11.4f %11.4f %11.4f   0  +1   0   0\n',probepl(i,1) - xProbeDistBtwMeas/2, probepl(i,2)-Gap/2,probepu(i,3));
                fprintf(fid,'CLP %11.4f %11.4f %11.4f   0   1   0   0\n',probepu(i,1) - xProbeDistBtwMeas/2, probepu(i,2), probepu(i,3));
            end
            fprintf(fid,'CLP %11.4f %11.4f %11.4f   1   0   0   0\n',clpclear_x,probepu(i,2),300);
            fclose(fid);

            fid=fopen('Request.flg',"w");
            fclose(fid);

            app.STATUSEditField.Value = 'Dover.inp input file and Request.flg created';
            pause(5);


            % Matlab waits until Q-Server is ready
            flag = 0;
            while flag == 0
                fid = fopen('Reply.txt', 'r');
                if fid ~= -1
                    str = fgetl(fid);
                    fclose(fid);
                    if ischar(str) && contains(str, 'DONE=1')
                        flag = 1;
                        disp('Process complete: DONE=1 found.');
                    else
                        pause(1); % wait for 1 second before checking again

                    end
                else
                    if isfile("Kugler.out")
                        fid = fopen('Kugler.out', 'r');
                        D = textscan(fid, '%f %f %f', 'HeaderLines', 1, 'CommentStyle', '$');
                        fclose(fid);

                        clear UndPoles;
                        UndPoles = cell2mat(D) * 1e3;
                        pointsMeas = size(UndPoles);
                        pointsMeas = pointsMeas(1);
                        %pointsMeas = int32(pointsMeas);
                        if pointsMeas>0
                            y = UndPoles(:,2); % mm
                            z = UndPoles(:,3) * 1e-3; % m
                            %p(pointsMeas) = index(floor((pointsMeas - 1)/4) + 1);
                        end

                        pause(1);

                    end
                    if pointsMeas>0
                        app.STATUSEditField.Value = sprintf('%d out of %d measured poles. Measured points: %d (~ %d min. left)', floor(pointsMeas/4), length(indexPole), pointsMeas, round(timePerPole*(length(indexPole) - floor(pointsMeas/4))/60));
                        plot(app.UIAxes, p(y > midp(2)), y(y > midp(2)), 'kx', 'LineStyle', 'none');
                        plot(app.UIAxes2, p(y < midp(2)), y(y < midp(2)), 'kx', 'LineStyle', 'none');

                        % Add grid
                        grid(app.UIAxes, 'on');
                        grid(app.UIAxes2, 'on');

                        % --- Add margin automatically ---
                        % ======== FIRST AXIS ========
                        xData1 = p(y > midp(2));
                        yData1 = y(y > midp(2));

                        if ~isempty(xData1)
                            dx = range(xData1);
                            dy = range(yData1);

                            % Handle single-point or zero-range case
                            if dx == 0
                                dx = max(abs(xData1(1)), 1);
                            end
                            if dy == 0
                                dy = max(abs(yData1(1)), 1);
                            end

                            % Apply limits (using min/max for multi-point, same for single)
                            %xlim(app.UIAxes, [min(xData1) - dx, max(xData1) + dx]);
                            xlim(app.UIAxes, [firstPoleNum-1, lastPoleNu + 1]);
                            ylim(app.UIAxes, [min(yData1) - dy * 0.05, max(yData1) + dy * 0.05]);
                        end


                        % ======== SECOND AXIS ========
                        xData2 = p(y < midp(2));
                        yData2 = y(y < midp(2));

                        if ~isempty(xData2)
                            dx2 = range(xData2);
                            dy2 = range(yData2);

                            % Handle single-point or zero-range case
                            if dx2 == 0
                                dx2 = max(abs(xData2(1)), 1);
                            end
                            if dy2 == 0
                                dy2 = max(abs(yData2(1)), 1);
                            end

                            % Apply limits
                            %xlim(app.UIAxes2, [min(xData2) - dx2, max(xData2) + dx2]);
                            xlim(app.UIAxes2, [firstPoleNum-1, lastPoleNu + 1]);
                            ylim(app.UIAxes2, [min(yData2) - dy2 * 0.05, max(yData2) + dy2 * 0.05]);
                        end

                        % if ~isempty(xData1)
                        %     dx = range(xData1);
                        %     dy = range(yData1);
                        % 
                        %     % Handle single-point case (zero range)
                        %     if dx == 0
                        %         dx = abs(xData1(1)) * 0.05;  % 5% of value
                        %         if dx == 0, dx = 1; end      % fallback if x = 0
                        %     end
                        %     if dy == 0
                        %         dy = abs(yData1(1)) * 0.05;  % 5% of value
                        %         if dy == 0, dy = 1; end
                        %     end
                        % 
                        %     % Apply limits safely
                        %     xlim(app.UIAxes, [xData1(1) - dx, xData1(1) + dx]);
                        %     ylim(app.UIAxes, [yData1(1) - dy, yData1(1) + dy]);
                        % end
                    end
                    pause(1);
                end
            end
            delete('Reply.txt');
            app.STATUSEditField.Value = sprintf('Completed! %d out of %d measured poles. Measured points: %d', floor(pointsMeas/4), length(indexPole), pointsMeas);

            app.LocateundulatorButton.Enable = "on";
            app.MeasurepolesButton.Enable = "on";
            app.NominalgapmmEditField.Enable = "on";
            app.UndulatorEditField.Enable = "on";
            app.UndulatortypeButtonGroup.Enable = "on";
            app.CommentsTextArea.Enable = "on";
            app.OperatorEditField.Enable = "on";
            app.FrompoleEditField.Enable = "on";
            app.topoleEditField.Enable = "on";
            app.instepsofEditField.Enable = "on";
            app.xaxiscalButton.Enable = "on";
            app.AnalysisButton.Enable = "on";
            app.RunEditField.Enable = "on";

            % if Kugler.out exists

            fid = fopen('Kugler.out', 'r');
            C = textscan(fid, '%f %f %f', 'HeaderLines', 1, 'CommentStyle', '$');
            fclose(fid);

            clear measPoleMatrix;
            measPoleMatrix = cell2mat(C) * 1e3;

            % measPoleMatrix: R x C, with R a multiple of 4
            [nRows, ~] = size(measPoleMatrix);
            assert(mod(nRows,4)==0, 'Number of rows must be a multiple of 4.');

            % Build row indices by blocks of 4
            idx = reshape(1:nRows, 4, []);   % each column is a block of 4 rows

            % First matrix: take rows 1–2 of each block, but swap within each pair
            idxA = idx(1:2, :);
            idxA = idxA([2 1], :);           % swap within each 2-row pair
            upperPolesMeas = measPoleMatrix(idxA(:), :);  % rows: 2,1, 6,5, 10,9, ...

            % Second matrix: the remaining rows (3–4 of each block), in order
            idxB = idx(3:4, :);
            lowerPolesMeas = measPoleMatrix(idxB(:), :);  % rows: 3,4, 7,8, 11,12, ...

            upperPolesMeasOutputData(:, 3:5) = upperPolesMeas;
            lowerPolesMeasOutputData(:, 3:5) = lowerPolesMeas;

            
            for n=1:nRows/2
                if mod(n,2) == 1
                    upperPolesMeasOutputData(n,2) = 1;
                    lowerPolesMeasOutputData(n,2) = 1;
                else
                    upperPolesMeasOutputData(n,2) = 2;
                    lowerPolesMeasOutputData(n,2) = 2;
                end

                upperPolesMeasOutputData(n,1) = indexPole(ceil(n/2)); % proud
                lowerPolesMeasOutputData(n,1) = indexPole(ceil(n/2));
            end

            





            


            

            

            measPoleInfo = sprintf('%s, %s-%s undulator, Run %d, %s', todayStrColon, selText, idStr, runNum, operator);
            save measPoleInfo.mat measPoleInfo measPoleMatrix indexPole fileName upperPolesMeasOutputData lowerPolesMeasOutputData TopJawYaw BottomJawYaw todayStrColon selText idStr runNum operator comments

            runNum = runNum + 1;
            fid = fopen("runNum.txt", "w")
            fprintf(fid, "%d", runNum);
            fclose(fid);


        end

        % Button pushed function: xaxiscalButton
        function xaxiscalButtonPushed(app, event)
            % Collects calibration data for x
            figure
            plot(1:10, 1:10)
            createFig('test', app.ioFilesPath)
        end

        % Button pushed function: AnalysisButton
        function AnalysisButtonPushed(app, event)
            %clear all

            app.LocateundulatorButton.Enable = "off";
            app.MeasurepolesButton.Enable = "off";
            app.NominalgapmmEditField.Enable = "off";
            app.UndulatorEditField.Enable = "off";
            app.UndulatortypeButtonGroup.Enable = "off";
            app.CommentsTextArea.Enable = "off";
            app.OperatorEditField.Enable = "off";
            app.FrompoleEditField.Enable = "off";
            app.topoleEditField.Enable = "off";
            app.instepsofEditField.Enable = "off";
            app.xaxiscalButton.Enable = "off";
            app.AnalysisButton.Enable = "off";
            app.RunEditField.Enable = "off";
            

            cd (app.ioFilesPath)
            %load measurementMatrix.mat
            

            S = load('measurementMatrix.mat');   
            %runNum = S.runNum;
            %selText= S.selText;
            %operator= S.operator;
            todayStr= S.todayStr;
            %todayStrColon= S.todayStrColon;
            idStr= S.idStr;
            BlockGap= S.BlockGap;
            ap= S.ap;
            apOriginal= S.apOriginal;

            S = load('measPoleInfo.mat');

            fileName = S.fileName;
            measPoleMatrix = S.measPoleMatrix;
            measPoleInfo = S.measPoleInfo;
            indexPole = S.indexPole;
            % These variables should contain the output data following the same format in the Kugler bench
            upperPolesMeasOutputData = S.upperPolesMeasOutputData; 
            lowerPolesMeasOutputData = S.lowerPolesMeasOutputData;
            TopJawYaw = S.TopJawYaw;
            BottomJawYaw = S.BottomJawYaw;
            todayStrColon = S.todayStrColon;
            selText = S.selText;
            idStr = S.idStr;
            runNum = S.runNum;
            operator = S.operator;
            comments = S.comments{1};



            %data=importdata("Kugler_out5_fullUndulator.out", ' ', 1);
            data=importdata("Kugler.out", ' ', 1);
            data = data.data; % x, y, and z in m




            baseDir = 'S:\magdata\DOVER BENCH\LCLS-II\Undulator';
            pairFolder = sprintf('%s_%s', char(selText), char(idStr));
            targetPath = fullfile(baseDir, pairFolder, 'DATASET0001', 'Mechanical');

            if ~isfolder(baseDir), error('Base dir missing: %s', baseDir); end
            if ~isfolder(fileparts(targetPath)), mkdir(fileparts(targetPath)); end
            if ~isfolder(fullfile(baseDir, pairFolder)), mkdir(fullfile(baseDir, pairFolder)); end
            if ~isfolder(fullfile(baseDir, pairFolder, 'DATASET0001')), mkdir(fullfile(baseDir, pairFolder, 'DATASET0001')); end
            if ~isfolder(targetPath), mkdir(targetPath); end

            cd(targetPath);

            % Parameters
            %sphereDiam = 5e-3; %m
            poleNum1stZ = 1;
            period = 19.5e-3; %m

            indexArray=1:1:length(data);

            index = zeros(1,length(data));
            index(1:4:length(data))=1;
            index = logical(index);
            index = indexArray(index);
            posUB = data(index, :); % Saves all the x, y, z positions, in m, for a specific pole location (see Pos 1 in the figure above)

            index = zeros(1,length(data));
            index(2:4:length(data))=1;
            index = logical(index);
            index = indexArray(index);
            posUA = data(index, :); % Saves all the x, y, z positions, in m, for a specific pole location (see Pos 2 in the figure above)

            index = zeros(1,length(data));
            index(3:4:length(data))=1;
            index = logical(index);
            index = indexArray(index);
            posLA = data(index, :); % Saves all the x, y, z positions, in m, for a specific pole location (see Pos 3 in the figure above)

            index = zeros(1,length(data));
            index(4:4:length(data))=1;
            index = logical(index);
            index = indexArray(index);
            posLB = data(index, :); % Saves all the x, y, z positions, in m, for a specific pole location (see Pos 4 in the figure above)

            Z = [posUB(:,3) posUA(:,3) posLB(:,3) posLA(:,3)]';
            Z = mean(Z)';

            poleNumbers = round((Z-Z(1))/period) + poleNum1stZ;

            deltaX = posUA - posUB;
            deltaX = deltaX(:,1);
            rollU = atan((posUA(:,2) - posUB(:,2))./deltaX);
            deltaX = posLA - posLB;
            deltaX = deltaX(:,1);
            rollL = atan((posLA(:,2) - posLB(:,2))./deltaX);

            % Plots of top and bottom jaw measurements
            get(groot,'DefaultAxesXTickLabelRotation');   % likely returns 45
            set(groot,'DefaultAxesXTickLabelRotation','remove')  % clears the default

            fontsize = 14;
            z=posUB(:,3); %m
            y = 1e3*(posUB(:,2) + posUA(:,2))/2; % Average the two measurements on the same pole, in mm
            meanY_U = mean(y); % mm
            yUP_copy = y; % mm
            y0 = y - meanY_U; % mm

            p1 = polyfit(poleNumbers, y0, 1);
            yfit = polyval(p1, poleNumbers); % mm

            p2 = polyfit(z, y0, 1); % the slope p2(1) will be given in [dy0] / [dz] = mm / m = 1e-3. Therefore, a atan operation returns an angle in mrad
            slope_U = atan(p2(1)) * 1e3; % urad

            p3 = polyfit(poleNumbers, y, 1);
            top1 = polyval(p3, 1);
            top28 = polyval(p3, 28);
            top90 = polyval(p3, 90);
            topLast = polyval(p3, poleNumbers(end));

            % Create taller figure
            f1 = figure('Visible','off', 'Position',[100 0 1200 800]);  % invisible

            % ========= TOP SUBPLOT =========
            ax1 = subplot(2,1,1);
            ax1.XTickLabelRotation = 0;
            plot(ax1, poleNumbers, y0, '-b', 'LineWidth', 1); hold(ax1,'on');
            plot(ax1, poleNumbers, yfit, '--k', 'LineWidth', 1);
            xline(28, 'LineWidth',1, 'LineStyle', '-')
            xline(90, 'LineWidth',1, 'LineStyle', '-')
            xlabel(ax1, 'Pole number');
            ylabel(ax1, 'Y dev. from mean (mm)');
            set(ax1, 'FontSize', fontsize); grid(ax1,'on');

            % Title for top subplot (shifted above top x-axis)
            title(ax1, 'Top Jaw Pole Tips', 'FontSize', fontsize+2, ...
                'FontWeight','bold', 'Units','normalized', 'Position',[0.5 1.20 0]);

            % Overlay axis for z scale
            ax2 = axes('Position', ax1.Position, 'Color','none', 'XAxisLocation','top');
            ax2.YAxis.Visible = 'off';
            xlabel(ax2, 'z (m)');
            ax1.XLim = [min(poleNumbers) max(poleNumbers)];
            ax2.XLim = [min(z) max(z)];
            text(0.8, 0.2, sprintf('Mean: %+.3f mm', meanY_U), 'Units','normalized', 'FontSize',fontsize)
            text(0.8, 0.1, sprintf('Slope: %+.3f µrad', slope_U), 'Units','normalized', 'FontSize',fontsize)
            %linkaxes([ax1 ax2],'x');

            % Adjust subplot height for breathing room
            pos = ax1.Position; pos(4) = pos(4) - 0.08; ax1.Position = pos; ax2.Position = pos;

            if mean(diff(poleNumbers))>10
                ax1.XTick = poleNumbers;
            else
                ax1.XTick = 0:10:poleNumbers(end);
            end

            % ========= BOTTOM SUBPLOT =========
            z = posLB(:,3); %m

            firstBtmPolePos = z(1);
            y = 1e3*(posLB(:,2) + posLA(:,2))/2; %mm
            meanY_L = mean(y);
            yLO_copy = y;
            y0 = y - meanY_L; %mm

            p1 = polyfit(poleNumbers, y0, 1);
            yfit = polyval(p1, poleNumbers);

            p2 = polyfit(z, y0, 1); % the slope p2(1) will be given in [dy0] / [dz] = mm / m = 1e-3. Therefore, a atan operation returns an angle in mrad
            slope_L = atan(p2(1)) * 1e3; % urad

            p3 = polyfit(poleNumbers, y, 1);
            down1 = polyval(p3, 1);
            down28 = polyval(p3, 28);
            down90 = polyval(p3, 90);
            downLast = polyval(p3, poleNumbers(end));


            ax3 = subplot(2,1,2);
            ax3.XTickLabelRotation = 0;
            plot(ax3, poleNumbers, y0, '-r', 'LineWidth', 1); hold(ax3,'on');
            plot(ax3, poleNumbers, yfit, '--k', 'LineWidth', 1);
            xline(28, 'LineWidth',1, 'LineStyle', '-')
            xline(90, 'LineWidth',1, 'LineStyle', '-')
            xlabel(ax3, 'Pole number');
            ylabel(ax3, 'Y dev. from mean (mm)');
            set(ax3, 'FontSize', fontsize); grid(ax3,'on');

            % Title for bottom subplot (shifted above top x-axis)
            title(ax3, 'Bottom Jaw Pole Tips', 'FontSize', fontsize+2, ...
                'FontWeight','bold', 'Units','normalized', 'Position',[0.5 1.20 0]);

            % Overlay axis for z scale
            ax4 = axes('Position', ax3.Position, 'Color','none', 'XAxisLocation','top');
            ax4.YAxis.Visible = 'off';
            xlabel(ax4, 'z (m)');
            ax3.XLim = [min(poleNumbers) max(poleNumbers)];
            ax4.XLim = [min(z) max(z)];
            text(0.8, 0.2, sprintf('Mean: %+.3f mm', meanY_L), 'Units','normalized', 'FontSize',fontsize)
            text(0.8, 0.1, sprintf('Slope: %+.3f µrad', slope_L), 'Units','normalized', 'FontSize',fontsize)
            %linkaxes([ax3 ax4],'x');

            % Adjust subplot height
            pos = ax3.Position; pos(4) = pos(4) - 0.08; ax3.Position = pos; ax4.Position = pos;
            if mean(diff(poleNumbers))>10
                ax3.XTick = poleNumbers;
            else
                ax3.XTick = 0:10:poleNumbers(end);
            end



            createFig('Upper_Lower_Pole_Tips', targetPath)
            delete(f1);

            %Statistics of top and bottom jaw measurements
            gap = yUP_copy - yLO_copy; % mm
            meanGap = mean(gap); % mm
            minGap = min(gap); % mm

            ActualGapTaper = importdata('ActualGapTaper.txt');
            actualGap = ActualGapTaper(1);
            actualTaper = ActualGapTaper(2);


            textFontSize = 13;
            titleFontSize = 16;
            f2 = figure('Visible','off', 'Position',[100 0 1200 800]);  % invisible
            axis off   % blank canvas

            % First set of data
            nRows = 5;
            nCols = 5;

            % Title above table
            titleText = {'Top and Bottom Jaw: Regression Line Intersect Points (mm)'};
            text(0.5, 1.0, titleText, ...
                'FontSize', titleFontSize, 'FontWeight','bold', ...
                'HorizontalAlignment','center', 'Color', 'b');

            % Table content
            tableData = { 'Jaw',   'First Pole',                 'US Actuator (#28)', 'DS Actuator (#90)', 'Last Pole';
                'Top',    sprintf('%.4f', top1),        sprintf('%.4f', top28),  sprintf('%.4f', top90),  sprintf('%.4f', topLast);
                'Bottom', sprintf('%.4f', down1),       sprintf('%.4f', down28), sprintf('%.4f', down90), sprintf('%.4f', downLast);
                'Gap',   sprintf('%.4f', top1 - down1), ' ',                   ' ',                   sprintf('%.4f', topLast - downLast);
                'Taper',' ',' ',' ',sprintf('%.4f', topLast - downLast - top1 + down1);};

            % Vertical and horizontal positions (normalized units)
            yPos = linspace(0.95,0.75,nRows);   % spread rows
            xPos = linspace(0.1,0.9,nCols);   % spread columns

            % Loop over cells
            for r = 1:nRows
                for c = 1:nCols
                    if r == 1 || c == 1
                        % Bold first row OR first column
                        text(xPos(c), yPos(r), tableData{r,c}, ...
                            'FontWeight','bold','HorizontalAlignment','center', "FontSize", textFontSize)
                    else
                        text(xPos(c), yPos(r), tableData{r,c}, ...
                            'HorizontalAlignment','center', "FontSize", textFontSize)
                    end
                end
            end

            % Second set of data
            nRows = 2;
            nCols = 6;


            % Title above table
            titleText = {'Summary of Mean Values (mm and mrad)'};
            text(0.5, 0.65, titleText, ...
                'FontSize', titleFontSize, 'FontWeight','bold', ...
                'HorizontalAlignment','center', 'Color', 'b');

            % Table content
            tableData = { 'Top Jaw Poles',   'Bottom Jaw Poles',                 'Gap Values', 'Sym. Pt. Values', 'Top Jaw Roll', 'Bottom Jaw Roll';
                sprintf('%.4f', meanY_U),    sprintf('%.4f', meanY_L),        sprintf('%.4f', meanGap),  sprintf('%.4f', (meanY_U + meanY_L)/2), sprintf('%.4f', 1e3*mean(rollU)), sprintf('%.4f', 1e3*mean(rollL));};

            % Vertical and horizontal positions (normalized units)
            yPos = linspace(0.6,0.55,nRows);   % spread rows
            xPos = linspace(0.1,0.9,nCols);   % spread columns

            % Loop over cells
            for r = 1:nRows
                for c = 1:nCols
                    if r == 1
                        % Bold first row OR first column
                        text(xPos(c), yPos(r), tableData{r,c}, ...
                            'FontWeight','bold','HorizontalAlignment','center', "FontSize", textFontSize)
                    else
                        text(xPos(c), yPos(r), tableData{r,c}, ...
                            'HorizontalAlignment','center', "FontSize", textFontSize)
                    end
                end
            end


            % Third set of data
            nRows = 5;
            nCols = 2;

            % Title above table
            titleText = {'Additional Calculated Values'};
            text(0.5, 0.45, titleText, ...
                'FontSize', titleFontSize, 'FontWeight','bold', ...
                'HorizontalAlignment','center', 'Color', 'b');

            %load refBlockData.mat % To get the last measured block gap

            % Table content
            tableData = { 'Bottom Pole #1 Z Value (m)',  sprintf('%.4f', firstBtmPolePos);
                'Top Jaw Pitch (mrad)',    sprintf('%.4f', slope_L);
                'Bottom Jaw Pitch (mrad)', sprintf('%.4f', slope_U);
                'Minimum Effective Gap (mm)',   sprintf('%.4f', minGap);
                'Reference Block Gap (mm)',     sprintf('%.4f', BlockGap);};

            % Vertical and horizontal positions (normalized units)
            yPos = linspace(0.4,0.2,nRows);   % spread rows
            xPos = linspace(0.35,0.65,nCols);   % spread columns

            % Loop over cells
            for r = 1:nRows
                for c = 1:nCols
                    if c == 1
                        % Bold first row OR first column
                        text(xPos(c), yPos(r), tableData{r,c}, ...
                            'FontWeight','bold','HorizontalAlignment','center', "FontSize", textFontSize)
                    else
                        text(xPos(c), yPos(r), tableData{r,c}, ...
                            'HorizontalAlignment','center', "FontSize", textFontSize)
                    end
                end
            end

            % Fourth set of data
            nRows = 2;
            nCols = 2;

            % Title above table
            titleText = {'Gap and taper'};
            text(0.5, 0.1, titleText, ...
                'FontSize', titleFontSize, 'FontWeight','bold', ...
                'HorizontalAlignment','center', 'Color', 'b');

            % Table content
            tableData = { sprintf('Actual gap: %.4f mm', actualGap),  sprintf('Actual taper: %.4f µm', 1e3*actualTaper);
                sprintf('Nominal gap: %.4f mm', 10),  sprintf('Nominal taper: %.4f µm', 0); };

            % Vertical and horizontal positions (normalized units)
            yPos = linspace(0.05,0.00,nRows);   % spread rows
            xPos = linspace(0.35,0.65,nCols);   % spread columns

            % Loop over cells
            for r = 1:nRows
                for c = 1:nCols
                    text(xPos(c), yPos(r), tableData{r,c}, ...
                        'HorizontalAlignment','center', "FontSize", textFontSize)
                end
            end




            % Fifth set of data
            nRows = 1;
            nCols = 1;

            % Title above table
            % titleText = {'Gap and taper'};
            % text(0.5, 0.1, titleText, ...
            %     'FontSize', titleFontSize, 'FontWeight','bold', ...
            %     'HorizontalAlignment','center', 'Color', 'b');

            % Table content
            tableData = { sprintf('%s', measPoleInfo); };

            % Vertical and horizontal positions (normalized units)
            yPos = linspace(-0.07,-0.07,nRows);   % spread rows
            xPos = linspace(0.2,0.2,nCols);   % spread columns

            % Loop over cells
            for r = 1:nRows
                for c = 1:nCols
                    text(xPos(c), yPos(r), tableData{r,c}, ...
                        'HorizontalAlignment','center', "FontSize", textFontSize+2, 'FontWeight','bold')
                end
            end










            createFig('Stats', targetPath)
            delete(f2);

            

            

            



            fileName=strrep(fileName, ':', '-');


            system(sprintf('gswin64c -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=%s.pdf Upper_Lower_Pole_Tips.pdf Stats.pdf', fileName));

            delete('Stats.eps')
            delete('Stats.png')
            delete('Stats.pdf')

            delete('Upper_Lower_Pole_Tips.eps')
            delete('Upper_Lower_Pole_Tips.png')
            delete('Upper_Lower_Pole_Tips.pdf')

            app.LocateundulatorButton.Enable = "on";
            app.MeasurepolesButton.Enable = "on";
            app.NominalgapmmEditField.Enable = "on";
            app.UndulatorEditField.Enable = "on";
            app.UndulatortypeButtonGroup.Enable = "on";
            app.CommentsTextArea.Enable = "on";
            app.OperatorEditField.Enable = "on";
            app.FrompoleEditField.Enable = "on";
            app.topoleEditField.Enable = "on";
            app.instepsofEditField.Enable = "on";
            app.xaxiscalButton.Enable = "on";
            app.AnalysisButton.Enable = "on";
            app.RunEditField.Enable = "on";

            open(sprintf('%s.pdf', fileName))

            summary = struct( ...
                'TopJawPitch',      slope_U, ...
                'TopJawRoll',       1e3*mean(rollU), ...
                'TopJawYaw',        TopJawYaw, ...
                'MeanTopJaw',       meanY_U, ...
                'BottomJawPitch',   slope_L, ...
                'BottomJawRoll',    1e3*mean(rollL), ...
                'BottomJawYaw',     BottomJawYaw, ...
                'MeanBottomJaw',    meanY_L, ...
                'MeanGap',          meanGap, ...
                'MeanGapSymmetry',  (meanY_U + meanY_L)/2, ...
                'BtmPole1ZVal',     firstBtmPolePos, ...
                'RefBlockGap',      BlockGap);

            write_gap_report(strcat(fileName, '.txt'), summary, upperPolesMeasOutputData, lowerPolesMeasOutputData)

            write_gap_report_with_preamble(strcat(fileName,'_WithPreamble', '.txt'), summary, upperPolesMeasOutputData, lowerPolesMeasOutputData, todayStrColon, selText, idStr, runNum, comments, operator)



            function write_gap_report_with_preamble(filename, summary, table1, table2, todayStrColon, selText, idStr, runNum, comments, operator)
                % WRITE_GAP_REPORT  Emit a text report matching your file’s format.
                %
                % Inputs
                %   filename : char/string, path to output .txt
                %   summary  : struct with fields (numeric):
                %       TopJawPitch, TopJawRoll, TopJawYaw, MeanTopJaw, ...
                %       BottomJawPitch, BottomJawRoll, BottomJawYaw, MeanBottomJaw, ...
                %       MeanGap, MeanGapSymmetry, BtmPole1ZVal, RefBlockGap
                %   table1   : Nx5 numeric matrix with columns [Pole, PtNum, X, Y, Z]
                %   table2   : Mx5 numeric matrix with columns [Pole, PtNum, X, Y, Z]
                %
                % Notes on formatting (matched to sample):
                % - Separator lines: 58 dashes
                % - Summary values: generally 4 decimals; BTM Pole #1,Z Val has 3
                % - Table columns: right-aligned with fixed widths and 5 decimals for X/Y/Z

                fid = fopen(filename,'w');
                assert(fid>0, 'Could not open %s for writing.', filename);
                cleaner = onCleanup(@() fclose(fid));

                sep = repmat('-',1,58);
                hdr = '   Pole   Pt. Num.    X Value       Y Value       Z Value';


                fprintf(fid, 'SLAC Magnetic Measurements\n');
                fprintf(fid, 'Date/Time: ');
                fprintf(fid, todayStrColon);
                fprintf(fid, '\n');
                fprintf(fid, 'Project: LCLS-II-HE\n');
                fprintf(fid, 'Device Type: Undulator\n');
                fprintf(fid, 'Serial Number: ');
                fprintf(fid, strcat(selText, '-', idStr));
                fprintf(fid, '\n');
                fprintf(fid, sprintf('Run: %d', runNum));
                fprintf(fid, '\n')
                fprintf(fid, 'Comment: ');
                fprintf(fid, comments);
                fprintf(fid, '\n');
                fprintf(fid, 'Operator: ');
                fprintf(fid, operator);
                fprintf(fid, '\n\n\n');

                % ----- Summary Header -----
                fprintf(fid, 'Final\n');
                fprintf(fid, '%s\n', sep);
                fprintf(fid, '        ----- Summary of Calculated Values -----\n');
                fprintf(fid, '%s\n', sep);
                fprintf(fid, '\n');

                % helper for aligned "Label = value" with equals signs lined up
                colW = 18; % width of label column to match alignment
                pf  = @(label,fmt,val) fprintf(fid, ['%-' num2str(colW) 's= ' fmt '\n'], label, val);

                % ----- Summary Lines (precisions chosen to match sample) -----
                pf('Top Jaw Pitch'    ,'%.4f', summary.TopJawPitch);
                pf('Top Jaw Roll'     ,'%.4f', summary.TopJawRoll);
                pf('Top Jaw Yaw'      ,'%.4f', summary.TopJawYaw);
                pf('Mean Top Jaw'     ,'%.4f', summary.MeanTopJaw);
                pf('Bottom Jaw Pitch' ,'%.4f', summary.BottomJawPitch);
                pf('Bottom Jaw Roll'  ,'%.4f', summary.BottomJawRoll);
                pf('Bottom Jaw Yaw'   ,'%.4f', summary.BottomJawYaw);
                pf('Mean Bottom Jaw'  ,'%.4f', summary.MeanBottomJaw);
                pf('Mean Gap'         ,'%.4f', summary.MeanGap);
                pf('Mean Gap Symmetry','%.4f', summary.MeanGapSymmetry);
                pf('BTM Pole #1,Z Val','%.3f', summary.BtmPole1ZVal);  % 3 decimals
                pf('Ref. Block Gap'   ,'%.4f', summary.RefBlockGap);

                % ----- First Table -----
                fprintf(fid, '%s\n', sep);
                fprintf(fid, '%s\n', hdr);
                fprintf(fid, '%s\n', sep);

                % Column format (right-aligned widths chosen to match visual spacing)
                %   Pole:   7, PtNum: 10, X: 15.5f, Y: 14.5f, Z: 14.5f
                rowfmt = '%7d%10d%15.5f%14.5f%14.5f\n';

                write_table(fid, table1, rowfmt);

                % ----- Second Table (same header repeated) -----
                fprintf(fid, '%s\n', sep);
                fprintf(fid, '%s\n', hdr);
                fprintf(fid, '%s\n', sep);

                write_table(fid, table2, rowfmt);
            end




            function write_gap_report(filename, summary, table1, table2)
                % WRITE_GAP_REPORT  Emit a text report matching your file’s format.
                %
                % Inputs
                %   filename : char/string, path to output .txt
                %   summary  : struct with fields (numeric):
                %       TopJawPitch, TopJawRoll, TopJawYaw, MeanTopJaw, ...
                %       BottomJawPitch, BottomJawRoll, BottomJawYaw, MeanBottomJaw, ...
                %       MeanGap, MeanGapSymmetry, BtmPole1ZVal, RefBlockGap
                %   table1   : Nx5 numeric matrix with columns [Pole, PtNum, X, Y, Z]
                %   table2   : Mx5 numeric matrix with columns [Pole, PtNum, X, Y, Z]
                %
                % Notes on formatting (matched to sample):
                % - Separator lines: 58 dashes
                % - Summary values: generally 4 decimals; BTM Pole #1,Z Val has 3
                % - Table columns: right-aligned with fixed widths and 5 decimals for X/Y/Z

                fid = fopen(filename,'w');
                assert(fid>0, 'Could not open %s for writing.', filename);
                cleaner = onCleanup(@() fclose(fid));

                sep = repmat('-',1,58);
                hdr = '   Pole   Pt. Num.    X Value       Y Value       Z Value';

                % ----- Summary Header -----
                fprintf(fid, 'Final\n');
                fprintf(fid, '%s\n', sep);
                fprintf(fid, '        ----- Summary of Calculated Values -----\n');
                fprintf(fid, '%s\n', sep);
                fprintf(fid, '\n');

                % helper for aligned "Label = value" with equals signs lined up
                colW = 18; % width of label column to match alignment
                pf  = @(label,fmt,val) fprintf(fid, ['%-' num2str(colW) 's= ' fmt '\n'], label, val);

                % ----- Summary Lines (precisions chosen to match sample) -----
                pf('Top Jaw Pitch'    ,'%.4f', summary.TopJawPitch);
                pf('Top Jaw Roll'     ,'%.4f', summary.TopJawRoll);
                pf('Top Jaw Yaw'      ,'%.4f', summary.TopJawYaw);
                pf('Mean Top Jaw'     ,'%.4f', summary.MeanTopJaw);
                pf('Bottom Jaw Pitch' ,'%.4f', summary.BottomJawPitch);
                pf('Bottom Jaw Roll'  ,'%.4f', summary.BottomJawRoll);
                pf('Bottom Jaw Yaw'   ,'%.4f', summary.BottomJawYaw);
                pf('Mean Bottom Jaw'  ,'%.4f', summary.MeanBottomJaw);
                pf('Mean Gap'         ,'%.4f', summary.MeanGap);
                pf('Mean Gap Symmetry','%.4f', summary.MeanGapSymmetry);
                pf('BTM Pole #1,Z Val','%.3f', summary.BtmPole1ZVal);  % 3 decimals
                pf('Ref. Block Gap'   ,'%.4f', summary.RefBlockGap);

                % ----- First Table -----
                fprintf(fid, '%s\n', sep);
                fprintf(fid, '%s\n', hdr);
                fprintf(fid, '%s\n', sep);

                % Column format (right-aligned widths chosen to match visual spacing)
                %   Pole:   7, PtNum: 10, X: 15.5f, Y: 14.5f, Z: 14.5f
                rowfmt = '%7d%10d%15.5f%14.5f%14.5f\n';

                write_table(fid, table1, rowfmt);

                % ----- Second Table (same header repeated) -----
                fprintf(fid, '%s\n', sep);
                fprintf(fid, '%s\n', hdr);
                fprintf(fid, '%s\n', sep);

                write_table(fid, table2, rowfmt);
            end

            function write_table(fid, T, rowfmt)
                % Expects T as [Pole, PtNum, X, Y, Z]
                validateattributes(T, {'numeric'}, {'ncols',5});
                for i = 1:size(T,1)
                    fprintf(fid, rowfmt, T(i,1), T(i,2), T(i,3), T(i,4), T(i,5));
                end
            end







            function createFig(fileName, figDir)
                % createFig saves the current figure in PNG, PDF, and EPS formats.
                %
                % Usage:
                %   createFig(fileName)
                %
                % Description:
                %   The createFig function saves the current figure in three formats: PNG, PDF,
                %   and EPS, with high resolution (300 dpi). The function prompts the user to
                %   choose a directory to save the figure. If the user does not select a
                %   directory, the function displays a message and does not save the figure.
                %
                % Input:
                %   fileName (string) - Name of the file (without extension) under which
                %   the figure will be saved in the chosen directory.
                %
                % Example:
                %   % Assuming a figure is already open in MATLAB
                %   createFig('MyFigure')
                %
                % Note:
                %   Ensure that the figure you wish to save is the active figure when calling
                %   createFig. This function uses a 300 dpi resolution for high-quality output.


                % Johann E. Baader (12.11.2024)

                % % Prompt the user to select a directory for saving the figure
                % figDir = uigetdir(pwd, 'Select a directory to save the figure');
                %figDir = 'S:\magdata\LCLS-II-HE\Dover bench touch probe IO files';
                %
                % % Check if the user selected a valid directory, if not, return
                % if figDir == 0
                %     disp('No directory selected. Figure not saved.');
                %     return;
                % end

                % Get the handle of the current figure
                h = gcf;

                % Set figure properties for saving
                set(h, 'PaperOrientation', 'portrait');
                set(h, 'Units', 'Inches');
                pos = get(h, 'Position');
                set(h, 'PaperPositionMode', 'Auto', 'PaperUnits', 'Inches', 'PaperSize', [pos(3), pos(4)]);

                % Save the figure as PNG
                pngFile = fullfile(figDir, [fileName, '.png']);
                print(h, pngFile, '-dpng', '-r300');

                % Save the figure as PDF
                pdfFile = fullfile(figDir, [fileName, '.pdf']);
                print(h, pdfFile, '-dpdf', '-r300');

                % Save the figure as EPS
                epsFile = fullfile(figDir, [fileName, '.eps']);
                print(h, epsFile, '-depsc', '-r300');

                %disp(['Figure saved to ', figDir]);
            end





            % If measurement is done and Dover.out exists, execute
            % calculations. Otherwise, inform the user that the proper
            % files do not exist.
        end
    end

    % Component initialization
    methods (Access = private)

        % Create UIFigure and components
        function createComponents(app)

            % Get the file path for locating images
            pathToMLAPP = fileparts(mfilename('fullpath'));

            % Create UIFigure and hide until all components are created
            app.UIFigure = uifigure('Visible', 'off');
            app.UIFigure.Color = [0.549 0.0784 0.0784];
            app.UIFigure.Position = [100 40 640 858];
            app.UIFigure.Name = 'MATLAB App';

            % Create UIAxes
            app.UIAxes = uiaxes(app.UIFigure);
            xlabel(app.UIAxes, 'Pole #')
            ylabel(app.UIAxes, 'y (mm)')
            zlabel(app.UIAxes, 'Z')
            app.UIAxes.XColor = [1 1 1];
            app.UIAxes.YColor = [1 1 1];
            app.UIAxes.ZColor = [1 1 1];
            app.UIAxes.Position = [35 232 578 185];

            % Create UIAxes2
            app.UIAxes2 = uiaxes(app.UIFigure);
            xlabel(app.UIAxes2, 'Pole #')
            ylabel(app.UIAxes2, 'y (mm)')
            app.UIAxes2.XColor = [1 1 1];
            app.UIAxes2.YColor = [1 1 1];
            app.UIAxes2.Position = [35 10 578 185];

            % Create LocateundulatorButton
            app.LocateundulatorButton = uibutton(app.UIFigure, 'push');
            app.LocateundulatorButton.ButtonPushedFcn = createCallbackFcn(app, @LocateundulatorButtonPushed, true);
            app.LocateundulatorButton.BackgroundColor = [1 1 1];
            app.LocateundulatorButton.FontSize = 24;
            app.LocateundulatorButton.Position = [287 717 202 45];
            app.LocateundulatorButton.Text = 'Locate undulator';

            % Create UndulatortypeButtonGroup
            app.UndulatortypeButtonGroup = uibuttongroup(app.UIFigure);
            app.UndulatortypeButtonGroup.Title = 'Undulator type';
            app.UndulatortypeButtonGroup.Position = [23 559 100 70];

            % Create HESXUButton
            app.HESXUButton = uiradiobutton(app.UndulatortypeButtonGroup);
            app.HESXUButton.Text = 'HE-SXU';
            app.HESXUButton.Position = [11 24 67 22];
            app.HESXUButton.Value = true;

            % Create SXUButton
            app.SXUButton = uiradiobutton(app.UndulatortypeButtonGroup);
            app.SXUButton.Text = 'SXU';
            app.SXUButton.Position = [11 2 65 22];

            % Create MeasurepolesButton
            app.MeasurepolesButton = uibutton(app.UIFigure, 'push');
            app.MeasurepolesButton.ButtonPushedFcn = createCallbackFcn(app, @MeasurepolesButtonPushed, true);
            app.MeasurepolesButton.BackgroundColor = [1 1 1];
            app.MeasurepolesButton.FontSize = 36;
            app.MeasurepolesButton.FontWeight = 'bold';
            app.MeasurepolesButton.Position = [287 625 325 83];
            app.MeasurepolesButton.Text = 'Measure poles';

            % Create UndulatorEditFieldLabel
            app.UndulatorEditFieldLabel = uilabel(app.UIFigure);
            app.UndulatorEditFieldLabel.HorizontalAlignment = 'right';
            app.UndulatorEditFieldLabel.FontColor = [1 1 1];
            app.UndulatorEditFieldLabel.Position = [62 677 57 22];
            app.UndulatorEditFieldLabel.Text = 'Undulator';

            % Create UndulatorEditField
            app.UndulatorEditField = uieditfield(app.UIFigure, 'text');
            app.UndulatorEditField.CharacterLimits = [0 3];
            app.UndulatorEditField.HorizontalAlignment = 'right';
            app.UndulatorEditField.Position = [134 677 93 22];
            app.UndulatorEditField.Value = '017';

            % Create NominalgapmmEditFieldLabel
            app.NominalgapmmEditFieldLabel = uilabel(app.UIFigure);
            app.NominalgapmmEditFieldLabel.HorizontalAlignment = 'right';
            app.NominalgapmmEditFieldLabel.FontColor = [1 1 1];
            app.NominalgapmmEditFieldLabel.Position = [16 740 104 22];
            app.NominalgapmmEditFieldLabel.Text = 'Nominal gap (mm)';

            % Create NominalgapmmEditField
            app.NominalgapmmEditField = uieditfield(app.UIFigure, 'numeric');
            app.NominalgapmmEditField.ValueDisplayFormat = '%.4f';
            app.NominalgapmmEditField.FontColor = [0.149 0.149 0.149];
            app.NominalgapmmEditField.Placeholder = '10.0000';
            app.NominalgapmmEditField.Position = [135 740 92 22];
            app.NominalgapmmEditField.Value = 10;

            % Create CommentsTextAreaLabel
            app.CommentsTextAreaLabel = uilabel(app.UIFigure);
            app.CommentsTextAreaLabel.HorizontalAlignment = 'right';
            app.CommentsTextAreaLabel.FontColor = [1 1 1];
            app.CommentsTextAreaLabel.Position = [135 618 63 22];
            app.CommentsTextAreaLabel.Text = 'Comments';

            % Create CommentsTextArea
            app.CommentsTextArea = uitextarea(app.UIFigure);
            app.CommentsTextArea.Position = [135 559 93 60];

            % Create STATUSEditFieldLabel
            app.STATUSEditFieldLabel = uilabel(app.UIFigure);
            app.STATUSEditFieldLabel.HorizontalAlignment = 'center';
            app.STATUSEditFieldLabel.FontSize = 18;
            app.STATUSEditFieldLabel.FontWeight = 'bold';
            app.STATUSEditFieldLabel.FontColor = [0 1 0];
            app.STATUSEditFieldLabel.Position = [40 488 578 23];
            app.STATUSEditFieldLabel.Text = 'STATUS';

            % Create STATUSEditField
            app.STATUSEditField = uieditfield(app.UIFigure, 'text');
            app.STATUSEditField.Editable = 'off';
            app.STATUSEditField.FontSize = 18;
            app.STATUSEditField.FontColor = [0.149 0.149 0.149];
            app.STATUSEditField.Position = [40 457 578 27];

            % Create PrecisionUndulatorLocationSystemEvaluationPULSELabel
            app.PrecisionUndulatorLocationSystemEvaluationPULSELabel = uilabel(app.UIFigure);
            app.PrecisionUndulatorLocationSystemEvaluationPULSELabel.HorizontalAlignment = 'center';
            app.PrecisionUndulatorLocationSystemEvaluationPULSELabel.FontName = 'Copperplate Gothic Bold';
            app.PrecisionUndulatorLocationSystemEvaluationPULSELabel.FontSize = 24;
            app.PrecisionUndulatorLocationSystemEvaluationPULSELabel.FontWeight = 'bold';
            app.PrecisionUndulatorLocationSystemEvaluationPULSELabel.FontColor = [1 1 1];
            app.PrecisionUndulatorLocationSystemEvaluationPULSELabel.Position = [12 789 623 64];
            app.PrecisionUndulatorLocationSystemEvaluationPULSELabel.Text = {'Precision Undulator Location & System Evaluation '; '- PULSE -'};

            % Create UpperJawLabel
            app.UpperJawLabel = uilabel(app.UIFigure);
            app.UpperJawLabel.HorizontalAlignment = 'center';
            app.UpperJawLabel.FontSize = 14;
            app.UpperJawLabel.FontWeight = 'bold';
            app.UpperJawLabel.FontColor = [1 1 1];
            app.UpperJawLabel.Position = [4 414 632 22];
            app.UpperJawLabel.Text = 'Upper Jaw';

            % Create LowerJawLabel
            app.LowerJawLabel = uilabel(app.UIFigure);
            app.LowerJawLabel.HorizontalAlignment = 'center';
            app.LowerJawLabel.FontSize = 14;
            app.LowerJawLabel.FontWeight = 'bold';
            app.LowerJawLabel.FontColor = [1 1 1];
            app.LowerJawLabel.Position = [4 189 632 22];
            app.LowerJawLabel.Text = 'Lower Jaw';

            % Create OperatorEditFieldLabel
            app.OperatorEditFieldLabel = uilabel(app.UIFigure);
            app.OperatorEditFieldLabel.HorizontalAlignment = 'right';
            app.OperatorEditFieldLabel.FontColor = [1 1 1];
            app.OperatorEditFieldLabel.Position = [66 708 52 22];
            app.OperatorEditFieldLabel.Text = 'Operator';

            % Create OperatorEditField
            app.OperatorEditField = uieditfield(app.UIFigure, 'text');
            app.OperatorEditField.HorizontalAlignment = 'right';
            app.OperatorEditField.FontColor = [0.149 0.149 0.149];
            app.OperatorEditField.Position = [135 708 92 22];
            app.OperatorEditField.Value = 'JB';

            % Create FrompoleEditFieldLabel
            app.FrompoleEditFieldLabel = uilabel(app.UIFigure);
            app.FrompoleEditFieldLabel.HorizontalAlignment = 'right';
            app.FrompoleEditFieldLabel.FontAngle = 'italic';
            app.FrompoleEditFieldLabel.FontColor = [1 1 1];
            app.FrompoleEditFieldLabel.Position = [308 594 59 22];
            app.FrompoleEditFieldLabel.Text = 'From pole';

            % Create FrompoleEditField
            app.FrompoleEditField = uieditfield(app.UIFigure, 'numeric');
            app.FrompoleEditField.HorizontalAlignment = 'center';
            app.FrompoleEditField.FontAngle = 'italic';
            app.FrompoleEditField.Position = [375 594 30 22];
            app.FrompoleEditField.Value = 3;

            % Create topoleEditFieldLabel
            app.topoleEditFieldLabel = uilabel(app.UIFigure);
            app.topoleEditFieldLabel.HorizontalAlignment = 'right';
            app.topoleEditFieldLabel.FontAngle = 'italic';
            app.topoleEditFieldLabel.FontColor = [1 1 1];
            app.topoleEditFieldLabel.Position = [405 594 41 22];
            app.topoleEditFieldLabel.Text = 'to pole';

            % Create topoleEditField
            app.topoleEditField = uieditfield(app.UIFigure, 'numeric');
            app.topoleEditField.HorizontalAlignment = 'center';
            app.topoleEditField.FontAngle = 'italic';
            app.topoleEditField.Position = [452 594 30 22];
            app.topoleEditField.Value = 174;

            % Create instepsofEditFieldLabel
            app.instepsofEditFieldLabel = uilabel(app.UIFigure);
            app.instepsofEditFieldLabel.HorizontalAlignment = 'right';
            app.instepsofEditFieldLabel.FontAngle = 'italic';
            app.instepsofEditFieldLabel.FontColor = [1 1 1];
            app.instepsofEditFieldLabel.Position = [482 594 61 22];
            app.instepsofEditFieldLabel.Text = 'in steps of';

            % Create instepsofEditField
            app.instepsofEditField = uieditfield(app.UIFigure, 'numeric');
            app.instepsofEditField.HorizontalAlignment = 'center';
            app.instepsofEditField.FontAngle = 'italic';
            app.instepsofEditField.Position = [550 594 30 22];
            app.instepsofEditField.Value = 2;

            % Create xaxiscalButton
            app.xaxiscalButton = uibutton(app.UIFigure, 'push');
            app.xaxiscalButton.ButtonPushedFcn = createCallbackFcn(app, @xaxiscalButtonPushed, true);
            app.xaxiscalButton.BackgroundColor = [1 1 1];
            app.xaxiscalButton.FontSize = 18;
            app.xaxiscalButton.Position = [516 718 97 44];
            app.xaxiscalButton.Text = 'x-axis cal.';

            % Create AnalysisButton
            app.AnalysisButton = uibutton(app.UIFigure, 'push');
            app.AnalysisButton.ButtonPushedFcn = createCallbackFcn(app, @AnalysisButtonPushed, true);
            app.AnalysisButton.Icon = fullfile(pathToMLAPP, 'icon.png');
            app.AnalysisButton.BackgroundColor = [1 1 1];
            app.AnalysisButton.FontName = 'Century';
            app.AnalysisButton.FontSize = 14;
            app.AnalysisButton.FontWeight = 'bold';
            app.AnalysisButton.Position = [518 552 97 33];
            app.AnalysisButton.Text = 'Analysis';

            % Create RunEditFieldLabel
            app.RunEditFieldLabel = uilabel(app.UIFigure);
            app.RunEditFieldLabel.HorizontalAlignment = 'right';
            app.RunEditFieldLabel.FontColor = [1 1 1];
            app.RunEditFieldLabel.Position = [93 647 27 22];
            app.RunEditFieldLabel.Text = 'Run';

            % Create RunEditField
            app.RunEditField = uieditfield(app.UIFigure, 'numeric');
            app.RunEditField.ValueDisplayFormat = '%.d';
            app.RunEditField.FontColor = [0.149 0.149 0.149];
            app.RunEditField.Placeholder = '10.0000';
            app.RunEditField.Position = [135 647 92 22];
            app.RunEditField.Value = 1;

            % Show the figure after all components are created
            app.UIFigure.Visible = 'on';
        end
    end

    % App creation and deletion
    methods (Access = public)

        % Construct app
        function app = PULSE

            % Create UIFigure and components
            createComponents(app)

            % Register the app with App Designer
            registerApp(app, app.UIFigure)

            % Execute the startup function
            runStartupFcn(app, @startupFcn)

            if nargout == 0
                clear app
            end
        end

        % Code that executes before app deletion
        function delete(app)

            % Delete UIFigure when app is deleted
            delete(app.UIFigure)
        end
    end
end