%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Copyright 2014 National Renewable Energy Laboratory and National
% Technology & Engineering Solutions of Sandia, LLC (NTESS).
% Under the terms of Contract DE-NA0003525 with NTESS,
% the U.S. Government retains certain rights in this software.
%
% Licensed under the Apache License, Version 2.0 (the "License");
% you may not use this file except in compliance with the License.
% You may obtain a copy of the License at
%
% http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS,
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing permissions and
% limitations under the License.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

classdef responseClass<handle
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % The  ``responseClass`` creates an ``output`` object saved to the MATLAB workspace
    % that contains structures for each instance of a WEC-Sim class (e.g.
    % ``waveClass``, ``bodyClass``, ``constraintClass``, ``ptoClass``,
    % ``cableClass``, ``mooringClass``, etc).
    %
    %.. autoattribute:: objects.responseClass.responseClass
    %
    %.. autoattribute:: objects.responseClass.wave
    %
    %   * ``type`` (`string`) = 'waveType'
    %   * ``time`` (`array`) = [# of time-steps x 1]
    %   * ``elevation`` (`array`) = [# of time-steps x 1]
    %   * ``waveGauge1Elevation`` (`array`) = [# of time-steps x 1] Wave elevation at the location of wave gauge 1
    %   * ``waveGauge2Elevation`` (`array`) = [# of time-steps x 1] Wave elevation at the location of wave gauge 2
    %   * ``waveGauge3Elevation`` (`array`) = [# of time-steps x 1] Wave elevation at the location of wave gauge 3
    %
    %.. autoattribute:: objects.responseClass.bodies
    %
    %   * ``name`` (`string`) = 'bodyName'
    %   * ``time`` (`array`) = [# of time-steps x 1]
    %   * ``position`` (`array`) = [# of time-steps x 6]
    %   * ``velocity`` (`array`) = [# of time-steps x 6]
    %   * ``acceleration`` (`array`) = [# of time-steps x 6]
    %   * ``forceTotal`` (`array`) = [# of time-steps x 6] The sum of all hydrodynamic forces applied to the body
    %   * ``forceExcitation`` (`array`) = [# of time-steps x 6] The sum of the Froude-Krylov excitation force and the mean drift force exerted by the incoming wave on the body
    %   * ``forceRadiationDamping`` (`array`) = [# of time-steps x 6] The negative radiation damping force due to body velocity
    %   * ``forceAddedMass`` (`array`) = [# of time-steps x 6] The negative added mass force due to body acceleration
    %   * ``forceRestoring`` (`array`) = [# of time-steps x 6] The negative sum of the gravity force, buoyant force, the hydrostatic stiffness force, and any moment due to separation between the center of gravity and the center of buoyancy
    %   * ``forceMorisonAndViscous`` (`array`) = [# of time-steps x 6] The negative sum of the Morison element force and the viscous drag force
    %   * ``forceLinearDamping`` (`array`) = [# of time-steps x 6] The negative force due to linear damping and the body velocity
    %
    %   There are 4 additional ``output.bodies`` arrays when using nonlinear hydro and Paraview output:
    %
    %   * ``cellPressures_time`` (`array`) = [# of Paraview time-steps x 1] Nonlinear calculation timeseries
    %   * ``cellPressures_hydrostatic`` (`array`) = [# of Paraview time-steps x # of mesh faces] Hydrostatic pressure on each stl facet
    %   * ``cellPressures_waveLinear`` (`array`) = [# of Paraview time-steps x # of mesh faces] Excitation pressure on each stl facet given zero displacement and the mean free surface
    %   * ``cellPressures_waveNonLinear`` (`array`) = [# of Paraview time-steps x # of mesh faces] Excitation pressure on each stl facet given the instantaneous displacement and instantaneous free surface
    %
    %.. autoattribute:: objects.responseClass.constraints
    %
    %   * ``name`` (`string`) = 'constraintName'
    %   * ``time`` (`array`) = [# of time-steps x 1]
    %   * ``position`` (`array`) = [# of time-steps x 6] The constraint position relative to the initial condition
    %   * ``velocity`` (`array`) = [# of time-steps x 6] The constraint velocity relative to the initial condition
    %   * ``acceleration`` (`array`) = [# of time-steps x 6] The constraint acceleration relative to the initial condition
    %   * ``forceConstraint`` (`array`) = [# of time-steps x 6] The force required to resist motion in the restricted DOFs
    %
    %.. autoattribute:: objects.responseClass.ptos
    %
    %   * ``name`` (`string`) = 'ptoName'
    %   * ``time`` (`array`) = [# of time-steps x 1]
    %   * ``position`` (`array`) = [# of time-steps x 6] The constraint position relative to the initial condition
    %   * ``velocity`` (`array`) = [# of time-steps x 6] The constraint velocity relative to the initial condition
    %   * ``acceleration`` (`array`) = [# of time-steps x 6] The constraint acceleration relative to the initial condition
    %   * ``forceTotal`` (`array`) = [# of time-steps x 6] The sum of the actuation, constraint and internal mechanics forces
    %   * ``forceActuation`` (`array`) = [# of time-steps x 6] The prescribed force input to the PTO to control its motion
    %   * ``forceConstraint`` (`array`) = [# of time-steps x 6] The force required to resist motion in the restricted DOFs
    %   * ``forceInternalMechanics`` (`array`) = [# of time-steps x 6] The net force in the joint DOF due to stiffness and damping
    %   * ``powerInternalMechanics`` (`array`) = [# of time-steps x 6] The net power lost in the joint DOF due to stiffness and damping
    %
    %.. autoattribute:: objects.responseClass.cables
    %
    %   * ``name`` (`string`) = 'cableName'
    %   * ``time`` (`array`) = [# of time-steps x 1]
    %   * ``position`` (`array`) = [# of time-steps x 6]
    %   * ``velocity`` (`array`) = [# of time-steps x 6]
    %   * ``acceleration`` (`array`) = [# of time-steps x 6]
    %   * ``forceTotal`` (`array`) = [# of time-steps x 6] The sum of the actuation and constraint forces
    %   * ``forceActuation`` (`array`) = [# of time-steps x 6] The cable tension
    %   * ``forceConstraint`` (`array`) = [# of time-steps x 6] The force required to resist motion in the restricted DOFs
    %
    %.. autoattribute:: objects.responseClass.mooring
    %
    %   * ``position`` (`array`) = [# of time-steps x 6]
    %   * ``velocity`` (`array`) = [# of time-steps x 6]
    %   * ``forceMooring`` (`array`) = [# of time-steps x 6] The sum of the stiffness, damping and pretension forces applied on the body by the mooring
    %
    %.. autoattribute:: objects.responseClass.moorDyn
    %
    %   * ``Lines`` (`struct`) = [1 x 1] Contains the time and fairlead tensions
    %   * ``Line#`` (`struct`) = [1 x 1] One structure for each mooring line: Line1, Line2, etc. Each line structure contains node positions in x, y, z and segment tensions
    %
    %.. autoattribute:: objects.responseClass.ptosim
    %
    %   * ``time`` (`struct`) = [# of time-steps x 1] Simulation timeseries
    %
    %   There are additional ``output.ptosim`` structs corresponding to the Simulink blocks used:
    %
    %   * ``pistonCF`` (`struct`) = [1 x # of pistons] Structure containing timeseries of compressible fluid piston properties including absolute power, force, position, velocity
    %   * ``pistonNCF`` (`array`) = [1 x # of pistons] Structure containing timeseries of non-compressible fluid piston properties including absolute power, force, top pressure and bottom pressure
    %   * ``checkValve`` (`struct`) = [1 x # of valves] Structure containing timeseries of check valve properies including volume flow rate
    %   * ``valve`` (`struct`) = [1 x # of valves] Structure containing timeseries of valve properties including volume flow rate
    %   * ``accumulator`` (`struct`) = [1 x # of accumulators] Structure containing timeseries of accumulator properties including pressure and volume
    %   * ``hydraulicMotor`` (`struct`) = [1 x # of motors] Structure containing timeseries of hydraulic motor properties including angular velocity and volume flow rate
    %   * ``rotaryGenerator`` (`struct`) = [1 x # of generators] Structure containing timeseries of rotary generator properties including electrical power and generated power
    %   * ``pmLinearGenerator`` (`struct`) = [1 x # of generators] Structure containing timeseries of permanent magnet linear generator properties including absolute power, force, friction force, current, voltage, velocity and electrical power
    %   * ``pmRotaryGenerator`` (`struct`) = [1 x # of generators] Structure containing timeseries of permanent magnet rotary generator properties including absolute power, force, friction force, current, voltage, velocity and electrical power
    %   * ``motionMechanism`` (`struct`) = [1 x # of mechanisms] Structure containing timeseries of motion mechanism properties including PTO torque, angular position and angular velocity
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    properties (SetAccess = 'public', GetAccess = 'public')
        bodies              = struct()     % This property contains a structure for each instance of the ``bodyClass`` (i.e. for each Body block)
        cables              = struct()     % This property contains a structure for each instance of the ``cableClass`` (i.e. for each Cable block)
        constraints         = struct()     % This property contains a structure for each instance of the ``constraintClass`` (i.e. for each Constraint block). Constraint motion is relative from frame F to frame B. Constraint forces act on frame F.
        moorDyn             = struct()     % This property contains a structure for each instance of the ``mooringClass`` using MoorDyn (i.e. for each MoorDyn block)
        mooring             = struct()     % This property contains a structure for each instance of the ``mooringClass`` using the mooring matrix (i.e. for each MooringMatrix block)
        ptos                = struct()     % This property contains a structure for each instance of the ``ptoClass`` (i.e. for each PTO block). PTO motion is relative from frame F to frame B. PTO forces act on frame F.
        ptosim              = struct()     % This property contains a structure for each instance of the ``ptoSimClass`` (i.e. for each PTO-Sim block).
        wave                = struct()     % This property contains a structure for each instance of the ``waveClass``
    end

    methods (Access = 'public')
        function obj = responseClass(bodiesOutput,ptosOutput,constraintsOutput,ptosimOutput,cablesOutput,mooringOutput,waveOutput)
            % This method initializes the ``responseClass``, reads
            % output from each instance of a WEC-Sim class (e.g.
            % ``waveClass``, ``bodyClass``, ``ptoClass``, ``mooringClass``, etc)
            % , and saves the response to an ``output`` object.
            %
            % Returns
            % ------------
            %     output : obj
            %         responseClass object
            %

            % Wave
            obj.wave.type = waveOutput.type;
            obj.wave.time = waveOutput.waveAmpTime(:,1);
            obj.wave.elevation = waveOutput.waveAmpTime(:,2);

            % Bodies
            signals = {'position','velocity','acceleration','forceTotal','forceExcitation','forceRadiationDamping','forceAddedMass','forceRestoring','forceMorisonAndViscous','forceLinearDamping'};
            for ii = 1:length(bodiesOutput)
                obj.bodies(ii).name = bodiesOutput(ii).name;
                obj.bodies(ii).time = bodiesOutput(ii).time;
                obj.bodies(ii).centerGravity   = bodiesOutput(ii).centerGravity;
                for jj = 1:length(signals)
                    obj.bodies(ii).(signals{jj}) = bodiesOutput(ii).signals.values(:, (jj-1)*6+1:(jj-1)*6+6);
                end
                if(bodiesOutput(ii).yaw==1)
                    for t = 1:length(obj.wave.time)
                        % convert kinematic data from global frame to local frame (for use with yaw when yaw displacements may be large).
                        rotMatYaw = eulXYZ2RotMat(0, 0, obj.bodies(ii).position(t,6));
                        rotMatGlobal = eulXYZ2RotMat(obj.bodies(ii).position(t,4), obj.bodies(ii).position(t,5), obj.bodies(ii).position(t,6));
                        rotMatLocal = rotMatYaw.' * rotMatGlobal;
                        [phiLoc, thetaLoc, psiLoc] = rotMatXYZ2Eul(rotMatLocal); % get orientation in local frame
                        % position in local frame
                        obj.bodies(ii).positionLocal(t,1:3) = rotMatYaw.'*obj.bodies(ii).position(t,1:3).'; % rotate linear position vector from global to local frame
                        obj.bodies(ii).positionLocal(t,4:6) = [phiLoc, thetaLoc, psiLoc];
                        % velocity in local frame
                        obj.bodies(ii).velocityLocal(t,1:3) = rotMatYaw.'*obj.bodies(ii).velocity(t,1:3).';
                        obj.bodies(ii).velocityLocal(t,4:6) = rotMatYaw.'*obj.bodies(ii).velocity(t,4:6).';
                        % acceleration in local frame
                        obj.bodies(ii).accelerationLocal(t,1:3) = rotMatYaw.'*obj.bodies(ii).acceleration(t,1:3).';
                        obj.bodies(ii).accelerationLocal(t,4:6) = rotMatYaw.'*obj.bodies(ii).acceleration(t,4:6).';
                    end
                end
                if ~isempty(bodiesOutput(ii).hspressure)
                    obj.bodies(ii).cellPressures_time = bodiesOutput(ii).hspressure.time;
                    obj.bodies(ii).cellPressures_hydrostatic   = bodiesOutput(ii).hspressure.signals.values;
                    obj.bodies(ii).cellPressures_waveLinear    = bodiesOutput(ii).wpressurel.signals.values;
                    obj.bodies(ii).cellPressures_waveNonLinear = bodiesOutput(ii).wpressurenl.signals.values;
                else
                    obj.bodies(ii).cellPressures_time = [];
                    obj.bodies(ii).cellPressures_hydrostatic   = [];
                    obj.bodies(ii).cellPressures_waveLinear    = [];
                    obj.bodies(ii).cellPressures_waveNonLinear = [];
                end
            end
            % PTOs
            if isstruct(ptosOutput)
                signals = {'position','velocity','acceleration','forceTotal','forceActuation','forceConstraint','forceInternalMechanics','powerInternalMechanics'};
                for ii = 1:length(ptosOutput)
                    obj.ptos(ii).name = ptosOutput(ii).name;
                    obj.ptos(ii).time = ptosOutput(ii).time;
                    for jj = 1:length(signals)
                        obj.ptos(ii).(signals{jj}) =  ptosOutput(ii).signals.values(:,(jj-1)*6+1:(jj-1)*6+6);
                    end
                end
            end
            % Constraints
            if isstruct(constraintsOutput)
                signals = {'position','velocity','acceleration','forceConstraint'};
                for ii = 1:length(constraintsOutput)
                    obj.constraints(ii).name = constraintsOutput(ii).name;
                    obj.constraints(ii).time = constraintsOutput(ii).time;
                    for jj = 1:length(signals)
                        obj.constraints(ii).(signals{jj}) = constraintsOutput(ii).signals.values(:, (jj-1)*6+1:(jj-1)*6+6);
                    end
                end
            end
            % Mooring
            if isstruct(mooringOutput)
                signals = {'position','velocity','forceMooring'};
                for ii = 1:length(mooringOutput)
                    obj.mooring(ii).name = mooringOutput(ii).name;
                    obj.mooring(ii).time = mooringOutput(ii).time;
                    for jj = 1:length(signals)
                        obj.mooring(ii).(signals{jj}) = mooringOutput(ii).signals.values(:, (jj-1)*6+1:(jj-1)*6+6);
                    end
                end
            end
            % Cables
            if isstruct(cablesOutput)
                signals = {'position','velocity','acceleration','forceTotal','forceActuation',...
                    'forceConstraint'};
                for ii = 1:length(cablesOutput)
                    obj.cables(ii).name = cablesOutput(ii).name;
                    obj.cables(ii).time = cablesOutput(ii).time;
                    for jj = 1:length(signals)
                        obj.cables(ii).(signals{jj}) = cablesOutput(ii).signals.values(:,(jj-1)*6+1:(jj-1)*6+6);
                    end
                end
            end
            % PTO-Sim
            if isstruct(ptosimOutput)
                %names = {'HydPistonCompressible','GasHydAccumulator','RectifyingCheckValve','HydraulicMotorV2','ElectricMachineEC'};
                hydPistonCompressibleSignals = {'pressureA','forcePTO','pressureB'};
                gasHydAccumulatorSignals = {'pressure','flowRate'};
                rectifyingCheckValveSignals = {'flowRateA','flowRateB','flowRateC','flowRateD'};
                hydraulicMotorSignals = {'shaftSpeed','torque','deltaP','flowRate'};
                electricMachineECSignals = {'torqueEM','shaftSpeed','current','voltage'};
                linearCrankSignals = {'ptoTorque','angPosition','angVelocity'};
                adjustableRodSignals = {'ptoTorque','angPosition','angVelocity'};
                checkValveSignals = {'flowCheckValve','deltaPCheckValve'};
                linearGeneratorSignals = {'absPower','force','fricForce','Ia','Ib','Ic','Va','Vb','Vc','elecPower','vel'};
                rotaryGeneratorSignals = {'absPower','Torque','fricTorque','Ia','Ib','Ic','Va','Vb','Vc','elecPower','vel'};

                for ii = 1:length(ptosimOutput)
                    obj.ptosim(ii).name = ptosimOutput(ii).name;
                    obj.ptosim(ii).time = ptosimOutput(ii).time;
                    obj.ptosim(ii).type = ptosimOutput(ii).type;
                    if ptosimOutput(ii).type == 1
                        signals = electricMachineECSignals;
                    elseif ptosimOutput(ii).type == 2
                        signals = hydPistonCompressibleSignals;
                    elseif ptosimOutput(ii).type == 3
                        signals = gasHydAccumulatorSignals;
                    elseif ptosimOutput(ii).type == 4
                        signals = rectifyingCheckValveSignals;
                    elseif ptosimOutput(ii).type == 5
                        signals = hydraulicMotorSignals;
                    elseif ptosimOutput(ii).type == 6
                        signals = linearCrankSignals;
                    elseif ptosimOutput(ii).type == 7
                        signals = adjustableRodSignals;
                    elseif ptosimOutput(ii).type == 8
                        signals = checkValveSignals;
                    elseif ptosimOutput(ii).type == 9
                        signals = linearGeneratorSignals;
                    elseif ptosimOutput(ii).type == 10
                        signals = rotaryGeneratorSignals;
                    end
                    for jj = 1:length(signals)
                        obj.ptosim(ii).(signals{jj}) = ptosimOutput(ii).signals.values(:,jj);
                    end
                end
            end
        end

        function obj = loadMoorDyn(obj,linesNum)
            % This method reads MoorDyn outputs for each instance of the
            % ``mooringClass``
            %
            % Parameters
            % ------------
            %     linesNum : integer
            %         the number of MoorDyn lines
            %

            arguments
                obj
                linesNum (1,1) double {mustBeInteger}
            end

            % load Lines.out
            filename = './Mooring/Lines.out';
            fid = fopen(filename, 'r');
            header = strsplit(fgetl(fid));
            data = dlmread(filename,'',1,0);
            tmp = size(data);
            ncol = tmp(2);clear tmp
            for icol=1:ncol
               eval(['obj.moorDyn.Lines.' header{icol} ' = data(:,' num2str(icol) ');']);
            end
            fclose(fid);
            % load Line#.out
            for iline=1:linesNum
                eval(['obj.moorDyn.Line' num2str(iline) '=struct();']);
                filename = ['./Mooring/Line' num2str(iline) '.out'];
                try
                    fid = fopen(filename);
                    header = strsplit(strtrim(fgetl(fid)));
                    data = dlmread(filename,'',1,0);
                    tmp = size(data);
                    ncol = tmp(2);clear tmp
                    for icol=1:ncol
                        eval(['obj.moorDyn.Line' num2str(iline) '.' header{icol} ' = data(:,' num2str(icol) ');']);
                    end
                    fclose(fid);
                catch
                    fprintf('\n No moorDyn *.out file saved for Line%u\n',iline);
                end
            end
        end

        function plotResponse(obj,bodyNum,comp)
            % This method plots the response of a body for a given DOF.
            %
            % Parameters
            % ------------
            %     bodyNum : integer
            %         the body number to plot
            %
            %     comp : integer
            %         the response component (i.e. dof) to be plotted (e.g. 1-6)
            %

            arguments
                obj
                bodyNum (1,1) double {mustBeInteger}
                comp (1,1) double {mustBeMember(comp,1:6)}
            end

            DOF = {'Surge','Sway','Heave','Roll','Pitch','Yaw'};
            t=obj.bodies(bodyNum).time;
            if comp < 4
                pos=obj.bodies(bodyNum).position(:,comp)-obj.bodies(bodyNum).centerGravity(comp);
            else
                pos=obj.bodies(bodyNum).position(:,comp);
            end
            vel=obj.bodies(bodyNum).velocity(:,comp);
            acc=obj.bodies(bodyNum).acceleration(:,comp);
            figure()
            plot(t,pos,'k-',...
                t,vel,'b-',...
                t,acc,'r-')
            legend({'position','velocity','acceleration'})
            xlabel('Time (s)')
            ylabel('Response in (m) or (radians)')
            title(['body' num2str(bodyNum) ' (' obj.bodies(bodyNum).name ') ' DOF{comp} ' Response'])
            clear t pos vel acc i
        end

        function plotForces(obj,bodyNum,comp)
            % This method plots the forces on a body for a given DOF.
            %
            % Parameters
            % ------------
            %     bodyNum : integer
            %         the body number to plot
            %
            %     comp : integer
            %         the force component (i.e. dof) to be plotted (e.g. 1-6)
            %

            arguments
                obj
                bodyNum (1,1) double {mustBeInteger}
                comp (1,1) double {mustBeMember(comp,1:6)}
            end

            DOF = {'Surge','Sway','Heave','Roll','Pitch','Yaw'};
            t=obj.bodies(bodyNum).time;
            FT=obj.bodies(bodyNum).forceTotal(:,comp);
            FE=obj.bodies(bodyNum).forceExcitation(:,comp);
            FRD=-1*obj.bodies(bodyNum).forceRadiationDamping(:,comp);
            FAM=-1*obj.bodies(bodyNum).forceAddedMass(:,comp);
            FR=-1*obj.bodies(bodyNum).forceRestoring(:,comp);
            FMV=-1*obj.bodies(bodyNum).forceMorisonAndViscous(:,comp);
            FLD=-1*obj.bodies(bodyNum).forceLinearDamping(:,comp);
            figure();
            plot(t,FT,...
                t,FE,...
                t,FRD,...
                t,FAM,...
                t,FR,...
                t,FMV,...
                t,FLD)
            legend('forceTotal','forceExcitation','forceRadiationDamping','forceAddedMass','forceRestoring','forceViscous','forceLinearDamping')
            xlabel('Time (s)')
            ylabel('Force (N) or Torque (N*m)')
            title(['body' num2str(bodyNum) ' (' obj.bodies(bodyNum).name ') ' DOF{comp} ' Forces'])
            clear t FT FE FRD FR FV FM i
        end

        function saveViz(obj,simu,body,waves,options)
            % This method plots and saves the wave elevation and body
            % geometry over time to visualize the waves and response
            %
            % Parameters
            % ------------
            %     simu :
            %         simulationClass object
            %
            %     body :
            %         bodyClass object
            %
            %     waves :
            %         waveClass object
            %
            %     options
            %         axisLimits : 1x6 float matrix
            %             x, y, and z-bounds of figure axes in the format:
            %             [min x, max x, min y, max y, min z, max z]
            %             Default = [-simu.domainSize/2 simu.domainSize/2
            %             -simu.domainSize/2 simu.domainSize/2 -waves.waterDepth maximumHeight]
            %         timesPerFrame : float
            %             number of simulation time steps per video frame
            %             (higher number decreases computation time)
            %             Default = 1
            %         startEndTime : 1x2 float matrix
            %             Array defining the start and end times of the
            %             visualization
            %             Default = [min(t) max(t)]
            %         saveSetting : integer
            %             0 = video, 1 = gif. Default = 0
            %

            arguments
                obj
                simu
                body
                waves
                options.axisLimits (1,6) double {mustBeReal, mustBeNonNan, mustBeFinite} = [-simu.domainSize/2 simu.domainSize/2 -simu.domainSize/2 simu.domainSize/2 -waves.waterDepth -999];
                options.timesPerFrame (1,1) double {mustBeInteger, mustBePositive} = 1;
                options.startEndTime (1,2) double {mustBeReal, mustBeNonnegative, mustBeNonNan} = [0 0];
                options.saveSetting (1,1) {mustBeMember(options.saveSetting,0:1)} = 0;
            end
            % Set time vector
            t = obj.wave.time(1:options.timesPerFrame*round(simu.dtOut/simu.dt,0):end,1);
            if isequal(options.startEndTime, [0 0])
                options.startEndTime = [min(t) max(t)];
            end
            % Create grid using provided x and y coordinates
            x = linspace(options.axisLimits(1),options.axisLimits(2),200);
            y = linspace(options.axisLimits(3),options.axisLimits(4),200);
            [X,Y] = meshgrid(x,y);
            % Initialize maximum body height
            maxHeight = 0;
            % Read in data for each body
            for ibod=1:length(obj.bodies)
                % Read and assign geometry data
                if isempty(body(ibod).geometry.vertex)
                    % Import body geometry for linear hydro cases
                    body(ibod).importBodyGeometry(simu.domainSize);
                end
                bodyMesh(ibod).Points = body(ibod).geometry.vertex;
                bodyMesh(ibod).Conns = body(ibod).geometry.face;
                % Read changes and assign angles and position changes over time
                bodyMesh(ibod).deltaPos = [obj.bodies(ibod).position(1:options.timesPerFrame:end,1)-obj.bodies(ibod).position(1,1),...
                obj.bodies(ibod).position(1:options.timesPerFrame:end,2)-obj.bodies(ibod).position(1,2),...
                obj.bodies(ibod).position(1:options.timesPerFrame:end,3)-obj.bodies(ibod).position(1,3)];
                % Save maximum body height
                if max(bodyMesh(ibod).Points(:,3))+max(bodyMesh(ibod).deltaPos(:,3)) > maxHeight
                    maxHeight = max(bodyMesh(ibod).Points(:,3))+max(bodyMesh(ibod).deltaPos(:,3));
                end
            end
            if options.axisLimits(6) == -999
                options.axisLimits(6) = maxHeight;
            end
            if options.saveSetting == 0
                % Create video file and open it for writing
                video = VideoWriter('waveViz.avi');
                video.FrameRate = 1/(simu.dtOut*options.timesPerFrame);
                open(video);
            elseif options.saveSetting == 1
                % Create the gif file
                gifFilename = 'waveViz.gif';
            end
            % Initialize figure and image counter
            figure();
            imageCount = 0;
            for i=1:length(t)
                if t(i) >= options.startEndTime(1) && t(i) <= options.startEndTime(2)
                    imageCount = imageCount + 1;
                    for ibod = 1:length(obj.bodies)
                        % Apply rotation to each point
                        rotMat = eulXYZ2RotMat(obj.bodies(ibod).position(1+options.timesPerFrame*(i-1),4), ...
                            obj.bodies(ibod).position(1+options.timesPerFrame*(i-1),5), ...
                            obj.bodies(ibod).position(1+options.timesPerFrame*(i-1),6));
                        for ipts=1:length(bodyMesh(ibod).Points(:,1))
                            bodyMesh(ibod).rotation(ipts,:) = (rotMat*bodyMesh(ibod).Points(ipts,:).').';
                        end

                        % Calculate full position changes due to rotation,
                        % translation, and center of gravity
                        bodyMesh(ibod).pointsNew = bodyMesh(ibod).rotation + bodyMesh(ibod).deltaPos(i,:) + body(ibod).centerGravity.';

                        % Create and plot final triangulation of geometry with applied changes
                        bodFinal = triangulation(bodyMesh(ibod).Conns,bodyMesh(ibod).pointsNew);
                        trisurf(bodFinal,'FaceColor',[1 1 0],'EdgeColor','k','EdgeAlpha',.2)
                        hold on
                    end
                    % Create and wave elevation grid
                    Z = waveElevationGrid(waves, t(i), X, Y, simu.dtOut, simu.gravity);
                    surf(X,Y,Z,'FaceAlpha',.85,'EdgeColor','none')
                    hold on
                    % Display seafloor
                    seaFloor = -waves.waterDepth*ones(size(X, 1));
                    surf(X,Y,seaFloor,'FaceColor',[.4 .4 0],'EdgeColor','none');
                    hold on
                    % Time visual
                    nDecimals = max(0,ceil(-log10(simu.dtOut*options.timesPerFrame)));
                    nLeading = ceil(log10(max(t)));
                    tAnnot = sprintf(['time = %' num2str(nDecimals+nLeading+1) '.' num2str(nDecimals) 'f s'],t(i));
                    % Settings and labels
                    caxis([min(waves.waveAmpTime(:,2)) max(waves.waveAmpTime(:,2))])
                    colormap winter
                    c = colorbar;
                    ylabel(c, 'Wave Elevation (m)')
                    title({'Wave Elevation and Geometry Visualization',tAnnot})
                    xlabel('x(m)')
                    ylabel('y(m)')
                    zlabel('z(m)')
                    daspect([1 1 1])
                    axis(options.axisLimits)
                    % Create figure while iterating through time loop
                    drawnow;
                    % Capture figure for saving
                    frame = getframe(gcf);
                    if options.saveSetting == 0
                        % Save to video
                        writeVideo(video,frame);
                    elseif options.saveSetting == 1
                        % Save to gif
                        im = frame2im(frame);
                        [imind,cm] = rgb2ind(im,256);
                        if imageCount == 1
                            imwrite(imind,cm,gifFilename,'gif', 'Loopcount',inf);
                        else
                            imwrite(imind,cm,gifFilename,'gif','WriteMode','append','DelayTime',simu.dtOut);
                        end
                    end
                    hold off
                end
            end
            % Close video file
            if options.saveSetting == 0
                close(video);
            end
        end

        function writeText(obj)
            % This method writes WEC-Sim outputs to a (ASCII) text file.
            % This method is executed by specifying ``simu.outputtxt=1``
            % in the ``wecSimInputFile.m``.
            filename = ['output/wave.txt'];
            fid = fopen(filename,'w+');
            header = {'time','elevation'};
            for ii=1:length(header)
                tmp(ii) = length(header{ii});
            end
            numChar = max(tmp)+2; clear tmp;
            header_fmt = ['%' num2str(numChar) 's '];
            ncols = length(header);
            tmp = size(obj.wave.time);
            nrows = tmp(1); clear tmp;
            data_fmt = [repmat('%10.5f ',1,ncols) '\n'];
            data = zeros(nrows,ncols);
            data(:,1) = obj.wave.time;
            data(:,2) = obj.wave.elevation;
            if ncols > 2
                for ii = 3:length(header)
                    eval(['data(:,' num2str(ii) ') = obj.wave.' header{ii} ';']);
                end
            end
            for ii = 1:length(header)
                fprintf(fid,header_fmt,header{ii});
            end
            fprintf(fid,'\n');
            fprintf(fid,data_fmt,data');
            fclose(fid);
            % bodies
            signals = {'position','velocity','acceleration','forceTotal','forceExcitation','forceRadiationDamping','forceAddedMass','forceRestoring','forceMorisonAndViscous','forceLinearDamping'};
            header = {'time', ...
                      'position_1'               ,'position_2'               ,'position_3'               ,'position_4'               ,'position_5'               ,'position_6'               , ...
                      'velocity_1'               ,'velocity_2'               ,'velocity_3'               ,'velocity_4'               ,'velocity_5'               ,'velocity_6'               , ...
                      'acceleration_1'           ,'acceleration_2'           ,'acceleration_3'           ,'acceleration_4'           ,'acceleration_5'           ,'acceleration_6'           , ...
                      'forceTotal_1'             ,'forceTotal_2'             ,'forceTotal_3'             ,'forceTotal_4'             ,'forceTotal_5'             ,'forceTotal_6'             , ...
                      'forceExcitation_1'        ,'forceExcitation_2'        ,'forceExcitation_3'        ,'forceExcitation_4'        ,'forceExcitation_5'        ,'forceExcitation_6'        , ...
                      'forceRadiationDamping_1'  ,'forceRadiationDamping_2'  ,'forceRadiationDamping_3'  ,'forceRadiationDamping_4'  ,'forceRadiationDamping_5'  ,'forceRadiationDamping_6'  , ...
                      'forceAddedMass_1'         ,'forceAddedMass_2'         ,'forceAddedMass_3'         ,'forceAddedMass_4'         ,'forceAddedMass_5'         ,'forceAddedMass_6'         , ...
                      'forceRestoring_1'         ,'forceRestoring_2'         ,'forceRestoring_3'         ,'forceRestoring_4'         ,'forceRestoring_5'         ,'forceRestoring_6'         , ...
                      'forceMorisonAndViscous_1' ,'forceMorisonAndViscous_2' ,'forceMorisonAndViscous_3' ,'forceMorisonAndViscous_4' ,'forceMorisonAndViscous_5' ,'forceMorisonAndViscous_6' , ...
                      'forceLinearDamping_1'     ,'forceLinearDamping_2'     ,'forceLinearDamping_3'     ,'forceLinearDamping_4'     ,'forceLinearDamping_5'     ,'forceLinearDamping_6'     };
            for ii=1:length(signals)
                tmp(ii) = length(signals{ii});
            end
            numChar = max(tmp)+2; clear tmp;
            ncols = 1 + length(signals)*6;
            tmp = size(obj.bodies(1).time);
            nrows = tmp(1); clear tmp;
            header_fmt = ['%' num2str(numChar) 's '];
            data_fmt = [repmat('%10.5f ',1,ncols) '\n'];
            for ibod = 1:length(obj.bodies)
                filename = ['output/body' num2str(ibod) '_' obj.bodies(ibod).name '.txt'];
                fid = fopen(filename,'w+');
                data = zeros(nrows,ncols);
                data(:,1) = obj.bodies(ibod).time;
                fprintf(fid,header_fmt,header{1});
                for isignal=1:length(signals)
                    for idof = 1:6
                        fprintf(fid,header_fmt,header{1 + (isignal-1)*6+idof});
                    end
                    data(:, 1+(isignal-1)*6+1:1+(isignal-1)*6+6) = obj.bodies(ibod).(signals{isignal});
                end
                fprintf(fid,'\n');
                fprintf(fid,data_fmt,data');
                fclose(fid);
                if isfield(obj.bodies(ibod),'cellPressures_hydrostatic')
                    filename = ['output/body' num2str(ibod) '_' obj.bodies(ibod).name '_cellPressure_hydrostatic.txt'];
                    fid = fopen(filename,'w+');
                    header_2 = {'time'};
                    tmp = size(obj.bodies(ibod).cellPressures_hydrostatic);
                    nrows2 = tmp(1);
                    ncols2 = tmp(2)+1;
                    for icell=1:ncols2-1
                        header_2{icell+1} = ['cell_' num2str(icell)];
                    end
                    tmp = length(header_2{end});
                    numChar = max(tmp)+2; clear tmp;
                    header_fmt_2 = ['%' num2str(numChar) 's '];
                    data_fmt_2 = [repmat('%10.5f ',1,ncols2) '\n'];
                    data = zeros(nrows2,ncols2);
                    data(:,1) = obj.bodies(ibod).cellPressures_time;
                    data(:,2:end) = obj.bodies(ibod).cellPressures_hydrostatic;
                    for jj = 1:length(header_2)
                        fprintf(fid,header_fmt_2,header_2{jj});
                    end
                    fprintf(fid,'\n');
                    fprintf(fid,data_fmt_2,data');
                    fclose(fid);
                    % wave linear
                    filename = ['output/body' num2str(ibod) '_' obj.bodies(ibod).name '_cellPressure_waveLinear.txt'];
                    fid = fopen(filename,'w+');
                    data = zeros(nrows2,ncols2);
                    data(:,1) = obj.bodies(ibod).cellPressures_time;
                    data(:,2:end) = obj.bodies(ibod).cellPressures_waveLinear;
                    for jj = 1:length(header_2)
                        fprintf(fid,header_fmt_2,header_2{jj});
                    end
                    fprintf(fid,'\n');
                    fprintf(fid,data_fmt_2,data');
                    fclose(fid);
                    % wave nonlinear
                    filename = ['output/body' num2str(ibod) '_' obj.bodies(ibod).name '_cellPressure_waveNonLinear.txt'];
                    fid = fopen(filename,'w+');
                    data = zeros(nrows2,ncols2);
                    data(:,1) = obj.bodies(ibod).cellPressures_time;
                    data(:,2:end) = obj.bodies(ibod).cellPressures_waveNonLinear;
                    for jj = 1:length(header_2)
                        fprintf(fid,header_fmt_2,header_2{jj});
                    end
                    fprintf(fid,'\n');
                    fprintf(fid,data_fmt_2,data');
                    fclose(fid);
                end
            end
            % ptos
            if isfield(obj.ptos,'name')
                signals = {'position','velocity','acceleration','forceTotal','forceActuation','forceConstraint','forceInternalMechanics','powerInternalMechanics'};
                header = {'time', ...
                          'position_1'              ,'position_2'              ,'position_3'              ,'position_4'              ,'position_5'              ,'position_6'              , ...
                          'velocity_1'              ,'velocity_2'              ,'velocity_3'              ,'velocity_4'              ,'velocity_5'              ,'velocity_6'              , ...
                          'acceleration_1'          ,'acceleration_2'          ,'acceleration_3'          ,'acceleration_4'          ,'acceleration_5'          ,'acceleration_6'          , ...
                          'forceTotal_1'            ,'forceTotal_2'            ,'forceTotal_3'            ,'forceTotal_4'            ,'forceTotal_5'            ,'forceTotal_6'            , ...
                          'forceActuation_1'        ,'forceActuation_2'        ,'forceActuation_3'        ,'forceActuation_4'        ,'forceActuation_5'        ,'forceActuation_6'        , ...
                          'forceConstraint_1'       ,'forceConstraint_2'       ,'forceConstraint_3'       ,'forceConstraint_4'       ,'forceConstraint_5'       ,'forceConstraint_6'       , ...
                          'forceInternalMechanics_1','forceInternalMechanics_2','forceInternalMechanics_3','forceInternalMechanics_4','forceInternalMechanics_5','forceInternalMechanics_6', ...
                          'powerInternalMechanics_1','powerInternalMechanics_2','powerInternalMechanics_3','powerInternalMechanics_4','powerInternalMechanics_5','powerInternalMechanics_6', };
                for ii=1:length(signals)
                    tmp(ii) = length(signals{ii});
                end
                numChar = max(tmp)+2; clear tmp;
                ncols = 1 + length(signals)*6;
                tmp = size(obj.ptos(1).time);
                nrows = tmp(1); clear tmp;
                header_fmt = ['%' num2str(numChar) 's '];
                data_fmt = [repmat('%10.5f ',1,ncols) '\n'];
                for ipto = 1:length(obj.ptos)
                    filename = ['output/pto' num2str(ipto) '_' obj.ptos(ipto).name '.txt'];
                    fid = fopen(filename,'w+');
                    data = zeros(nrows,ncols);
                    data(:,1) = obj.ptos(ipto).time;
                    fprintf(fid,header_fmt,header{1});
                    for isignal=1:length(signals)
                        for idof = 1:6
                            fprintf(fid,header_fmt,header{1 + (isignal-1)*6+idof});
                        end
                        data(:, 1+(isignal-1)*6+1:1+(isignal-1)*6+6) = obj.ptos(ipto).(signals{isignal});
                    end
                    fprintf(fid,'\n');
                    fprintf(fid,data_fmt,data');
                    fclose(fid);
                end
            end
            % constraints
            if isfield(obj.constraints,'name')
                signals = {'position','velocity','acceleration','forceConstraint'};
                header = {'time', ...
                          'position_1'       ,'position_2'       ,'position_3'       ,'position_4'       ,'position_5'       ,'position_6'       , ...
                          'velocity_1'       ,'velocity_2'       ,'velocity_3'       ,'velocity_4'       ,'velocity_5'       ,'velocity_6'       , ...
                          'acceleration_1'   ,'acceleration_2'   ,'acceleration_3'   ,'acceleration_4'   ,'acceleration_5'   ,'acceleration_6'   , ...
                          'forceConstraint_1','forceConstraint_2','forceConstraint_3','forceConstraint_4','forceConstraint_5','forceConstraint_6'     };
                for ii=1:length(signals)
                    tmp(ii) = length(signals{ii});
                end
                numChar = max(tmp)+2; clear tmp;
                ncols = 1 + length(signals)*6;
                tmp = size(obj.constraints(1).time);
                nrows = tmp(1); clear tmp;
                header_fmt = ['%' num2str(numChar) 's '];
                data_fmt = [repmat('%10.5f ',1,ncols) '\n'];
                for icon = 1:length(obj.constraints)
                    filename = ['output/constraint' num2str(icon) '_' obj.constraints(icon).name '.txt'];
                    fid = fopen(filename,'w+');
                    data = zeros(nrows,ncols);
                    data(:,1) = obj.constraints(icon).time;
                    fprintf(fid,header_fmt,header{1});
                    for isignal=1:length(signals)
                        for idof = 1:6
                            fprintf(fid,header_fmt,header{1 + (isignal-1)*6+idof});
                        end
                        data(:, 1+(isignal-1)*6+1:1+(isignal-1)*6+6) = obj.constraints(icon).(signals{isignal});
                    end
                    fprintf(fid,'\n');
                    fprintf(fid,data_fmt,data');
                    fclose(fid);
                end
            end
            %ptoSim
            if isfield(obj.ptosim,'time')
                f1 = fields(obj.ptosim);
                count = 1;
                header = {'time'};
                data = obj.ptosim.time;
                for ifld1=1:(length(f1)-1)
                    f2 = fields(obj.ptosim.(f1{ifld1}));
                    for iins = 1:length(obj.ptosim.(f1{ifld1}))
                        for ifld2 = 1:length(f2)
                            count = count+1;
                            header{count} = [f1{ifld1} num2str(iins) '_' f2{ifld2}];
                            data(:,count) = obj.ptosim.(f1{ifld1}).(f2{ifld2});
                        end
                    end
                end
                for ii=1:length(header)
                    tmp(ii) = length(header{ii});
                end
                numChar = max(tmp)+2; clear tmp;
                header_fmt = ['%' num2str(numChar) 's '];
                data_fmt = [repmat('%10.5f ',1,length(header)) '\n'];
                filename = ['output/ptosim.txt'];
                fid = fopen(filename,'w+');
                for ii=1:length(header)
                    fprintf(fid,header_fmt,header{ii});
                end
                fprintf(fid,'\n');
                fprintf(fid,data_fmt,data');
                fclose(fid);
            end
            % mooring
            if isfield(obj.mooring,'name')
                signals = {'position','velocity','forceMooring'};
                header = {'time', ...
                          'position_1'       ,'position_2'       ,'position_3'       ,'position_4'       ,'position_5'       ,'position_6'       , ...
                          'velocity_1'       ,'velocity_2'       ,'velocity_3'       ,'velocity_4'       ,'velocity_5'       ,'velocity_6'       , ...
                          'forceMooring_1','forceMooring_2','forceMooring_3','forceMooring_4','forceMooring_5','forceMooring_6'     };
                for ii=1:length(signals)
                    tmp(ii) = length(signals{ii});
                end
                numChar = max(tmp)+2; clear tmp;
                ncols = 1 + length(signals)*6;
                tmp = size(obj.mooring(1).time);
                nrows = tmp(1); clear tmp;
                header_fmt = ['%' num2str(numChar) 's '];
                data_fmt = [repmat('%10.5f ',1,ncols) '\n'];
                for imoor = 1:length(obj.mooring)
                    filename = ['output/mooring' num2str(imoor) '_' obj.mooring(imoor).name '.txt'];
                    fid = fopen(filename,'w+');
                    data = zeros(nrows,ncols);
                    data(:,1) = obj.mooring(imoor).time;
                    fprintf(fid,header_fmt,header{1});
                    for isignal=1:length(signals)
                        for idof = 1:6
                            fprintf(fid,header_fmt,header{1 + (isignal-1)*6+idof});
                        end
                        data(:, 1+(isignal-1)*6+1:1+(isignal-1)*6+6) = obj.mooring(imoor).(signals{isignal});
                    end
                    fprintf(fid,'\n');
                    fprintf(fid,data_fmt,data');
                    fclose(fid);
                end
            end
        end
    end
end


function [out] = prep_selectTrials(dat,varargin)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% prep_selectTrials (Pre-processing procedure):
%
% Synopsis:
%     [out] = prep_selectTrials(DAT,<OPT>)
%
% Example :
%     out = prep_selectTrials(dat,{'Index',[20:35]});
%
% Arguments:
%     dat - Structure. epoched data
%         - Data which trials are to be selected
%     varargin - struct or property/value list of optional properties:
%          :  index - index of trials to be selected
%
% Returns:
%     out - Data structure which has selected channels from epoched data
%
% Description:
%     This function selects data of specified trials
%     from  epoched data.
%     continuous data should be [time * channels]
%     epoched data should be [time * channels * trials]
%
% See also 'https://github.com/PatternRecognition/OpenBMI'
%
% Min-ho Lee, 12-2017
% mh_lee@korea.ac.kr
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if isempty(varargin)
    warning('OpenBMI: Trials should be specified');
    out = dat;
    return
end
if iscell(varargin{:})
    opt=opt_cellToStruct(varargin{:});
elseif isstruct(varargin{:}) % already structure(x-validation)
    opt=varargin{:}
end

if ~isfield(dat, 'x')
    warning('OpenBMI: Data structure must have a field named ''x''');
    return
end
if ~isfield(dat, 't')
    warning('OpenBMI: Data structure must have a field named ''t''');
    return
end
if ~isfield(dat, 'y_dec') || ~isfield(dat, 'y_logic') || ~isfield(dat, 'y_class')
    warning('OpenBMI: Data structure must have a field named ''y_dec'',''y_logic'',''y_class''');
    return
end

idx = opt.Index;
nd = ndims(dat.x);
if nd == 3
    x = dat.x(:,idx,:);
elseif nd==2
    if size(dat.chan,2)==1
        x = dat.x(:,idx);
        warning('OpenBMI: just 1 channel data?')
    else
        x=dat.x;
    end
elseif nd ==1
    x = dat.x;
else
    warning('OpenBMI: Check for the data dimensionality')
    return
end
out = rmfield(dat,{'x','t','y_dec','y_logic','y_class'});
out.x = x;
out.t = dat.t(idx);
out.y_dec = dat.y_dec(idx);
out.y_logic = dat.y_logic(:,idx);
out.y_class = dat.y_class(idx);


function func = fcond(c, varargin)
% FUNC = FCOND(COND-FUNC, FUNCTION_1, ...)
%   Make a function FUNC that takes any number of ARGS, and invokes
%   FUNCTO_n with them, where n = COND-FUNC(ARGS).
%

  functions = varargin;
  function varargout = fcondFunc(varargin)
    idx = c(varargin{:});
    f = functions{idx};
    [varargout{1:nargout}] = f(varargin{:});
  end

  func = @fcondFunc;
end


function varargout=rotax2qr(varargin)
%
% For calling details please see v_rotax2qr.m
%
% This dummy routine is included for backward compatibility only
% and will be removed in a future release of voicebox. Please use
% v_rotax2qr.m in future and/or update with v_voicebox_update.m
%
%      Copyright (C) Mike Brookes 2018
%      Version: $Id: rotax2qr.m 10863 2018-09-21 15:39:23Z dmb $
%
if nargout
    varargout=cell(1,nargout);
    [varargout{:}]=v_rotax2qr(varargin{:});
else
    v_rotax2qr(varargin{:});
end


function [isvalid msg]  = verify_tracks(filename,targettype)
% function [isvalid msg] = verify_tracks(filename,targettype)
% Check integrity of tracks file (see published doc as a guide).
%
% filename: full path to trx file
% targettype: JLabelData targetType
%
% isvalid: true if trx file passes all checks, false otherwise
% msg: if isvalid is false, string containing reason(s) for failure.

TRX_FLDS_REQ = {'x' 'y' 'theta' 'a' 'b' 'nframes' 'firstframe' 'endframe' ...
  'off' 'id' 'x_mm' 'y_mm' 'theta_mm' 'a_mm' 'b_mm' 'sex' 'dt' 'fps'};
TRX_FLDS_OPT = {'timestamps'};
TRX_FLDS_LAR = {'area' 'xcontour' 'ycontour' 'xspine' 'yspine' 'area_mm' ...
  'xspine_mm' 'yspine_mm'};

try
  mat = load(filename','-mat');
catch %#ok<CTCH>
  isvalid = false;
  msg = sprintf('Can''t load MAT file ''%s''.',filename);
  return;
end

if ~isfield(mat,'trx')
  isvalid = false;
  msg = 'MAT file does not contain variable ''trx''.';
  return;
end
trx = mat.trx;

% check trx fields
tf = isfield(trx,TRX_FLDS_REQ);
if ~all(tf)
  isvalid = false;
  msg = sprintf('trx struct array missing required fields: %s',...
    civilizedStringFromCellArrayOfStrings(TRX_FLDS_REQ(~tf)));
  return;
end

unkFlds = setdiff(fieldnames(trx),[TRX_FLDS_REQ TRX_FLDS_OPT TRX_FLDS_LAR]);
if ~isempty(unkFlds)
  warning('verify_tracks:unknownFields','Unknown fields in trx struct array: %s',...
    civilizedStringFromCellArrayOfStrings(unkFlds));
end

Ntrx = numel(trx);
issues = cell(0,1);
NFRAMES_ROW_VECS = {'x' 'y' 'theta' 'a' 'b' 'x_mm' 'y_mm' 'theta_mm' 'a_mm' 'b_mm'};
VALID_SEX_VALS = {'M' 'F' '?'};
% Check each trx element. This is not a 100% comprehensive check.
for iTrx = 1:Ntrx

  trxEl = trx(iTrx);
  nf = trxEl.nframes;

  % sizes of row vectors
  for fld = NFRAMES_ROW_VECS, fld = fld{1}; %#ok<*FXSET>
    val = trxEl.(fld);
    issues = lclChk(issues,iTrx,isrow(val) && numel(val)==nf,...
      sprintf('trx field ''%s'' has unexpected size',fld));
  end

  % firstframe/endframe/nframes/off
  issues = lclChk(issues,iTrx,(trxEl.endframe-trxEl.firstframe+1)==trxEl.nframes,...
    'inconsistent values for nframes/firstframe/endframe');
  issues = lclChk(issues,iTrx,trxEl.off==1-trxEl.firstframe,...
    'inconsistent values for firstframe/off');

  val = trxEl.sex;
  issues = lclChk(issues,iTrx,...
    (isscalar(val) || isvector(val) && iscellstr(val) && numel(val)==nf) ...
      && all(ismember(val,VALID_SEX_VALS)),'invalid value for field ''sex''');

  val = trxEl.dt;
  issues = lclChk(issues,iTrx,isrow(val) && numel(val)==nf-1,...
      'field ''dt'' has unexpected size');
end

isvalid = isempty(issues);
msg = sprintf('%s\n',issues{:});
msg = msg(1:end-1);

function issues = lclChk(issues,iTrx,tf,str)
if ~tf
  issues{end+1,1} = sprintf('Trx %d: %s',iTrx,str);
end


function vis_multicut2(det,pidxs,parts)

colors = {'r','g','b','c','m','y'};
markers = {'+','o','s'}; %,'x','.','-','s','d'

for j = 1:length(det)
    labels = cell(0);
    n = 0;
    points = zeros(1,2);
    for i = 1:length(pidxs)
        pidx = pidxs(i);
        jidx = parts(pidx+1).pos(1);
        pp = det{jidx+1};
        if (~isempty(pp))
            n = n  + 1;
            labels{n} = num2str(i);
            %                     labels{n} = sprintf('%1.2f',pp(3));
            points(n,:) = pp(1:2);
        end
    end
    lp = 1;
    if (lp <= 5)
        m = markers{1};
    elseif (lp > 5 && lp <= 11)
        m = markers{2};
    else
        m = markers{3};
    end
    plot(points(:,1),points(:,2),[colors{mod(lp,6)+1} m],'MarkerSize',5);
    text(points(:,1)+10,points(:,2),labels,'FontSize',6,'BackgroundColor','w');
    axis off;
end

end


function L = gt(p1,p2)
%PREAL/GT Overloaded GT (>) operator for class preal.

global useUnitsFlag

if ~(useUnitsFlag) % If physunits is disabled...
    L=gt(double(p1),double(p2)); % ... treat as double.
    return
end

p1=preal(p1);
p2=preal(p2);
tol=0.001;
if isscalar(p1)
    p1=preal(p1.value*ones(size(p2)),p1.units);
elseif isscalar(p2)
    p2=preal(p2.value*ones(size(p1)),p2.units);
elseif ndims(p1)==ndims(p2)&size(p1)==size(p2)
    % do nothing
else
    error('Array dimensions must agree')
end

L=false(size(p1));
for k=1:numel(L)
    if any(abs(p1(k).units-p2(k).units)>tol)
        error('Attempt to compare dimensionally inconsistent preals')
    end
    L(k)=gt(p1(k).value,p2(k).value);
end


%IM2GIF Convert a multiframe image to an animated GIF file
%
% Examples:
%   im2gif infile
%   im2gif infile outfile
%   im2gif(A, outfile)
%   im2gif(..., '-nocrop')
%   im2gif(..., '-nodither')
%   im2gif(..., '-ncolors', n)
%   im2gif(..., '-loops', n)
%   im2gif(..., '-delay', n)
%
% This function converts a multiframe image to an animated GIF.
%
% To create an animation from a series of figures, export to a multiframe
% TIFF file using export_fig, then convert to a GIF, as follows:
%
%    for a = 2 .^ (3:6)
%       peaks(a);
%       export_fig test.tif -nocrop -append
%    end
%    im2gif('test.tif', '-delay', 0.5);
%
%IN:
%   infile - string containing the name of the input image.
%   outfile - string containing the name of the output image (must have the
%             .gif extension). Default: infile, with .gif extension.
%   A - HxWxCxN array of input images, stacked along fourth dimension, to
%       be converted to gif.
%   -nocrop - option indicating that the borders of the output are not to
%             be cropped.
%   -nodither - option indicating that dithering is not to be used when
%               converting the image.
%   -ncolors - option pair, the value of which indicates the maximum number
%              of colors the GIF can have. This can also be a quantization
%              tolerance, between 0 and 1. Default/maximum: 256.
%   -loops - option pair, the value of which gives the number of times the
%            animation is to be looped. Default: 65535.
%   -delay - option pair, the value of which gives the time, in seconds,
%            between frames. Default: 1/15.

% Copyright (C) Oliver Woodford 2011

function im2gif(A, varargin)

% Parse the input arguments
[A, options] = parse_args(A, varargin{:});

if options.crop ~= 0
    % Crop
    A = crop_borders(A, A(ceil(end/2),1,:,1));
end

% Convert to indexed image
[h, w, c, n] = size(A);
A = reshape(permute(A, [1 2 4 3]), h, w*n, c);
map = unique(reshape(A, h*w*n, c), 'rows');
if size(map, 1) > 256
    dither_str = {'dither', 'nodither'};
    dither_str = dither_str{1+(options.dither==0)};
    if options.ncolors <= 1
        [B, map] = rgb2ind(A, options.ncolors, dither_str);
        if size(map, 1) > 256
            [B, map] = rgb2ind(A, 256, dither_str);
        end
    else
        [B, map] = rgb2ind(A, min(round(options.ncolors), 256), dither_str);
    end
else
    if max(map(:)) > 1
        map = double(map) / 255;
        A = double(A) / 255;
    end
    B = rgb2ind(im2double(A), map);
end
B = reshape(B, h, w, 1, n);

% Bug fix to rgb2ind
map(B(1)+1,:) = im2double(A(1,1,:));

% Save as a gif
imwrite(B, map, options.outfile, 'LoopCount', round(options.loops(1)), 'DelayTime', options.delay);
end

%% Parse the input arguments
function [A, options] = parse_args(A, varargin)
% Set the defaults
options = struct('outfile', '', ...
                 'dither', true, ...
                 'crop', true, ...
                 'ncolors', 256, ...
                 'loops', 65535, ...
                 'delay', 1/15);

% Go through the arguments
a = 0;
n = numel(varargin);
while a < n
    a = a + 1;
    if ischar(varargin{a}) && ~isempty(varargin{a})
        if varargin{a}(1) == '-'
            opt = lower(varargin{a}(2:end));
            switch opt
                case 'nocrop'
                    options.crop = false;
                case 'nodither'
                    options.dither = false;
                otherwise
                    if ~isfield(options, opt)
                        error('Option %s not recognized', varargin{a});
                    end
                    a = a + 1;
                    if ischar(varargin{a}) && ~ischar(options.(opt))
                        options.(opt) = str2double(varargin{a});
                    else
                        options.(opt) = varargin{a};
                    end
            end
        else
            options.outfile = varargin{a};
        end
    end
end

if isempty(options.outfile)
    if ~ischar(A)
        error('No output filename given.');
    end
    % Generate the output filename from the input filename
    [path, outfile] = fileparts(A);
    options.outfile = fullfile(path, [outfile '.gif']);
end

if ischar(A)
    % Read in the image
    A = imread_rgb(A);
end
end

%% Read image to uint8 rgb array
function [A, alpha] = imread_rgb(name)
% Get file info
info = imfinfo(name);
% Special case formats
switch lower(info(1).Format)
    case 'gif'
        [A, map] = imread(name, 'frames', 'all');
        if ~isempty(map)
            map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
            A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
            A = permute(A, [1 2 5 4 3]);
        end
    case {'tif', 'tiff'}
        A = cell(numel(info), 1);
        for a = 1:numel(A)
            [A{a}, map] = imread(name, 'Index', a, 'Info', info);
            if ~isempty(map)
                map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
                A{a} = reshape(map(uint32(A{a})+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
            end
            if size(A{a}, 3) == 4
                % TIFF in CMYK colourspace - convert to RGB
                if isfloat(A{a})
                    A{a} = A{a} * 255;
                else
                    A{a} = single(A{a});
                end
                A{a} = 255 - A{a};
                A{a}(:,:,4) = A{a}(:,:,4) / 255;
                A{a} = uint8(A(:,:,1:3) .* A{a}(:,:,[4 4 4]));
            end
        end
        A = cat(4, A{:});
    otherwise
        [A, map, alpha] = imread(name);
        A = A(:,:,:,1); % Keep only first frame of multi-frame files
        if ~isempty(map)
            map = uint8(map * 256 - 0.5); % Convert to uint8 for storage
            A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0
        elseif size(A, 3) == 4
            % Assume 4th channel is an alpha matte
            alpha = A(:,:,4);
            A = A(:,:,1:3);
        end
end
end


function [labels,behaviors] = ReadStructSVMLabelFile(labelfile)

MAXSTRINGLENGTH = 10000;

fid = fopen(labelfile,'rb');
version = fread(fid,1,'double'); %#ok<NASGU>
moviename_length = fread(fid,1,'int');
if moviename_length > MAXSTRINGLENGTH,
  error('Movie name length = %d > %d\n',moviename_length,MAXSTRINGLENGTH);
end
moviename = fread(fid,moviename_length,'char=>char')'; %#ok<NASGU>
matname_length = fread(fid,1,'int');
if matname_length > MAXSTRINGLENGTH,
  error('Mat name length = %d > %d\n',matname_length,MAXSTRINGLENGTH);
end
matname = fread(fid,matname_length,'char=>char')'; %#ok<NASGU>
trxname_length = fread(fid,1,'int');
if trxname_length > MAXSTRINGLENGTH,
  error('Trx name length = %d > %d\n',trxname_length,MAXSTRINGLENGTH);
end
trxname = fread(fid,trxname_length,'char=>char')'; %#ok<NASGU>
nflies = fread(fid,1,'int'); %#ok<NASGU>
fly_ids = fread(fid,1,'int');
firstframe = fread(fid,1,'int');
firstframe = firstframe + 1;
lastframe = fread(fid,1,'int');
lastframe = lastframe + 1;
nbehaviors = fread(fid,1,'int');
nframes = lastframe-firstframe+1;

behaviornames = cell(1,nbehaviors);

for i = 1:nbehaviors,
  behaviorname_length = fread(fid,1,'int');
  if behaviorname_length > MAXSTRINGLENGTH,
    error('Behavior name length = %d > %d\n',behaviorname_length,MAXSTRINGLENGTH);
  end
  behaviorname = fread(fid,behaviorname_length,'char=>char')';
  behaviornames{i} = behaviorname;
end
nbouts = fread(fid,1,'int');
data = fread(fid,nbouts*3,'int');
fclose(fid);

% assuming startframes and endframes are relative -- CHECK THIS
startframes = data(1:3:end-2);
endframes = data(2:3:end-1);
behavioridx = data(3:3:end);
startframes = startframes+1;
endframes = endframes+1;
behavioridx = behavioridx+1;

% initialize everything as None
labelidx0 = repmat(2,[1,nframes]);
isunknown = ismember(behaviornames,{'*Unknown*','*Tracker Failure*'});
isnone = strcmpi(behaviornames,'None');
idx_behavior = find(~isunknown&~isnone);
idx = find(isunknown(behavioridx));
% set unknown labels
for i = idx(:)',
  labelidx0(startframes(i):endframes(i)-1) = 0;
end
idx = find(isnone(behavioridx));
% set none labels
for i = idx(:)',
  labelidx0(startframes(i):endframes(i)-1) = 2;
end

labels = cell(1,numel(idx_behavior));
behaviors = cell(1,numel(idx_behavior));
timestamp = now;
for ii = 1:numel(idx_behavior),
  i = idx_behavior(ii);
  labelidx = labelidx0;
  idx = find(behavioridx == i);
  for j = idx(:)',
    labelidx(startframes(j):endframes(j)-1) = 1;
  end

  behaviors_curr = {behaviornames{i},'None'};
  labels_curr = struct;
  labels_curr.t0s = [];
  labels_curr.t1s = [];
  labels_curr.names = {};
  labels_curr.timestamp = [];
  labels_curr.flies = fly_ids;
  labels_curr.imp_t0s = [];
  labels_curr.imp_t1s = [];
  labels_curr.off = 1-firstframe;

  for j = 1:2,
    [i0s,i1s] = get_interval_ends(labelidx==j);
    if ~isempty(i0s),
      n = numel(i0s);
      labels_curr.t0s(end+1:end+n) = i0s + firstframe - 1;
      labels_curr.t1s(end+1:end+n) = i1s + firstframe - 1;
      labels_curr.imp_t0s(end+1:end+n) = i0s + firstframe - 1;
      labels_curr.imp_t1s(end+1:end+n) = i1s + firstframe - 1;

      labels_curr.names(end+1:end+n) = repmat(behaviors_curr(j),[1,n]);
      labels_curr.timestamp(end+1:end+n) = timestamp;
    end
  end

  labels{ii} = labels_curr;
  behaviors{ii} = behaviornames{i};

end


% -*- INTERNAL UNDOCUMENTED FUNCTION -*-
function [geometry, msh, sp, u, gnum] = ...
              mp_solve_laplace_2d (problem_data, method_data)

warning ('geopdes:obsolete', 'Function MP_SOLVE_LAPLACE_2D is obsolete. Using MP_SOLVE_LAPLACE instead')

[geometry, msh, sp, u, gnum] = mp_solve_laplace (problem_data, method_data);


function [obj] = ft_convert_coordsys(obj, target, method, template)

% FT_CONVERT_COORDSYS changes the coordinate system of the input object to
% the specified coordinate system. The coordinate system of the input
% object is determined from the structure field object.coordsys, or needs to
% be determined and specified interactively by the user.
%
% Use as
%   [object] = ft_convert_coordsys(object)
% to only determine the coordinate system, or
%   [object] = ft_convert_coordsys(object, target)
%   [object] = ft_convert_coordsys(object, target, method)
%   [object] = ft_convert_coordsys(object, target, method, template)
% to determine and convert the coordinate system.
%
% With the optional method input argument you can determine whether to use
% SPM for an affine or non-linear transformation. This option is passed on
% to the private functions: align_ctf2acpc and align_neuromag2acpc.
%
% The following input objects are supported
%   anatomical mri, see FT_READ_MRI
%   anatomical or functional atlas, see FT_READ_ATLAS
%   (not yet) electrode definition
%   (not yet) gradiometer array definition
%   (not yet) volume conductor definition
%   (not yet) dipole grid definition
%
% Possible input coordinate systems are 'ctf', 'bti', '4d', 'neuromag' and 'itab'.
% Possible target coordinate systems are 'acpc'.
%
% Note that the conversion will be an automatic one, which means that it
% will be an approximate conversion, not taking into account differences in
% individual anatomies/differences in conventions where to put the
% fiducials.
%
% See also FT_DETERMINE_COORDSYS, ALIGN_CTF2ACPC, ALIGN_NEUROMAG2ACPC, ALIGN_FSAVERAGE2MNI

% Copyright (C) 2005-2011, Robert Oostenveld & Jan-Mathijs Schoffelen
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

if ~isfield(obj, 'coordsys') || isempty(obj.coordsys)
  % determine the coordinate system of the input object
  obj = ft_determine_coordsys(obj, 'interactive', 'yes');
end

if ~isfield(obj, 'coordsys') || isempty(obj.coordsys)
  % the call to ft_determine_coordsys should have taken care of this, but
  % it is possible that the user aborted the coordinate system
  % determination. See http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=2526
  ft_error('the coordinate system of the geometrical object is not specified');
end

if any(strcmp(target, {'spm', 'mni', 'tal'}))
  % see http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3304
  ft_warning('Not applying any scaling, using ''acpc'' instead of ''%s''. See http://bit.ly/2sw7eC4', target);
  target = 'acpc';
end

% set default behavior to use an approximate alignment, followed by a call
% to spm_normalise for a better quality alignment
if nargin<3
  method = 2;
end

if isdeployed && (method==1 || method==2)
  needtemplate = true;
else
  needtemplate = false;
end

if needtemplate && nargin<4
  ft_error('you need to specify a template filename for the coregistration');
end

hastemplate = nargin>3;

if nargin>1 && ~strcmpi(target, obj.coordsys)
  % convert to the desired coordinate system
  switch target
    case 'acpc'
      switch obj.coordsys
        case {'ctf' 'bti' '4d'}
          fprintf('converting the coordinate system from %s to %s\n', obj.coordsys, target);
          if hastemplate
            obj = align_ctf2acpc(obj, method, template);
          else
            obj = align_ctf2acpc(obj, method);
          end
        case {'itab' 'neuromag'}
          fprintf('converting the coordinate system from %s to %s\n', obj.coordsys, target);
          if hastemplate
            obj = align_neuromag2acpc(obj, method, template);
          else
            obj = align_neuromag2acpc(obj, method);
          end
        case {'mni', 'fsaverage'}
          fprintf('not converting the coordinate system from %s to %s, these are similar enough\n', obj.coordsys, target);
          % these are close enough to ACPC, so nothing needs to be done
        otherwise
          ft_warning('conversion from %s to %s is not supported', obj.coordsys, target);
      end % switch obj.coordsys
    otherwise
      ft_error('conversion from %s to %s is not supported', obj.coordsys, target);
  end % switch target
end


function [size1, size2] = size(f, varargin)
%SIZE   Size of a CLASSICFUN.
%   SIZE(F), where F is a CLASSICFUN, is the size of the ONEFUN of F.
%
% See also LENGTH.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% The size of a CLASSICFUN is the size of its onefun.
if ( nargout <= 1 )
    size1 = size(f.onefun, varargin{:});
else
    [size1, size2] = size(f.onefun, varargin{:});
end

end


function savetovariable = chipfile( compleximagefile, outfile, varargin )
%CHIPFILE Saves an AOI from a complex image to file or variable
%
%    chipfile(compleximagefile, outfile, 'PropertyName',PropertyValue,...)
%
%       Property name     Description
%       azlimits          Min and max samples in azimuth over which to
%                            compute (default = query user with GUI).  Use
%                            'full' to specify entire range.  If nothing is
%                            selected, a MATLAB GUI will be used to select
%                            an area.
%       rnglimits         Min and max lines in range over which to compute
%                            (default = query user with GUI).  Use 'full'
%                            to specify entire range.  If nothing is
%                            selected, a MATLAB GUI will be used to select
%                            an area.
%       framenumber       Frame to process if a multi-image file.  Default
%                            is 1.
%       file_format       Format of output file.  'SIO', 'SICD', or 'NRL'.
%                            Default is SICD.
%       block_size        Determines how many bytes are in memory at once.
%                            Set to Inf to read whole image at once.
%                            Default is about 50 Mbytes.
%
% Optionally one can also use this function to chip a file to a variable in
% memory:
%    savetovariable = chipfile(compleximagefile);
%
% Written by: Wade Schwartzkopf, NGA/IDT
%
% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////

% Select input image through GUI if not provided (and save path)
if (nargin<1)||isempty(compleximagefile)
    % Recall last interactively selected path used
    if ispref('matlab_sar_toolbox','last_used_directory')
        pathname = getpref('matlab_sar_toolbox','last_used_directory');
        if ~ischar(pathname)||~exist(pathname,'dir')
            pathname = pwd;
        end
    else
        pathname = pwd;
    end
    [compleximagefile,pathname]=uigetfile(sar_file_extensions('complex'),...
        'Select Input File',pathname);
    if(~compleximagefile), return; end; % Cancel was chosen
    setpref('matlab_sar_toolbox','last_used_directory',pathname);
    compleximagefile=fullfile(pathname,compleximagefile);
else
    pathname=fileparts(which(compleximagefile));
end

% Select output image through GUI if not provided (and save path)
default_filetype = 'SICD'; % If not chosen through file GUI
if ((nargin<2)||isempty(outfile))&&(nargout==0)
    [outfile,pathname,filterindex]=uiputfile(...
        {'*.ntf','SICD (*.ntf)'; '*.sio','SIO (*.sio)'; '*.iq8','NRL (*.iq8)'},...
        'Select output filename',pathname);
    if(~outfile), return; end; % Cancel was chosen
    exts = {'SICD','SIO','NRL'};
    default_filetype = exts{filterindex};
    outfile=fullfile(pathname,outfile);
end

% Parse input parameters
p = inputParser;
p.KeepUnmatched=true;
p.addParamValue('azlimits','default');
p.addParamValue('rnglimits','default');
p.addParamValue('framenumber',1);
p.addParamValue('file_format',default_filetype);
p.addParamValue('block_size',2^26); % in bytes
p.FunctionName = mfilename;
p.parse(varargin{:});
azlimits=p.Results.azlimits;
rnglimits=p.Results.rnglimits;
framenumber=p.Results.framenumber;
if(strcmpi(azlimits,'default')&&strcmpi(rnglimits,'default'))
    [aoi_info, framenumber]=mitm_viewer(compleximagefile,'mode','aoi',...
        'closeAfterSelect',true);
    if ~isempty(aoi_info) % User may have closed viewer without selecting AOI
        azlimits=[aoi_info(1) aoi_info(1)+aoi_info(3)-1];
        rnglimits=[aoi_info(2) aoi_info(2)+aoi_info(4)-1];
    else
        savetovariable = []; return;
    end
end
reader_object=open_reader(compleximagefile);
if iscell(reader_object)
    reader_object = reader_object{framenumber};
end
meta = reader_object.get_meta();
if(isempty(azlimits)||any(strcmpi(azlimits,{'full','default'})))
    azlimits=[1 double(meta.ImageData.NumCols)];
end
if(isempty(rnglimits)||any(strcmpi(rnglimits,{'full','default'})))
    rnglimits=[1 double(meta.ImageData.NumRows)];
end
save_to_file=exist('outfile','var')&&~isempty(outfile); % Will be saving chip to file
if save_to_file
    if ~isfield(meta.ImageData, 'PixelType')
        meta.ImageData.PixelType = 'RE32F_IM32F'; % Default type
    end
    % Update SICD coordinates to reflect chip area within larger image
    meta.ImageData.NumRows = uint32(diff(rnglimits)+1);
    meta.ImageData.NumCols = uint32(diff(azlimits)+1);
    meta.ImageData.FirstRow = uint32(meta.ImageData.FirstRow + rnglimits(1) - 1);
    meta.ImageData.FirstCol = uint32(meta.ImageData.FirstCol + azlimits(1) - 1);
    meta = add_sicd_corners(meta); % Update corners coords
    switch p.Results.file_format
        case 'SIO'
            writer_object=SIOWriter(outfile, meta);
        case 'SICD'
            writer_object=SICDWriter(outfile, meta);
        case 'NRL'
            writer_object=NRLWriter(outfile, meta);
        otherwise
            % Error
    end
end
if nargout>0, savetovariable=zeros(diff(azlimits)+1,diff(rnglimits)+1); end; % Saving to variable in memory

% Do chipping
first_row_in_block=rnglimits(1);
num_rows_in_block=max(1,floor(p.Results.block_size/((diff(azlimits)+1)*8))); % Assume 8-byte elements (largest allowed in SICD)
wb_hand=waitbar(0,'Chipping data...');
while(first_row_in_block<rnglimits(2))
    row_indices=first_row_in_block:min(rnglimits(2),first_row_in_block+num_rows_in_block-1);
    image_block = reader_object.read_chip(azlimits,row_indices([1 end]));
    if nargout>0, savetovariable(:,row_indices-rnglimits(1)+1)=image_block; end;
    if save_to_file
        writer_object.write_chip(image_block, [1 (first_row_in_block-rnglimits(1)+1)]);
    end
    first_row_in_block=row_indices(end)+1;
    waitbar(double(first_row_in_block-rnglimits(1))/double(diff(rnglimits)+1),wb_hand);
end
close(wb_hand);
reader_object.close();
% writer_object will close itself upon leaving this function

% //////////////////////////////////////////
% /// CLASSIFICATION: UNCLASSIFIED       ///
% //////////////////////////////////////////


function result = set_concat(varargin)
% Concatenate continuous signals across time.
% Result = set_joinepos(Set1, Set2, ...)
%
% In:
%   SetK   : The k'th data set to concatenate.
%
% Out:
%   Result : A new data set that is the concatenation of all input sets. The following changes are made:
%            * .data and all other time-series fields are concatenated across time (2nd dimension)
%            * .event is joined and .latency fields are updated appropriately
%            * .xmax/.pnts are updated
%
% Notes:
%   This function returns a new data set with meta-data set to that of the first input set, and the
%   time series fields joined across all sets. No checks for meta-data consistency are done. There
%   is a heavy-duty function for merging inconsistent sets called set_merge, which can merge cats
%   and dogs. This function does not attempt to keep miscellaneous EEGLAB meta-data consistent,
%   including: setname,filename,filepath,subject,group,condition,session,comments,urevent,reject,stats,history,etc
%
% Examples:
%   % concatenate data sets eegA, eegB and eegC across time
%   eeg = set_concat(eegA,eegB,eegC)
%
% See also:
%   set_joinepos, set_merge
%
%                                Christian Kothe, Swartz Center for Computational Neuroscience, UCSD
%                                2010-03-31
dp;

% set_concat_version<1.0> -- for the cache

if ~exp_beginfun('editing') return; end

declare_properties('name','Concatenate','independent_channels',true,'independent_trials',false);

% input validation
for k=1:length(varargin)
    utl_check_fields(varargin{k},{'data','event','pnts','xmin','xmax','srate'},'input','signal');
    if ~isempty(varargin{k}.event)
        if ~isfield(varargin{k}.event,'latency')
            error('A dataset passed to set_concat is lacking the .event.latency field.'); end
        latency_numels = cellfun('prodofsize',{varargin{k}.event.latency});
        if any(latency_numels == 0)
            error('One or more of the events in the given data set have an empty .latency field, which is not permitted.'); end
        if any(latency_numels ~= 1)
            error('One or more of the events in the given data set have a .latency value that is not a scalar, which is not permitted.'); end
    end
    if isfield(varargin{k},'epoch') && ~isempty(varargin{k}.epoch)
        error('Only continuous data can be concatenated with set_concat -- use set_joinepos for epoched data.'); end
end

if ~isempty(varargin)
    result = varargin{1};
    if length(varargin) > 1
        % concatenate time series fields
        for field = utl_timeseries_fields(result)
            data = cellfun(@(x)x.(field{1}),varargin,'UniformOutput',false);
            try
                result.(field{1}) = cat(2,data{:});
            catch e
                % concatenation failed: produce a reasonable error message
                if ~isempty(data)
                    sizes = cellfun('size',data,1);
                    sizes = sizes(sizes ~= 0);
                    if length(sizes) > 1 && ~all(sizes==sizes(1))
                        error('The time-series field .%s must have the same number of channels in each data set.',field{1}); end
                    if any(cellfun('size',data,3) > 1)
                        error('One or more of the datasets passed to set_concat were epoched -- use set_joinepos to concatenate epoched data.'); end
                end
                size_info = hlp_tostring(cellfun(@size,data,'UniformOutput',false));
                error('Concatenation of time-series fields failed with error: %s (the data sizes were %s -- make sure that they are mutually compatible).',e.message,size_info);
            end
            if isempty(result.(field{1}))
                result.(field{1}) = []; end
        end
        % count events, epochs and samples in each set
        event_count = cellfun(@(x)length(x.event),varargin);
        sample_count = cellfun(@(x)x.pnts,varargin);
        % concatenate .event and .epoch fields
        event = cellfun(@(x)x.event,varargin,'UniformOutput',false); result.event = [event{:}];
        % shift event latencies based on cumulative sample counts
        if ~isempty(result.event)
            [result.event.latency] = arraydeal([result.event.latency]+replicate(cumsum(sample_count)-sample_count,event_count)); end
        % update misc fields
        [result.nbchan,result.pnts,result.trials,extra_dims] = size(result.data); %#ok<ASGLU,NASGU>
        result.xmax = result.xmin + (result.pnts-1)/result.srate;
    end
else
    result = struct('setname','','filename','','filepath','','subject','','group','','condition','','session',[],'comments','','nbchan',0,...
        'trials',0,'pnts',0,'srate',1,'xmin',0,'xmax',0,'times',[],'data',[],'icaact',[],'icawinv',[],'icasphere',[],'icaweights',[], ...
        'icachansind',[],'chanlocs',[],'urchanlocs',[],'chaninfo',[],'ref',[],'event',[],'urevent',[],'eventdescription',{{}}, ...
        'epoch',[],'epochdescription',{{}},'reject',[],'stats',[],'specdata',[],'specicaact',[],'splinefile','','icasplinefile','', ...
        'dipfit',[],'history','','saved','no','etc',[]);
end

exp_endfun;

function result = replicate(values,counts)
% Replicate each element Values(k) by Count(k) times.
result = zeros(1,sum(counts));
k = 0;
for p=find(counts)
    result(k+(1:counts(p))) = values(p);
    k = k+counts(p);
end


function w = loadsac(w, filename)
   %LOADSAC  creates a waveform from a SAC file
   %
   % old usage, use waveform with a datasource instead
   %
   % waveform = loadsac(waveform, filename);
   % To call, the first argument must be a waveform.  However this waveform
   % will never be accessed-- it will be overwritten by the SAC information.
   % Therefore, you can use "waveform" as your first argument, so that a
   % generic waveform object will be created for you
   %
   % If the filename is a cell of several SAC file names, such as:
   % fn = {'BOB.SHZ.AV','TOM.EHZ.AV','HARRY.EHZ.AV'}
   % then, w = loadsac(waveform,fn) will return a matrix of waveforms, the
   % same size and shape  as fn.   fn(N,M) will be the SAC file name for the
   % waveform denoted by w(N,M).  In the example above, loadsac will return a
   % 1x3 waveform object, with all three files.
   %
   % Programming suggestion?select files using a dialog box, by using the
   % following code:
   %   % display the dialog box used for selecting files, and
   %   % allow for multiple selections
   %   [f,d] = uigetfile({'*.*','all Files (*.*)'}, 'MultiSelect', 'on');
   %
   %   % f will have one or more file names, so concatenate them
   %   % with the directory
   %   filename = strcat(d,f);
   %
   %   %call loadsac to load all these files into waveform objects
   %   w = loadsac(waveform, filename);
   %
   % The SAC header is parsed out, with the following equivelent fields used
   % by waveform:
   % _waveform_ 	_sac_
   % STATION		KSTNM
   % CHANNEL		KCMPNM
   % FREQUENCY		1 / DELTA (ODELTA is not used)
   % START			NZYEAR, NZJDAY, NZHOUR, NZMIN, NZSEC, NZMSEC, B
   % UNITS			IDEP is parsed.  IUNK becomes "Counts"
   % All header fields with values - that is, header fields that do not
   % contain the value  -12345 (either numeric or text) - are put into
   % user-defined fields within the waveform.
   % These fields can then be accessed via get/set.  User-defined fields
   % does not include those that are parsed into waveform's predefined  fields
   %
   % For more information about the SAC header, and the interpretation of the
   % fields, check out Lawrence Livermore's web site.  Search for "seismic
   % sac" and you'll find it.
   %
   % -------------------------------------------------------------------------
   % The functionality of loadsac has been redistributed to the datasource
   % class.  This will allow greater flexibility in traversing directory/file
   % structures and loading arbitrary time-ranges from the SAC files.
   % -------------------------------------------------------------------------
   %
   %  Here are examples of loading sac files using the datasource class
   %  sacfile of interest: "2008/myfile.MSOM.035.sac"
   %
   % % here is a datasource that finds files such as:"2008/myfile.MSOM.035.sac"
   % ds = datasource('sac',...        % type of data
   %    '%04d/myfile.%s.%03d.sac',... % filename described in sprintf terms
   %    'year','station','jday');     % used to determine filename at runtime
   %
   % %  and here is a datasource tied to a specific file
   % ds2 = datasource('sac','specificpath/specificfilename');
   %
   % %     Here's a scnlobject filled with wildcards,
   % %     that will grab any station or channel
   % anyscnl = scnlobject('*','*','*','*');
   %
   % %     and here's one that is specific to our station of interest
   % scnl = scnlobject('MSOM','BHZ','AV'); %% specific station
   %
   % % load any station for a timespan of interest
   % w = waveform(ds,anyscnl,'2/4/2008 04:40','2/4/2008 04:53');
   %    or
   % % load our specific sacfile, making sure to grab the whole thing
   % w = waveform(ds2,anyscnl,'1/1/2000','12/31/2009');

   % VERSION: 1.1 of waveform objects
   % AUTHOR: Celso Reyes
   % LASTUPDATE: 3/14/2009

   w = load_sac(filename);
end


function prior = truncatedGammaPriorExpandParam(prior, params)

% TRUNCATEDGAMMAPRIOREXPANDPARAM Expand truncated gamma prior structure from params.

% PRIOR

prior.a = params(1);
prior.b = params(2);


function input = handle_edit_input(text)

% HANDLE_EDIT_INPUT deals with user-entered input in the GUI. This is used to select
% channels and/or trials in FT_REJECTVISUAL and to select channels in FT_DATABROWSER
%
% The input text can consist of a string such as
%   1 2 3 4
%   1:4
%   [1 2 3 4]
%   [1:4]
% This is converted in a list of numbers.
%
% The input text can also consist of a single non-numeric string or a string that
% represents a cell-array of strings such as
%   all
%   {'MEG', '-MR*'}

% Copyright (C) 2022, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

if isempty(text)
  input = [];
elseif all(ismember(text, '0123456789 \t'))
  input = regexp(text, '\s+', 'split');
  input = cellfun(@str2num, input);
elseif ismember(text(1), '0123456789')
  input = eval(text); % it could be a single number or a string like 1:10
elseif startsWith(text, '[') && endsWith(text, ']')
  input = eval(text);
elseif startsWith(text, '{') && endsWith(text, '}')
  input = eval(text); % this allows for {'MEG', '-MR*'}
else
  input = text;
end


function mv = mv_selectPlotType(type);
%
% mv = mv_selectPlotType(type);
%
% Set the Multi Voxel UI to plot the selected plot
% type.
%
% Default types are:
% 1) Plot the whole time courses for each voxel, after
%    detrending/preprocessing.
% 2) Plot the time courses for each trial and condition,
%    averaged across voxels.
% 3) Plot the time courses for each voxel and condition,
%    averaged across trials.
% 4) Plot the mean amplitudes for each voxel and condition,
%    averaged across trials.
% 5) Plot the mean amplitudes for each trial, voxel, and condition.
% 6) d' histograms [n. y. i.]
% 7) Visualize GLMs for each voxel (w/ slider to page between voxels)
%
% ras, 04/05.
mv = get(gcf,'UserData');
mv.ui.plotType = type;
set(gcf, 'UserData', mv);

% clear previous objects in the figure
old = findobj('Type', 'axes', 'Parent', gcf);
old = [old; findobj('Type', 'uicontrol', 'Parent', gcf)];
old = [old; findobj('Tag', 'GLM Display Panel', 'Parent', gcf)];
delete(old);

% hide GLM control panel if we're not visualizing this
if type ~= 7
    mrvPanelToggle(mv.ui.glmPanel, 'off');
end

% make only the selected option checked
if checkfields(mv, 'ui', 'plotHandles')
    set(mv.ui.plotHandles, 'Checked', 'off')
    set(mv.ui.plotHandles(type), 'Checked', 'on');
end

% multiVoxelUI;

return


function [imageSpm4DArray, selectionArray] = split_into_MrImageSpm4D(this, dimLabelsSpm4D)
% Splits high dimensional MrImage (>4) into array of 4D MrImageSpm4D
% objects to be used for SPM interfacing
%
%   Y = MrImage(); % >4 dimensions
%   imageSpm4DArray = Y.split_into_MrImageSpm4D(inputs)
%
% This is a method of class MrImage.
%
% IN
%   dimLabelsSpm4D      cell(1,4) of dimLabels that shall represent the 1st
%                       four dimensions that will be in each element of the
%                       output 4D SPM-compatible image array
%                       default: {'x','y','z','t'}
%                       NOTE: If less than 4 dimensions are specified, the
%                             remaining up to 4th dimension is included in
%                             the 4D images
%                             e.g.
%                               specified: {'x','y','z','t'}
%                               actual dimLabels:  {'x','z','echo', 'y', 'coil'}
%                               => {'x','y','z','echo'} will be in 4D image
%                       NOTE2: If certain labels do not exist, the
%                              existing dimensions later in the array are
%                              moved up in their dimension
%                               e.g.,
%                               specified: {'x','y','z','t'}
%                               actual dimLabels:  {'x','y','coil', 't', 'echo'}
%                               => {'x','y','t','coil'} will be in 4D image
%
% OUT
%   imageSpm4DArray         cell(nElementsSplitDim1, ..., nElementsSplitDimN) of
%                           MrImageSpm4D, split along splitDims,
%                           e.g. 6-D MrImage of 4D time series with
%                           16 coils and 3 echoes will result in a 16x3
%                           cell of MrImageSpm4D
%   selectionArray
%                           cell(nElementsSplitDim1, ..., nElementsSplitDimN) of
%                           selections, defined as cells containing propertyName/value
%                           pairs over split dimensions, e.g.
%                           {'t', 5, 'dr', 3, 'echo', 4}
%
% EXAMPLE
%   split_into_MrImageSpm4D
%
%   See also MrImage

% Author:   Saskia Bollmann & Lars Kasper
% Created:  2018-05-03
% Copyright (C) 2018 Institute for Biomedical Engineering
%                    University of Zurich and ETH Zurich
%
% This file is part of the TAPAS UniQC Toolbox, which is released
% under the terms of the GNU General Public License (GPL), version 3.
% You can redistribute it and/or modify it under the terms of the GPL
% (either version 3 or, at your option, any later version).
% For further details, see the file COPYING or
%  <http://www.gnu.org/licenses/>.

if nargin < 2
    dimLabelsSpm4D = {'x','y','z','t'};
end

%% permute dimLabelsSpm4D as first 4 dimensions
permutedThis = this.permute(this.dimInfo.get_dim_index(dimLabelsSpm4D));

%% split along all higher dimensions, keep chunks of 1st four together
[imageSpm4DArray, selectionArray] = permutedThis.split('splitDims', 5:this.dimInfo.nDims, ...
    'doRemoveDims', false); % dimInfo for singleton dimension kept to facilitate later recombination; MrImageSpm4D is more of an internal class
nImages = numel(imageSpm4DArray);
for iImage = 1:nImages
    imageSpm4DArray{iImage} = imageSpm4DArray{iImage}.recast_as_MrImageSpm4D;
end


function handle = xyzhumanevaVisualise2(pos,fid)

% XYZHUMANEVAVISUALISE2
%
% COPYRIGHT : Carl Henrik Ek and Neil Lawrence, 2008

% MOCAP

if(nargin<2)
  fid = 2;
end

figure(fid);

% determine parametrization
if(max(max(abs(pos)))<100)
  type = 'jon';
else
  type = 'raquel';
end

joint = xyzhumaneva2joint(pos);
handle{1} = xyzhumanevaDraw(joint);axis equal;view([1 0 0]);
switch type
 case 'raquel'
  set(gca,'XLim',[-300 300],'YLim',[-300 300],'ZLim',[-800 800]);
 case 'jon'
  set(gca,'XLim',[-0.35 0.35],'YLim',[-0.35 0.35],'ZLim',[-1 0.3]);
end

figure(fid+2);
handle{2} = xyzhumanevaDraw(joint);axis equal;view([1 1 1]);
switch type
 case 'raquel'
  set(gca,'XLim',[-300 300],'YLim',[-300 300],'ZLim',[-800 800]);
 case 'jon'
  set(gca,'XLim',[-0.35 0.35],'YLim',[-0.35 0.35],'ZLim',[-1 0.3]);
end

return


%% Example
% An example script, it is used to show how to use the different
% functions of the KUKA iiwa matlab toolbox
% First start the server on the KUKA iiwa controller
% Then run the following script in Matlab

% Mohammad SAFEEA, 3rd of May 2017

close all,clear all,clc

ip='172.31.1.147'; % The IP of the controller
% start a connection with the server
t_Kuka=net_establishConnection( ip );

if ~exist('t_Kuka','var') || isempty(t_Kuka) || strcmp(t_Kuka.Status,'closed')
  warning('Connection could not be establised, script aborted');
  return;
else

    %% move to initial position
pinit={0,pi*20/180,0,-pi*70/180,0,pi*90/180,0}; % initial confuguration
relVel=0.15; % relative velocity
movePTPJointSpace( t_Kuka , pinit, relVel); % point to point motion in joint space

      %% PTP motion
      jPos={}
      homePos={}
     [ jPos ] = getJointsPos( t_Kuka ) % get current joints position

      for ttt=1:7  % home position
          homePos{ttt}=0;
      end

      pause(0.1)
      relVel=0.15;
      movePTPJointSpace( t_Kuka , homePos, relVel); % go to home position
      pause(0.1)
      movePTPJointSpace( t_Kuka , jPos, relVel); % return back to original position

      %% turn off the server
       net_turnOffServer( t_Kuka );

       fclose(t_Kuka);
end


function varargout = expression( nm, varargin )

%EXPRESSION Declares a single CVX object for storing subexpressions.
%   EXPRESSION x
%   where x is a valid MATLAB variable nm, declares a scalar expression
%   holder for the current cvx model. Like a variable, an expression holder
%   can be used in constraints and objectives, according to the DCP ruleset.
%   However, unlike a variable, an expression holder is initialized to
%   zero, because the intent is for it to hold intermediate computations.
%
%   EXPRESSION x(n1,n2,...,nk)
%   declares a vector, matrix, or array expression holder with dimensions
%   n1, n2, ..., nk, each of which must be nonnegative integers. The value
%   of the expression holder is initialized to zero.
%
%   Examples:
%      variable x y
%      expression z
%      z = 2 * x - y;
%
%   See also EXPRESSIONS.

global cvx___
prob = evalin( 'caller', 'cvx_problem', '[]' );
if ~isa( prob, 'cvxprob' ),
    error( 'No CVX model exists in this scope.' );
elseif isempty( cvx___.problems ) || cvx___.problems( end ).self ~= prob,
    error( 'Internal CVX data corruption. Please CLEAR ALL and rebuild your model.' );
elseif nargin > 1,
    error( 'Too many input arguments.\nTrying to declare multiple expression holders? Use the EXPRESSIONS keyword instead.', 1 ); %#ok
end

%
% Step 1: separate the name from the parenthetical, verify the name
%

toks = regexp( nm, '^\s*([a-zA-Z]\w*)\s*(\(.*\))?\s*$', 'tokens' );
if isempty( toks ),
    error( 'Invalid variable specification: %s', nm );
end
toks = toks{1};
x.name = toks{1};
x.size = toks{2};
if x.name(end) == '_',
    error( 'Invalid expression specification: %s\n   Names ending in underscores are reserved for internal use.', nm );
end

%
% Step 2: Parse the size. In effect, all we do here is surround what is
% replace the surrounding parentheses with square braces and evaluate. All
% that matters is the result is a valid size vector. In particular, it
% need to be a simple comma-delimited list.
%

if isempty( x.size ),
	x.size = [1,1];
else
    try
        x.size = evalin( 'caller', [ '[', x.size(2:end-1), '];' ] );
    catch exc
        error( exc.identifier, exc.message );
    end
    [ temp, x.size ] = cvx_check_dimlist( x.size, true );
    if ~temp,
        error( 'Invalid expression specification: %s\n   Dimension list must be a vector of finite nonnegative integers.', nm );
    end
end

%
% Step 3. Initialize
%

v = cvx( x.size, [] );
if nargout > 0,
    varargout{1} = v;
else
    assignin( 'caller', x.name, v );
end

% Copyright 2005-2016 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.