%% imx
% Below is a demonstration of the features of the |imx| function

%%
clear; close all; clc;

%% Syntax
% |hf=imx(varargin);|

%% Description
% The imx (image explorer) function is a GUI to navigate and segment 3D
% image data.

%% Examples
%
%% Example: Segmenting MRI data

%%
% Get a 3D image (see also |dcmFolder2MATobject| to import DICOM data)
testCase=2;

defaultFolder = fileparts(fileparts(mfilename('fullpath'))); %Set main folder
loadSavePath=fullfile(defaultFolder,'data','imseg'); %Path for loading and saving segmentation data
switch testCase
    case 1 %MATLAB brain data
        load mri;
        M=squeeze(D); %example image data set
        v=2./[1,1,.4]; %example voxel size
    case 2 %MRI imported from DICOM files, see also HELP_dcmFolder2MATobject
        pathName=fullfile(defaultFolder,'data','DICOM','0001_human_calf');
        loadName=fullfile(pathName,'IMDAT','IMDAT.mat');

        IMDAT_struct=load(loadName); %The image data structure
        G = IMDAT_struct.G; %Geometric/spatial information
        v = G.v; %The voxel size
        M = IMDAT_struct.type_1; %The image data
end

%%
% Start segmentation using |imx|
hf=imx(M,v,loadSavePath);

%%
% *Viewing*
%
% * _Toolbar_ - Note all functions displayed in the graphical user
% interface toolbar, equipt with an information panel and descriptions
% of keyboard shortcuts just below the toolbar.
% Instructions for each widget will appear along this top bar when in use.
% Right click to exit from any given widget.
%
% * _View manipulation_ - Use the View Control Widget to zoom, pan, and
% rotate a figure using different mouse gestures (right mouse button
% for zoom, left for panning, and middle/scroll for rotating).
% Use the sliding bars on the left hand side of the graphical user
% interface to change slice view from all 3 axes.
% Press home to return to active slice.
% Use the colorbar button to change the limits of the color axis displayed
% below the slice, shifting the color contrast across a slice and
% increasing the visibility of contour lines.
%
% <<HELP_imx_View.gif>>
%
% *Sketching a contour*
%
% * _Sample_ - Begin segmenting an element with s = sample sketch contour.
% With the activated widget, click on an area of contrast that outlines the
% element to generate an approximate dotted contour. If the generated outline is
% unsuitable, click elsewhere along the contrast to produce a new contour.
% Once the sample contour is acceptable, right click out of the
% widget. See below for an example of this process in segmenting the skin.
%
% <<HELP_imx_Sample.gif>>
%
% * _Cut_ - Use c = cut sketched contour to edit a sample sketch by
% boxing and removing an incorrect section of the outline.
%
% <<HELP_imx_Cut.gif>>
%
% * _Draw_ - After cutting a portion of a sample sketch, use the drawing
% tool to complete the sketch if needed. Use d = draw contour to
% place connected sketch points along a contour where the path needs to be filled in.
% After exiting the widget, observe that the drawn sketch will be in a
% different color compared to the original.
%
% <<HELP_imx_Draw.gif>>
%
% * _Adjust_ - To edit the alignment of certain points along a bad contour,
% use the adjust tool. To move a sketch point to a new location, click on
% the point and then click on its new placement.
%
% <<HELP_imx_Adjust.gif>>
%
% * _Delete_ - Use the delete tool to erase any sketch contour on the
% slice.
%
% <<HELP_imx_Delete.gif>>
%
%
% *Accepting a contour*
%
% * _Select_ - Once a sketch contour is well fit to an element on the given
% slice, use a = accept contour to select the contour, changing it to a
% solid green path. If multiple sketches exist on the slice, select your
% desired option from the displayed window to either add a new contour,
% merge with another contour, or replace the existing accepted contours.
% See below for an example of merging multiple contours of interest.
%
% <<HELP_imx_Accept.gif>>
%
% * _Convert_ - Use the convert button to easily switch from an accepted
% contour back to a sketch contour if further adjustments are needed. Use
% the reset button to return to the original, unsegmented slice.
%
% <<HELP_imx_Convert.gif>>
%
% * _Grow/Shrink_ - Use + = grow contour and - = shrink contour to
% manipulate the size of an accepted contour to best fit a given element.
% Growing and shrinking contour lines will likely wrinkle the path and
% require smoothing (see Smooth).
%
% <<HELP_imx_GrowShrink.gif>>
%
% * _Smooth_ - Use q = smooth accepted contour to smoothen a contour path.
% If more extreme smoothing is necessary, press p while the smoothing tool
% is activated to adjust the smoothing parameter accordingly.
%
% <<HELP_imx_Smooth.gif>>
%
% *Finalizing segmentation* - After the slice is complete, press space to
% go to the next slice and continue segmentation for all MRI slices.
% Periodically check the view of all slices using the showHide tool to
% verify continuity along the length of an element until completion.
%
% <<HELP_imx_ShowHide.gif>>
%

%%
%
% <<gibbVerySmall.gif>>
%
% _*GIBBON*_
% <www.gibboncode.org>
%
% _Kevin Mattheus Moerman_, <gibbon.toolbox@gmail.com>

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program 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.
%
% This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.


%EVALINIT Calculates initial solution vector from given expressions.
%
%   [ U0 ] = EVALINIT( PROB, C_EXPR ) Given a valid PROB struct
%   evaluates the inital value expressions in C_EXPR (or PHYS struct
%   if C_EXPR is not given), and returns a solution vector U0.
%
%   See also EVALEXPR

% Copyright 2013-2022 Precise Simulation, Ltd.


function xs=delif(x,t);
% DELIF
% DELIF(x,t) deletes the rows of x for which t=1
% x: NxK matrix, t: Nx1 matrix of 0's and 1's
nt=repmat(1-t,1,rows(x'));
nx=x.*nt;
xs=nx(nx~=0);
col=rows(x');
xs=reshape(xs,rows(xs)/col,col);


function sphere_voronoi_test ( )

%*****************************************************************************80
%
%% SPHERE_VORONOI_TEST tests the SPHERE_VORONOI library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    30 April 2010
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'SPHERE_VORONOI_TEST\n' );
  fprintf ( 1, '  MATLAB version:\n' );
  fprintf ( 1, '  Test the SPHERE_VORONOI library.\n' );

  sphere_voronoi_test01 ( );
  sphere_voronoi_test02 ( );
  sphere_voronoi_test03 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'SPHERE_VORONOI_TEST:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


classdef Par < handle
  % Par  TIC-TOC class for parfor loops
  %   This is a class for timing PARFOR loops. Once the measurement is
  %   made, it can be plotted to observe the various overheads that may
  %   exist in parallel for loops. It also shows the utilization of each
  %   worker.
  %
  % Par Properties:
  %  Worker       - Process ID of the worker
  %  ItStart      - Start time of iteration
  %  ItStop       - Stop time of iteration
  %
  % Par Methods:
  %  Par          - Construct Par objects and start the measurement
  %  stop         - Stop the measurement
  %  par2struct   - Convert the results to a flat structure
  %  plot         - Create a custom plot of the results
  %  horzcat      - Horizontally concatenate multiple PARFOR measurements
  %  StartTime    - Return the start time of the measurement
  %  StopTime     - Return the stop time of the measurement
  %  tic (Static) - Record start time of parfor loop iteration
  %  toc (Static) - Record stop time of parfor loop iteration
  %
  % This class should be used in the following way:
  %
  %       p = Par(n);                   (1)
  %       parfor id = 1:n
  %           Par.tic;                  (2)
  %
  %           <usual computations>
  %
  %           p(id) = Par.toc;          (3)
  %       end
  %       stop(p);                      (4)
  %
  %       plot(p);                      (5)
  %
  % 1. Construct a Par object, with the number of iterations as the input.
  %    This constructs the object.
  % 2. Call Par.tic just inside the PARFOR loop. This records the start
  %    time of the iteration.
  % 3. Call Par.toc just before the end of the PARFOR loop. Store the
  %    output to the appropriate index of the Par object. This is necessary
  %    for PARFOR to recognize that the variable is sliced.
  % 4. Stop the measurement. This records the final end time.
  % 5. Visualize.
  %
  % There may be some overhead in adding the Par construct. Because of
  % this, the numbers you get may not accurately portray the true timing,
  % especially for short computations.
  %
  % Doc page in Help browser
  %   doc Par

  % Copyright 2010 The MathWorks, Inc.

  properties (SetAccess = protected)
    % WORKER  Process ID of the worker running this iteration
    %   This is a read-only property and is only set using Par.tic and
    %   Par.toc
    Worker = NaN

    % ITSTART  Start time (from the start of object creation) of the iteration
    %   This is a read-only property and is only set using Par.tic and
    %   Par.toc
    ItStart = NaN

    % ITSTOP  Stop time (from the start of object creation) of the iteration
    %   This is a read-only property and is only set using Par.tic and
    %   Par.toc
    ItStop = NaN
  end

  properties (Hidden, GetAccess = protected)
    MainStartTime = []
    MainStopTime  = []
  end

  methods

    function obj = Par(n, varargin)
      % PAR Contructor for the Par object
      %
      % obj = Par(N)
      %   Creates an array of loop timer object for PARFOR loops. N is a
      %   positive integer equal to the length of iterations in the PARFOR
      %   loop.

      % Special case used internally
      %   check first since we want this to happen immediately.
      if nargin == 3
        obj.Worker  = n;
        obj.ItStart = varargin{1};
        obj.ItStop  = varargin{2};
        return;
      end

      switch nargin
        case 0
          return;

        case 1
          validateattributes(n, {'numeric'}, {'integer', 'scalar', 'positive'});
          obj(n) = Par();

          % Record the current time
          getnow(1);

          % Start the initial tic on this machine and on the workers
          tictoc(1);
          spmd
            tictoc(1);
          end

        otherwise
          error('Par:Par:InvalidNumberOfInputArguments', ...
            'You must call the constructor with one input argument: Par(n)');
      end

    end

    function newobj = horzcat(varargin)
      % HORZCAT Horizontally concatenate multiple PARFOR measurements.
      %
      % horzcat(p1, p2, ...) or [p1, p2, ...]
      %   Concatenates multiple Par objects. This allows you to combine
      %   results from multiple PARFOR blocks that are run sequentially.
      %   P1, P2, ... must be either Par objects or an empty array ([]).

      varargin(cellfun(@isempty, varargin)) = [];

      if ~all(cellfun('isclass', varargin, 'Par'))
        error('Par:horzcat:InvalidInputType', ...
          'Input arguments must [] or class type Par');
      end

      % Sort Par objects by MainStartTime
      [sortedGlobalTimes, idx] = sort(cellfun(@(x) min([x.MainStartTime]), varargin));
      % Calculate time to offset each Par objects
      offset = (sortedGlobalTimes - sortedGlobalTimes(1))*24*3600;

      % Reorder in ascending MainStartTime
      varargin = varargin(idx);

      % Create a new Par object with the appropriate number of elements
      num = sum(cellfun(@length, varargin));
      newobj = Par(num);

      % Concatenate one by one, offsetting the times by the offset values
      iCounter = 0;
      for iPar = 1:length(varargin)
        idx = (1:length(varargin{iPar})) + iCounter;
        os = offset(iPar);

        [newobj(idx).Worker]        = deal(varargin{iPar}.Worker);
        [newobj(idx).MainStartTime] = deal(varargin{iPar}.MainStartTime);
        [newobj(idx).MainStopTime]  = deal(varargin{iPar}.MainStopTime);

        newobj(idx(end)).MainStopTime = newobj(idx(end)).MainStopTime + os;

        newval = num2cell([varargin{iPar}.ItStart] + os);
        [newobj(idx).ItStart] = deal(newval{:});
        newval = num2cell([varargin{iPar}.ItStop] + os);
        [newobj(idx).ItStop] = deal(newval{:});

        iCounter = iCounter + length(varargin{iPar});
      end

    end

    function stop(obj)
      % STOP Stop the measurement.
      %
      % obj.stop() or stop(obj)
      %   Stops the measurement process. This should be called right after
      %   the parfor loop.

      if ~isempty(obj(end).MainStopTime)
        error('Par:stop:MultipleStopsNotAllowed', ...
          'You cannot stop more than once.');
      end

      % Assign only to the last element to minimize memory usage.
      obj(end).MainStartTime = getnow(2);
      obj(end).MainStopTime  = tictoc(2);                       %#ok<NASGU>

    end

    function val = StartTime(obj)
      % STARTTIME Return the end time of the measurement.
      %
      % val = obj.StartTime() or val = StartTime(obj)
      %   Returns the start time relative to the initial creation of the
      %   object. Usually, this is zero. If this object was a concatenation
      %   of multiple Par objects, then this will return multiple start
      %   times for each of the objects, relative to the initial start
      %   time.

      % The start time is stored in the hidden property MainStartTime
      gst = [obj.MainStartTime];
      % Convert to seconds (MainStartTime is a serial date)
      val = (gst - gst(1)) * 24 * 3600;

    end

    function val = StopTime(obj)
      % STOPTIME Return the end time of the measurement.
      %
      % val = obj.StopTime() or val = StopTime(obj)
      %   Returns the time passed from the creation of the object to
      %   stopping of the object.

      % The stop time is stored in the hidden property MainStopTime
      val = [obj.MainStopTime];

    end

    function parInfo = par2struct(obj)
      % PAR2STRUCT Convert the results to a flat structure.
      %
      % p = obj.par2struct() or p = par2struct(obj)
      %   Converts the results into a flat structure with the following
      %   fields:
      %       Start   : start times of each PARFOR block
      %       Stop    : end times of each PARFOR block
      %       Worker  : array of process id's for each iteration
      %       ItStart : array of start times for each iteration
      %       ItStop  : array of stop times for each iteration

      parInfo.Start   = obj.StartTime;
      parInfo.Stop    = obj.StopTime;
      parInfo.Worker  = [obj.Worker];
      parInfo.ItStart = [obj.ItStart];
      parInfo.ItStop  = [obj.ItStop];

    end

    function plot(obj, varargin)
      % PLOT Create a custom plot of the results.
      %
      % obj.plot() or plot(obj)
      %   Creates a custom plot of the results. The plot consists of 3
      %   parts:
      %     1) a line graph showing start and stop times of each iteration
      %     on each worker.
      %     2) a stacked bar graph showing the efficiency of each worker.
      %     3) a plot showing actual duration of each iteration.
      %
      % obj.plot(obj2) or plot(obj, obj2)
      %   Creates a custom plot that also compares the results of obj and
      %   obj2. obj2 must be of class Par and must be a result from a
      %   serial computation or a single-worker computation.

      % Error checking
      addSerial = 0;

      if nargin == 3

        obj2 = varargin{1};
        newMap = varargin{2};
        addSerial = 1;
        if ~isa(newMap, 'function_handle')
          error('Par:plot:invalidclass', ...
            'The third argument must be a function handle');
        end

      end

      if nargin == 2

        if isa(varargin{1}, 'function_handle')
          newMap = varargin{1};
        else
          obj2 = varargin{1};
          addSerial = 1;
          if ~(isa(obj2, 'Par'))
            error('Par:plot:invalidclass', ...
              'The second argument must also be of class Par or a function handle');
          end

          if length(unique([obj2.Worker])) > 1
            error('Par:plot:notserial', ...
              'The second argument must be the results from a serial (or 1 worker) calculation');
          end
        end

      end

      if any(isnan(obj.StopTime)) || (addSerial == 1 && isnan(obj2.StopTime))
        error('Par:plot:unterminated', ...
          'You need to stop() the object before you can plot()');
      end

      if any(isnan([obj.Worker])) || (addSerial == 1 && any(isnan([obj.Worker])))
        error('Par:plot:uncompleted', ...
          'You need to have timed all iterations before you can plot()');
      end

      % Call plotting subfunction
      if nargin == 1
        parPlot(addSerial, obj.par2struct)
      elseif nargin == 2
        if addSerial == 1
          parPlot(addSerial, obj.par2struct, obj2.par2struct)
        else
          parPlot(addSerial, obj.par2struct, newMap)
        end
      else
        parPlot(addSerial, obj.par2struct, obj2.par2struct, newMap)
      end

    end

  end

  methods (Static)

    function val = tic()
      % TIC Record start time of parfor loop iteration.
      %
      % Par.tic()
      %   Records the starting time within the loop. This should be called
      %   immediately inside the parfor loop.
      %
      % See also Par.toc

      persistent start_time

      if nargout
        if isempty(start_time)
          val = NaN;
        else
          val = start_time;
        end
      else
        start_time = tictoc(2);
      end

    end

    function obj = toc()
      % TOC Record stop time of parfor loop iteration.
      %
      % obj = Par.toc()
      %   Records the ending time within the loop. This should be called
      %   just before the end statement of the parfor loop.
      %
      % See also Par.tic

      if nargout

        workerNo = get(getCurrentTask,'ID');

        if isempty(workerNo)
          workerNo  = 0;
        end

        obj = Par(workerNo, Par.tic(), tictoc(2));

      end

    end

  end

  % These are overridden handle class methods. It's hidden so that it
  % doesn't show up as one of the standard methods in the DOC.
  methods (Hidden)

    function varargout = vertcat(varargin) %#ok<STOUT>

      error('Par:vertcat:VerticalConcatenationNotAllowed', ...
        ['Vertical concatenation is not allowed for a Par object.\n', ...
        'Consider horizontal concatenation.']);

    end

    function out = addlistener(varargin)
      out = addlistener@handle(varargin{:});
    end

    function delete(varargin)
      delete@handle(varargin{:});
    end

    function out = eq(varargin)
      out = eq@handle(varargin{:});
    end

    function findobj(varargin)
      findobj@handle(varargin{:});
    end

    function out = findprop(varargin)
      out = findprop@handle(varargin{:});
    end

    function out = ge(varargin)
      out = ge@handle(varargin{:});
    end

    function out = gt(varargin)
      out = gt@handle(varargin{:});
    end

    function out = le(varargin)
      out = le@handle(varargin{:});
    end

    function out = lt(varargin)
      out = lt@handle(varargin{:});
    end

    function out = ne(varargin)
      out = ne@handle(varargin{:});
    end

    function notify(varargin)
      notify@handle(varargin{:})
    end

  end

end

function out = getnow(flag)
% getnow
%   Internal function for recording global start time (in serial dates).

persistent nowtime

switch flag
  case 1
    nowtime = now;
  case 2
    if isempty(nowtime)
      error('Par:getnow:InvalidInitialization', ...
        ['The Par object may not have been initialized correctly.\n', ...
        'Be sure to initialize Par object with an input argument: p = Par(n)']);
    else
      out = nowtime;
    end
end

end

function out = tictoc(flag)
% tictoc
%   Internal function for recording start and end times.

persistent t1

switch flag
  case 1
    t1 = tic;
  case 2
    if isempty(t1)
      error('Par:tictoc:InvalidInitialization', ...
        ['The Par object may not have been initialized correctly.\n', ...
        'Be sure to initialize Par object with an input argument: p = Par(n)']);
    else
      out = toc(t1);
    end
  case 3
    if isempty(t1)
      error('Par:tictoc:InvalidInitialization', ...
        ['The Par object may not have been initialized correctly.\n', ...
        'Be sure to initialize Par object with an input argument: p = Par(n)']);
    else
      out = t1;
    end
end

end

function  parPlot(addSerial, parInfo, varargin)

cMap = @winter;

if nargin == 4
  parInfoS = varargin{1};
  cMap = varargin{2};
end

if nargin == 3
  if addSerial
    parInfoS = varargin{1};
  else
    cMap = varargin{1};
  end
end

% Determing unique workers
pid = parInfo.Worker;
allPIDs = unique(parInfo.Worker);
numWorkers = length(allPIDs);

% Preallocation
startTimes = cell(1, numWorkers);
endTimes = cell(1, numWorkers);
itTimes = cell(1, numWorkers);
totalTimes = nan(1, numWorkers);
overHead = nan(1, numWorkers);
overPerct = nan(1, numWorkers);
avgLoopTime = nan(1, numWorkers);

% Extracting start times, end times, and iteration times
if addSerial
  startTimesS = parInfoS.ItStart;
  endTimesS = parInfoS.ItStop;
  itTimesS = parInfoS.ItStop - parInfoS.ItStart;
  speedUp = parInfoS.Stop/parInfo.Stop;
end

totalParTime = sum(parInfo.Stop - parInfo.Start);

for ii = 1:numWorkers
  myIndex = (pid == allPIDs(ii));

  startTimes{ii} = parInfo.ItStart(myIndex);
  endTimes{ii} = parInfo.ItStop(myIndex);
  itTimes{ii} = parInfo.ItStop(myIndex) - parInfo.ItStart(myIndex);
  totalTimes(ii) = sum(endTimes{ii}-startTimes{ii});

  overHead(ii) = totalParTime-totalTimes(ii);
  overPerct(ii) = (overHead(ii)/totalParTime)*100;
  avgLoopTime(ii) = totalTimes(ii)/length(endTimes{ii});
end

% Plotting Data

myColors = cMap(numWorkers+addSerial); % setting up color scheme

hFig = figure;
subplot(2, 2, 1:2, 'Parent', hFig);
box on;

if addSerial
  plotdata = [startTimesS;endTimesS;nan(1, length(startTimesS))];
  plotdata2 = startTimesS;
  plotdata3 = endTimesS;

  line(plotdata(:), zeros(1, numel(plotdata)), ...
    'color', myColors(1,:));
  hold on
  line(plotdata2(:), zeros(1, numel(plotdata2)), ...
    'marker','.','MarkerSize',5, 'LineStyle', 'none',...
    'color', myColors(1,:));
  hold on
  line(plotdata3(:), zeros(1, numel(plotdata3)), ...
    'marker','X','MarkerSize',5, 'LineStyle', 'none',...
    'color', myColors(1,:));

  speedStr=['Speed Up = ', num2str(speedUp)];
  text(parInfo.Stop + (0.005*parInfo.Stop),numWorkers,speedStr)
end

for ii = 1:numWorkers
  plotdata = [startTimes{ii};endTimes{ii};nan(1, length(startTimes{ii}))];
  plotdata2 = startTimes{ii};
  plotdata3 = endTimes{ii};

  line(plotdata(:), ii*ones(1, numel(plotdata)), ...
    'color', myColors(ii+addSerial,:));
  hold on
  line(plotdata2(:), ii*ones(1, numel(plotdata2)), ...
    'marker','.','MarkerSize',5, 'LineStyle', 'none', ...
    'color',myColors(ii+addSerial,:));
  hold on
  line(plotdata3(:), ii*ones(1, numel(plotdata3)), ...
    'marker','X','MarkerSize',5, 'LineStyle', 'none', ...
    'color', myColors(ii+addSerial,:));

end

% Plotting total start and stop times

line([parInfo.Start; parInfo.Start], ...
  repmat([0-addSerial; (numWorkers+1)], 1, length(parInfo.Start)),...
  'color', [.5 .5 .5]);
line([parInfo.Stop; parInfo.Stop], ...
  repmat([0-addSerial; (numWorkers+1)], 1, length(parInfo.Stop)),...
  'color', [.5 .5 .5]);
line([0 0], [0-addSerial, (numWorkers+1)], 'color', 'k');
ylim([0-addSerial (numWorkers+1)])
set(gca, 'YTick', (1-addSerial):numWorkers);
set(gca, 'TickDir', 'out');

if addSerial == 1
  % Setting 0 label to Serial for clarity
  ylabels = get(gca, 'YTickLabel') ;
  newlabels = char(zeros(length(ylabels),6));
  newlabels(:,1) = ylabels;
  newlabels(1,:) = 'Serial';
  set(gca, 'YTickLabel', newlabels) ;
end

title('Iterations in Time By Worker','fontweight','b')
xlabel('Time (s)')
ylabel('Worker')

% Plotting Efficency
subplot(2,2,3)

if numWorkers > 1

  % Giving bars different colors
  for ii = 1:numWorkers
    pp = nan(numWorkers, 2);
    pp(ii, :) = [100-overPerct(ii), overPerct(ii)];
    hB = barh(1:numWorkers, pp, 'stack');
    set(hB(1),'FaceColor',myColors(addSerial+ii,:));
    set(hB(2),'FaceColor',[0.5 0.5 0.5]);
    hold on;
  end

else
  hB = barh( [1 2] ,[100-overPerct, NaN; overPerct, NaN]','Stack');
  set(hB(1),'FaceColor',myColors(1,:));
  set(hB(2),'FaceColor',[0.5 0.5 0.5])
end

ylim([0, numWorkers+1])
set(gca, 'YTick', 1:numWorkers);

title('Worker Utilization','fontweight','b')
xlabel('% of Total Time on Worker')
ylabel('Worker')

% Plotting Stats on Iteration Times
% Adding menu to change between linear and semilog axis
hMenu = uicontextmenu();
hAx = subplot(2,2,4, 'UIContextMenu', hMenu);
uimenu('Parent', hMenu, 'Label', 'Linear Scale', 'Checked', 'on', ...
  'Callback', {@setScaleFcn, hAx});
uimenu('Parent', hMenu, 'Label', 'Log Scale', 'Checked', 'off', ...
  'Callback', {@setScaleFcn, hAx});

if addSerial
  counter = (1:length(parInfo.ItStop));
  plot(counter,itTimesS,'color', ...
    myColors(1,:),'Marker','.','LineStyle','none')
  hold on
end

for ii = 1:numWorkers
  myIndex = (pid == allPIDs(ii));
  counter = (1:length(parInfo.ItStop));
  plot(counter(myIndex),itTimes{ii},'color', ...
    myColors(ii+addSerial,:),'Marker','*','LineStyle','none')
  hold on
end

title('Time Of Individual Iterations','fontweight','b')
xlabel('Iteration Number')
ylabel('Iteration Time (s)')

set(hFig, 'HandleVisibility', 'off');

% if numWorkers + addSerial > 1
%     % Add legend if more than one point
%     legendTxt = cell(addSerial+numWorkers,1);
%
%     for ii = 1-addSerial:numWorkers
%         legendTxt{ii+addSerial,1} = num2str(ii);
%     end
%
%     legend(legendTxt)
%
% end
end

function setScaleFcn(hObject, ~, hAx)

set(get(get(hObject, 'Parent'), 'Children'), 'Checked', 'off')
set(hObject, 'Checked', 'on');
switch get(hObject, 'Label')
  case 'Log Scale'
    set(hAx, 'YScale', 'log');
  case 'Linear Scale'
    set(hAx, 'YScale', 'linear');
end

end


classdef Plotter < handle
% PLOTTER supports plotting data in 2D with a reference signal.
%
% Properties:
%   r           - Reference signal
%   x           - Time
%   y           - Output signal
%
% Methods:
%   plot_2d_ref - Plots an output and reference signal over time.

    properties
    %% PROPERTIES

        t   % Time
        y   % Output signal
        r   % Reference signal

        h
        g
        a
    end

    methods
        function obj = Plotter()
        % PLOTTER Constructor

            obj.t = 0;
            obj.y = 0;
            obj.r = 0;
            obj.h = -1;
            obj.g = -1;

            figure;
            obj.a = axes;
            set(obj.a, 'NextPlot', 'add');
            hold(obj.a, 'all');
            obj.t = 0;
        end

        function plot_2d_ref(obj, dt, y, r, color)
        %% PLOT_2D_REF Plots an output and reference signal over time
        %   [h,g] = plot_2d_ref(obj, h, g, x, y, r) plots the output signal
        %   (y) and reference signal (r) versus time (t).

            if ~ishandle(obj.h)
                obj.h = plot(obj.a, dt, y, 'b');
                obj.g = plot(obj.a, dt, r, '--');
                set(obj.g, 'Color', color);
                obj.t = obj.t(end);
                obj.y = obj.y(end);
                obj.r = obj.r(end);
            end

            obj.t = [obj.t obj.t(end)+dt];
            obj.y = [obj.y y];
            obj.r = [obj.r r];

            set(obj.h, 'XData', obj.t);
            set(obj.h, 'YData', obj.y);
            set(obj.g, 'XData', obj.t);
            set(obj.g, 'YData', obj.r);

        end

        function switch_2d_ref(obj)
            obj.h = -1;
        end

    end

end


%CODEGENERATOR.GETPIBUGFIXSTRING Returns a string to fix PI-Bug in auto genereated functions.
%
% bfixString = cGen.getPiBugfixString() Is the string with explanation comment
% and variable declaration as described below.
%
% Notes::
%  In some versions the symbolic toolbox writes the constant $pi$ in
%  capital letters. This way autogenerated functions might not work properly.
%  To fix this issue a local variable is introduced:
%  PI = pi
%
% Authors::
%  Joern Malzahn, (joern.malzahn@tu-dortmund.de)
%
% See also CodeGenerator.constructheaderstring, CodeGenerator.replaceheader.

% Copyright (C) 1993-2012, by Peter I. Corke
% Copyright (C) 2012-2013, by Joern Malzahn
%
% This file is part of The Robotics Toolbox for Matlab (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB 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 Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com
%
% The code generation module emerged during the work on a project funded by
% the German Research Foundation (DFG, BE1569/7-1). The authors gratefully
% acknowledge the financial support.

function bfixString = getpibugfixstring(CGen)
bfixString = [];
bfixString = [bfixString, sprintf('%s\n','%% Bugfix')];
bfixString = [bfixString, sprintf('%s\n','%  In some versions the symbolic toolbox writes the constant $pi$ in')];
bfixString = [bfixString, sprintf('%s\n','%  capital letters. This way autogenerated functions might not work properly.')];
bfixString = [bfixString, sprintf('%s\n','%  To fix this issue a local variable is introduced:')];
bfixString = [bfixString, sprintf('%s\n','PI = pi;')];
bfixString = [bfixString, sprintf('%s\n','   ')];


function [DEMc,MASK] = crop(DEM,varargin)

%CROP crop an instance of GRIDobj with axis-aligned minimum bounding box
%
% Syntax
%
%     DEMc = crop(DEM)
%     DEMc = crop(DEM,I)
%     DEMc = crop(DEM,I,fillval)
%     DEMc = crop(DEM,ix)
%     DEMc = crop(DEM,x,y)
%     DEMc = crop(DEM,'interactive');
%
% Description
%
%     crop removes outer parts of a grid based on missing values (NaNs),
%     a mask, linear indices or coordinate pairs such that the axis-aligned
%     minimum bounding rectangle remains.
%
% Input arguments
%
%     DEM      instance of GRIDobj
%     I        mask (logical) as instance of GRIDobj
%     fillval  scalar; values in the output grid where I.Z==0 obtain this
%              value (crop and clip by setting fillval to nan)
%     ix       linear index into the DEM
%     x,y      coordinate vectors
%
%
% See also: IND2SUB, GRIDobj/pad, GRIDobj/resample
%
% Author: Wolfgang Schwanghart (w.schwanghart[at]geo.uni-potsdam.de)
% Date: 2. September, 2017

narginchk(1,3);

if nargin == 1;
    MASK = isnan(DEM.Z);

    if ~any(MASK(:));
        DEMc = DEM;
        if nargout == 2;
            MASK = DEM;
            MASK.Z = true(DEM.size);
            MASK.zunit = '';
            MASK.name = 'mask for cropping';
        end

        return
    end
    MASK = ~MASK;
    MASK = bwperim(MASK);
    IX  = find(MASK);

elseif nargin >= 2;
    if isa(varargin{1},'GRIDobj') || isa(varargin{1},'logical');
        % GRIDobj
        validatealignment(DEM,varargin{1});
        if isa(varargin{1},'GRIDobj')
            MASK = logical(varargin{1}.Z);
        else
            MASK = varargin{1};
        end

        if nargin == 3
            validateattributes(varargin{2},{'numeric'},{'scalar'},'crop','fillval',3);
            if isnan(varargin{2}) && ~(isa(DEM.Z,'single') || isa(DEM.Z,'double'))
                DEM.Z(~MASK) = 0;
                warning('TopoToolbox:GRIDobj',...
                    ['fillval set to zero since data type of the input grid\newline' ...
                     'does not support nans'])
            else
                DEM.Z(~MASK) = varargin{2};
            end
        end
        MASK = bwperim(MASK);
        IX  = find(MASK);
    elseif nargin == 2;
        if isnumeric(varargin{1})
            % indices are supplied
            IX  = varargin{1};
            if numel(IX) < 2;
                error('TopoToolbox:GRIDobj',...
                    'At least two indices are required to crop the grid.')
            end

            if any(IX<1) || any(IX>prod(DEM.size));
                error('TopoToolbox:GRIDobj',...
                    ['Index must range between 1 and ' num2str(prod(DEM.size)) '.'])
            end
        else
            % interactive part
            try
            imagesc(DEM);
            c = uicontrol('Style','Text','Units','normalized','position',[0 0 1 0.05],...
                'String','Draw rectangle and double click when finished.');
            h = imrect;
            addNewPositionCallback(h,@(pos) set(c,'String',...
                ['LX:' num2str(round(pos(1)),'%d') ', LY:' num2str(round(pos(2)),'%d') ...
                 ', UX:' num2str(round(pos(1)+pos(3)),'%d') ', UY:' num2str(round(pos(2)+pos(4)),'%d')]));
            [~] = wait(h);
            MASK  = createMask(h);
            delete(h)
            close
            catch ME
                error('TopoToolbox:crop','output variable undefined')
%                 warning('empty matrix returned')
%                 DEMc = [];
                return
            end

            MASK  = bwperim(MASK);
            IX    = find(MASK);
        end

    else

        [X,Y] = refmat2XY(DEM.refmat,DEM.size);
        x = varargin{1};
        y = varargin{2};

        x = max(min(X),x);
        x = min(max(X),x);

        y = max(min(Y),y);
        y = min(max(Y),y);

        IX = coord2ind(X,Y,x,y);
    end

end

if nargout == 2
    MASK = DEM;
    MASK.Z = false(DEM.size);
    MASK.Z(IX) = true;
    MASK.name = 'mask for cropping';
    MASK.zunit = '';
end

% nr of dimensions
siz  = DEM.size;
k    = [1 cumprod(siz(1:end-1))];

% preallocate subsref structure
S    = substruct('()',cell(1,2));

% subset size
sizout = zeros(1,2);

% loop through dimensions (see ind2sub)
% and get subscripts of minimum bounding rectangle/box/...
for r = 2:-1:1
    IX2       = rem(IX-1,k(r))+1;
    subdim    = (IX-IX2)/k(r)+1;
    S.subs{r} = min(subdim):max(subdim);
    sizout(r) = numel(S.subs{r});
    IX        = IX2;
end

DEMc      = DEM;
DEMc.Z    = reshape(subsref(DEM.Z,S),sizout);
DEMc.size = sizout;
[x,y]     = sub2coord(DEM,S.subs{1}(1),S.subs{2}(1));
DEMc.refmat(3,:) = [x y] - DEMc.cellsize*[1 -1];

DEMc.name   = [DEM.name ' (cropped)'];
DEMc.zunit  = DEM.zunit;
DEMc.xyunit = DEM.xyunit;

if ~isempty(DEM.georef)
    % Copy all referencing information
    DEMc.georef = DEM.georef;
    DEMc.georef.SpatialRef = refmatToMapRasterReference(DEMc.refmat, DEMc.size);

end


function nd = ndim(c)

%tstoolbox/@core/ndim
%   Syntax:
%     * ndim(c)
%
%   Input Arguments:
%     * c - core object
%
%   return number of dimensions, a scalar value has 0 dimensions
%
% Copyright 1997-2001 DPI Goettingen, License http://www.physik3.gwdg.de/tstool/gpl.txt

nd = length(c.dlens);
if nd == 1
	if c.dlens(1) == 1
		nd = 0;
	end
end


% Test file for SPINPREFSPHERE:

function pass = test_spinprefsphere()

% Construction from inputs:
pref = spinprefsphere('Clim', [0 10], 'dataplot', 'abs', 'dealias', 'off');
pass(1) = isequal(pref.Clim, [0 10]);
pass(2) = strcmpi(pref.dataplot, 'abs');
pass(3) = strcmpi(pref.dealias, 'off');

pref = spinprefsphere('iterplot', 10);
pass(4) = isequal(pref.iterplot, 10);

pref = spinprefsphere('Nplot', 2, 'plot', 'movie');
pass(5) = isequal(pref.Nplot, 2);
pass(6) = strcmpi(pref.plot, 'movie');

pref = spinprefsphere('view', [10 20]);
pass(7) = isequal(pref.view, [10 20]);

end


function [ node_coord, node_att, node_marker ] = triangle_node_data_read ( ...
  node_filename, node_num, node_dim, node_att_num, node_marker_num )

%*****************************************************************************80
%
%% TRIANGLE_NODE_DATA_READ reads the data from a node file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    11 October 2014
%
%  Author:
%
%    John Burkardt
%
% Parameters:
%
%   Input, string NODE_FILENAME, the name of the node file.
%
%   Input, integer NODE_NUM, the number of nodes.
%
%   Input, integer NODE_DIM, the spatial dimension.
%
%   Input, integer NODE_ATT_NUM, number of node attributes
%   listed on each node record.
%
%   Input, integer NODE_MARKER_NUM, 1 if every node record
%   includes a final boundary marker value.
%
%   Output, real NODE_COORD(NODE_DIM,NODE_NUM), the nodal
%   coordinates.
%
%   Output, real NODE_ATT(NODE_ATT_NUM,NODE_NUM), the nodal
%   attributes.
%
%   Output, integer NODE_MARKER(NODE_MARKER_NUM,NODE_NUM), the
%   node markers.
%
  node = 0;

  input = fopen ( node_filename, 'rt' );

  if ( input < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'TRIANGLE_NODE_DATA_READ - Fatal error!\n' );
    fprintf ( 1, '  Unable to open file.\n' );
    error ( 'TRIANGLE_NODE_DATA_READ - Fatal error!' );
  end
%
%  Create format.
%
  format = '%d';
  for i = 1 : node_dim
    format = strcat ( format, '%g' );
  end
  for i = 1 : node_att_num
    format = strcat ( format, '%g' );
  end
  for i = 1 : node_marker_num
    format = strcat ( format, '%d' );
  end
%
%  Create arrays.
%
  node_coord = zeros ( node_dim, node_num );
  node_att = zeros ( node_att_num, node_num );
  node_marker = zeros ( node_marker_num, node_num );
%
%  Read values and place in the arrays.
%
  while ( 1 )

    text = fgets ( input );

    if ( text == -1 )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'TRIANGLE_NODE_DATA_READ - Fatal error!\n' );
      fprintf ( 1, '  Unexpected end of file while reading.\n' );
      error ( 'TRIANGLE_NODE_DATA_READ - Fatal error!' );
    end

    if ( s_len_trim ( text ) == 0 )
      continue
    end

    if ( text(1) == '#' )
      continue
    end
%
%  Ignore the dimension line.
%
    if ( node == 0 )

    else

      [ value, count ] = sscanf ( text, format );

      if ( count < 1 + node_dim + node_att_num + node_marker_num )
        fprintf ( 1, '\n' );
        fprintf ( 1, 'TRIANGLE_NODE_DATA_READ - Fatal error!\n' );
        fprintf ( 1, '  Line did not have enough data.\n' );
        error ( 'TRIANGLE_NODE_DATA_READ - Fatal error!' );
      end

      j = 1;

      for i = 1 : node_dim
        j = j + 1;
        node_coord(i,node) = value(j);
      end

      for i = 1 : node_att_num
        j = j + 1;
        node_att(i,node) = value(j);
      end

      for i = 1 : node_marker_num
        j = j + 1;
        node_marker(i,node) = value(j);
      end

    end

    node = node + 1;

    if ( node_num < node )
      break
    end

  end

  fclose ( input );

  return
end


function A = shuffle_by_1(A)
%SHUFFLE_BY_1 shuffle the columns of A to the right by one, such that the
%new ith column is the old i-1th column, and the new 1st column is the old
%last column.
%
% A = shuffle_by_1(A);
%
% Inputs:
%  A  a rectangular matrix
% Outputs:
%  A  the input matrix with the rows shuffled to the right by 1

end


%% SATISFY_FSU uses the fsuClusterMatlab command to run the SATISFY computation.
%
%  Discussion:
%
%    The arguments to fsuClusterMatlab mean:
%
%    [] allows us to specify an output directory;
%    [] allows us to specify switches to the MOAB queue handler, such as more time.
%    'p" indicates this is a "parfor" job;
%    'w' indicates that the MATLAB session should wait for completion;
%    4 is the number of processors requested;
%    @sat_fun indicates the function we want to execute;
%    {} would contain input arguments if there were any.
%
%    The function "satisfy_fun" must correspond to a MATLAB M-file "satisfy_fun.m"
%    and that file must be in MATLAB's path.
%
%    The easiest way to ensure that the file is in MATLAB's path is to
%    create a subdirectory called "matlab" immediately below your home directory,
%    and place the function file there (as well as any other files needed by the job).
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    20 May 2010
%
%  Author:
%
%    John Burkardt
%
  results = fsuClusterMatlab ( [], [], 'p', 'w', 4, @satisfy_fun, {} );


function I = data_augmentation(I, K)

if K == 1
    return;
elseif K == 2 % flipped
    I = flipud(I);
    return;
elseif K == 3 % rotation 90
    I = rot90(I,1);
    return;
elseif K == 4 % rotation 90 & flipped
    I = rot90(I,1);
    I = flipud(I);
    return;
elseif K == 5 % rotation 180
    I = rot90(I,2);
    return;
elseif K == 6 % rotation 180 & flipped
    I = rot90(I,2);
    I = flipud(I);
    return;
elseif K == 7 % rotation 270
    I = rot90(I,3);
    return;
elseif K == 8 % rotation 270 & flipped
    I = rot90(I,3);
    I = flipud(I);
    return;
end


function [out1,out2,out3] = myginput(arg1,strpointertype)
%MYGINPUT Graphical input from mouse with custum cursor pointer.
%   [X,Y] = MYGINPUT(N) gets N points from the current axes and returns
%   the X- and Y-coordinates in length N vectors X and Y.
%
%   [X,Y] = MYGINPUT(N, POINTER) also specifies the cursor pointer, e.g.
%   'crosshair', 'arrow', 'circle' etc. See "Specifying the Figure Pointer"
%   in Matlab's documentation  to see the list of available pointers.
%
%   MYGINPUT is strictly equivalent to Matlab's original GINPUT, except
%   that a second argument specifies the cursor pointer instead of the
%   default 'fullcrosshair' pointer.
%
%   Example:
%     plot(1:2,1:2,'s');
%     hold on
%     [x,y] = myginput(1,'crosshair');
%     plot(x,y,'o');
%     hold off
%
%   MYGINPUT is copied from Matlab's GINPUT rev. 5.32.4.4.
%
%   See also GINPUT.

%   F. Moisy, moisy_at_fast.u-psud.fr
%   Revision: 1.02,  Date: 2006/10/24

% History:
% 2005/10/31: v1.00, first version, from GINPUT rev. 5.32.4.4.
% 2005/11/25: v1.01, line 'uisuspend' modified (for compatibility with
%                    ML7.00)
% 2006/10/24: v1.02, help text improved

out1 = []; out2 = []; out3 = []; y = [];

if nargin<1     % modified MYGINPUT
    strpointertype='crosshair'; % default GINPUT pointer
end

c = computer;
if ~strcmp(c(1:2),'PC')
   tp = get(0,'TerminalProtocol');
else
   tp = 'micro';
end

if ~strcmp(tp,'none') && ~strcmp(tp,'x') && ~strcmp(tp,'micro'),
   if nargout == 1,
      if nargin == 1,
         out1 = trmginput(arg1);
      else
         out1 = trmginput;
      end
   elseif nargout == 2 || nargout == 0,
      if nargin == 1,
         [out1,out2] = trmginput(arg1);
      else
         [out1,out2] = trmginput;
      end
      if  nargout == 0
         out1 = [ out1 out2 ];
      end
   elseif nargout == 3,
      if nargin == 1,
         [out1,out2,out3] = trmginput(arg1);
      else
         [out1,out2,out3] = trmginput;
      end
   end
else

   fig = gcf;
   figure(gcf);

   if nargin == 0
      how_many = -1;
      b = [];
   else
      how_many = arg1;
      b = [];
      if  isstr(how_many) ...
            || size(how_many,1) ~= 1 || size(how_many,2) ~= 1 ...
            || ~(fix(how_many) == how_many) ...
            || how_many < 0
         error('Requires a positive integer.')
      end
      if how_many == 0
         ptr_fig = 0;
         while(ptr_fig ~= fig)
            ptr_fig = get(0,'PointerWindow');
         end
         scrn_pt = get(0,'PointerLocation');
         loc = get(fig,'Position');
         pt = [scrn_pt(1) - loc(1), scrn_pt(2) - loc(2)];
         out1 = pt(1); y = pt(2);
      elseif how_many < 0
         error('Argument must be a positive integer.')
      end
   end

   % Suspend axes functions
       %haxes = findobj(fig,'type','axes');
        state = uisuspend(fig);
   %haxes = findobj(fig,'type','axes');
   %state = uisuspend(haxes);
   pointer = get(gcf,'pointer');
   set(gcf,'pointer',strpointertype);  % modified MYGINPUT
   fig_units = get(fig,'units');
   char = 0;

   % We need to pump the event queue on unix
   % before calling WAITFORBUTTONPRESS
   drawnow

   while how_many ~= 0
      % Use no-side effect WAITFORBUTTONPRESS
      waserr = 0;
      try
	keydown = wfbp;
      catch
	waserr = 1;
      end
      if(waserr == 1)
         if(ishandle(fig))
            set(fig,'units',fig_units);
	    uirestore(state);
            error('Interrupted');
         else
            error('Interrupted by figure deletion');
         end
      end

      ptr_fig = get(0,'CurrentFigure');
      if(ptr_fig == fig)
         if keydown
            char = get(fig, 'CurrentCharacter');
            button = abs(get(fig, 'CurrentCharacter'));
            scrn_pt = get(0, 'PointerLocation');
            set(fig,'units','pixels')
            loc = get(fig, 'Position');
            pt = [scrn_pt(1) - loc(1), scrn_pt(2) - loc(2)];
            set(fig,'CurrentPoint',pt);
         else
            button = get(fig, 'SelectionType');
            if strcmp(button,'open')
               button = 1;
            elseif strcmp(button,'normal')
               button = 1;
            elseif strcmp(button,'extend')
               button = 2;
            elseif strcmp(button,'alt')
               button = 3;
            else
               error('Invalid mouse selection.')
            end
         end
         pt = get(gca, 'CurrentPoint');

         how_many = how_many - 1;

         if(char == 13) % & how_many ~= 0)
            % if the return key was pressed, char will == 13,
            % and that's our signal to break out of here whether
            % or not we have collected all the requested data
            % points.
            % If this was an early breakout, don't include
            % the <Return> key info in the return arrays.
            % We will no longer count it if it's the last input.
            break;
         end

         out1 = [out1;pt(1,1)];
         y = [y;pt(1,2)];
         b = [b;button];
      end
   end

   uirestore(state);
   set(fig,'units',fig_units);

   if nargout > 1
      out2 = y;
      if nargout > 2
         out3 = b;
      end
   else
      out1 = [out1 y];
   end

end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function key = wfbp
%WFBP   Replacement for WAITFORBUTTONPRESS that has no side effects.

fig = gcf;
current_char = [];

% Now wait for that buttonpress, and check for error conditions
waserr = 0;
try
  h=findall(fig,'type','uimenu','accel','C');   % Disabling ^C for edit menu so the only ^C is for
  set(h,'accel','');                            % interrupting the function.
  keydown = waitforbuttonpress;
  current_char = double(get(fig,'CurrentCharacter')); % Capturing the character.
  if~isempty(current_char) & (keydown == 1)           % If the character was generated by the
	  if(current_char == 3)                       % current keypress AND is ^C, set 'waserr'to 1
		  waserr = 1;                             % so that it errors out.
	  end
  end

  set(h,'accel','C');                                 % Set back the accelerator for edit menu.
catch
  waserr = 1;
end
drawnow;
if(waserr == 1)
   set(h,'accel','C');                                % Set back the accelerator if it errored out.
   error('Interrupted');
end

if nargout>0, key = keydown; end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


function res = formatMeshOutput(nbArgs, vertices, edges, faces)
%FORMATMESHOUTPUT Format mesh output depending on nargout.
%
%   OUTPUT = formatMeshOutput(NARGOUT, VERTICES, EDGES, FACES)
%   Utilitary function to convert mesh data .
%   If NARGOUT is 0 or 1, return a matlab structure with fields vertices,
%   edges and faces.
%   If NARGOUT is 2, return a cell array with data VERTICES and FACES.
%   If NARGOUT is 3, return a cell array with data VERTICES, EDGES and
%   FACES.
%
%   OUTPUT = formatMeshOutput(NARGOUT, VERTICES, FACES)
%   Same as before, but do not intialize EDGES in output. NARGOUT can not
%   be equal to 3.
%
%   Example
%     % Typical calling sequence (for a very basic mesh of only one face)
%     v = [0 0; 0 1;1 0;1 1];
%     e = [1 2;1 3;2 4;3 4];
%     f = [1 2 3 4];
%
%     varargout = formatMeshOutput(nargout, v, e, f);
%
%   See also
%   meshes3d, parseMeshData
%
% ------
% Author: David Legland
% e-mail: david.legland@grignon.inra.fr
% Created: 2010-12-06,    using Matlab 7.9.0.529 (R2009b)
% Copyright 2010 INRA - Cepia Software Platform.

if nargin < 4
    faces = edges;
    edges = [];
end

switch nbArgs
    case {0, 1}
        % output is a data structure with fields vertices, edges and faces
        mesh.vertices = vertices;
        if ~isempty(edges)
            mesh.edges = edges;
        end
        mesh.faces = faces;
        res = {mesh};

    case 2
        % keep only vertices and faces
        res = cell(nbArgs, 1);
        res{1} = vertices;
        res{2} = faces;

    case 3
        % return vertices, edges and faces as 3 separate outputs
        res = cell(nbArgs, 1);
        res{1} = vertices;
        res{2} = edges;
        res{3} = faces;

    otherwise
        error('Can not manage more than 3 outputs');
end


function varargout=Whos(varargin)
%Whos (Upper case W) is  a customized version of whos (lower case w).
%
%The differences are
%
% (1) "Whos" will compute/display memory in kilobytes whereas "whos" displays in bytes.
%
% (2) "Whos" will always display all array dimensions whereas "whos" will
%     not display array dimensions for 4th and higher dimensional arrays.
%
%
%EXAMPLE: Given arrays
%
%  A=rand(10,20,30,40);
%  B=rand(5,10,15,20,25,'single')*i;
%
%using "whos" displays the following:
%
%>> whos
%   Name      Size              Bytes  Class     Attributes
%
%   A         4-D             1920000  double
%   B         5-D             3000000  single    complex
%
%
%whereas "Whos" will display the following
%
%>> Whos
%   Name   Size              Kilobytes     Class    Attributes
%
%   A      10x20x30x40            1875     double
%   B      5x10x15x20x25          2930     single   complex
%
%
%An unfortunate limitation is that Whos relies on EVALIN and so will not work
%correctly in a workspace context reached using DBUP and DBDOWN.
%I elaborate on this somewhat in this Newsgroup thread:
%
%      http://www.mathworks.com/matlabcentral/newsreader/view_thread/303357
%
%Hopefully, TMW will provide a way around this eventually.
%
%by Matt Jacobson
%
%Copyright, Xoran Technologies, Inc. 2011

if nargin==0

  cmdstr='whos;';
  s=evalin('caller', cmdstr) ;

else

     in=['''' varargin{1} ''''];

     numargs=length(varargin);

     if numargs>1
       for ii=2:numargs
         in= [in ',' '''' varargin{ii} ''''];
       end
     end

     cmdstr=['whos(' in  ');'];

     s=evalin('caller', cmdstr) ;

end

flds=fieldnames(s);
idx=strmatch('bytes',flds);
flds{idx}='kilobytes';
S=rmfield(s,'bytes');
[S.kilobytes]=deal([]);
S=orderfields(S,flds);

deepestLevel=S(1).nesting.level;
setAns=strmatch('ans',{S.name});
idx=[];
for ii=setAns(:).'

    if isequal(S(ii).class,'(unassigned)') && S(ii).nesting.level==deepestLevel
       idx=ii;
    end

end
S(idx)=[];

N=length(S);

sizeStrings=cell(N,1);
memStrings=cell(N,1);
attributesStrings=cell(N,1);
nestFuncs=cell(1,N);
nestLevels=nan(N,1);
 lastLevel=nan;

blockCounts=zeros(1,N);
blockIndex=0;

for ii=1:N

    sizeStrings{ii}=regexprep(num2str(S(ii).size),'\s*','x');

    S(ii).kilobytes=s(ii).bytes/2^10;
    if S(ii).kilobytes>=10

     memStrings{ii}=num2str(ceil(S(ii).kilobytes));
    else
     memStrings{ii}=num2str(S(ii).kilobytes,'%2.3f');
    end

    str='';

    if S(ii).persistent,  str=[str,'persistent, ']; end
    if S(ii).global,   str=[str,'global, ']; end
    if S(ii).sparse,   str=[str,'sparse, ']; end
    if S(ii).complex,  str=[str,'complex, ']; end

    idx=find(str==',',1,'last');
    str(idx:end)='';
    if isempty(str), str=' '; end

    attributesStrings{ii}=str;

    thisLevel=S(ii).nesting.level;
    nestLevels(ii)=thisLevel;

    if thisLevel~=lastLevel

       lastLevel=thisLevel;
       blockIndex=blockIndex+1;
       nestFuncs{ii}=S(ii).nesting.function;

    end

    blockCounts(blockIndex)=blockCounts(blockIndex)+1;

end

if ~nargout

  blockCounts=nonzeros(blockCounts);
  nestFuncs=nestFuncs( ~cellfun('isempty',nestFuncs)) ;
    nestFuncs=cellfun(@(str) ['  ---- ',str,' -'] , nestFuncs(:), 'UniformOutput',0);

  NameCol=char('Name',' ',S.name);
  SizeCol=char('Size',' ',sizeStrings{:});

  ClassCol=char('Class',' ',S.class);
  AttributesCol=char('Attributes',' ',attributesStrings{:});

  %%Right justify the memory footprints
  memStrings=cellfun(@fliplr, memStrings,'UniformOutput',0);
  MegCol=fliplr( char(fliplr('Kilobytes'),' ',memStrings{:}));

  %% set up the display table

  d=repmat(' ',N+2,1);
  dd=[d,d];
  ddd=[dd,d];

  DisplayTable=[dd,NameCol,ddd,...
                SizeCol,ddd,dd,...
                MegCol, ddd,dd,...
                ClassCol, ddd,...
                AttributesCol];

  DisplayTable=char(DisplayTable,' ');

  if length(blockCounts)>1

      subTable=DisplayTable(3:end-1,:);
      subTable=mat2cell(subTable,blockCounts,size(subTable,2));
      subTable=[repmat({' '},size(subTable,1),1)  , nestFuncs,subTable ];
      subTable=subTable.';
      subTable=char(subTable{:});

      DisplayTable=char( DisplayTable(1,:), subTable, DisplayTable(end,:) );

      divs=strmatch('  ----',DisplayTable);

      for ii=1:length(divs)

          jj=divs(ii);

          kk=find(DisplayTable(jj,:)=='-',1,'last');

          DisplayTable(jj,kk+1:end)='-';
      end

   end

  disp(DisplayTable)

else

    varargout{1}=S;

end


function [w,successList] = dmc_station_meta(w,varargin)

%DMC_STATION_META adds station metadata to a waveform
%  W = DMC_STATION_META(W) looks up station metadata at the IRIS Data
%  Management Center (DMC) based on the network, station and time of each
%  waveform. These fields are added to the waveform. W may be of aritrary
%  size and dimension. If a particular network-station-time combination is
%  not found at the DMC, that particular waveform is returned as is with no
%  additional fields.
%    STATION_STARTDATE        On date of the station (Matlab date format)
%    STATION_ENDDATE          Off date of the station (Matlab date format)
%    STATION_LATITUDE         latitude in degrees (double)
%    STATION_LONGITUDE        longitude in degress (double)
%    STATION_ELEVATION        elevation above sea level in meters (double)
%    STATION_NAME             full station name (text string)
%    STATION_NUMBEROFCHANNELS no. channels from station (double)
%
%  [W,SUCCESS] = DMC_STATION_META(W) returns a matrix SUCCESS which is the
%  same size as W. SUCCESS is a mask containing ones and zeros that can be
%  used to identify which waveforms where successfully tagged with metadata
%  from the DMC. Reasons that the metadata lookup might fail include:
%       - this network-station is not on record at the DMC
%       - this network-station is not on record at the time range requested
%       - there was no internet connection at the time of connection
%       - the DMC's web services were down (rare, but does happen)
%
%  [W,SUCCESS] = DMC_STATION_META(W,'CheckEach') For speed, this function
%  only looks up a given network-station combination once and applies it
%  to all elements of W that match the network-station. This is reasonable
%  for most W that might contain many waveforms from the same station and
%  general time range (e.g. a swarm of earthquakes over a few months). In
%  cases where the user suspects station data may have changed (e.g. a
%  decade of earthquakes from an unfamiliar network), the CheckEach flag
%  rerequests metadata for each individual waveform

%  AUTHOR: Michael West, Geophysical Institute, Univ. of Alaska Fairbanks
%  $Date$
%  $Revision$

% SETTINGS
httpServer = 'http://www.iris.edu/ws/station/';

% CHECK ARGUMENTS
if numel(varargin)>1
   error('dmc_station_meta:incorrectNumberArguments','Incorrect number of arguments');
end
if ~strcmpi(class(w),'waveform')
    error('dmc_station_meta:missingWaveform','First input must be a waveform object');
end
checkEach = 0;
if numel(varargin)>=1
    if strcmpi(varargin{1},'checkEach')
        checkEach = 1;
    end
end

% GET LIST OF UNIQUE CALLS TO SERVER
indexList = {[]};
if ~checkEach
    scnl = get(w,'SCNLOBJECT');
    netSta = cellstr(strcat([char(get(scnl,'NETWORK')) char(get(scnl,'STATION')) ]));
    uniqueSta = unique(netSta);
    for n = 1:length(uniqueSta)
        indexList(n) = {find(strcmpi(netSta,uniqueSta(n)))};
    end
else
    for n =1:length(w)
        indexList(n) = {n};
    end
end

% LOOP THROUGH THE SERVER CALLS
successList = zeros(size(w));
for n = 1:numel(indexList)
    index = indexList{n};
    scnlRequest = get(w(index(1)),'SCNLOBJECT');
    station = upper(get(scnlRequest,'STATION'));
    network = upper(get(scnlRequest,'NETWORK'));
    timeStart =  datestr(floor(get(w(index(1)),'START')),'yyyy-mm-dd');
    timeEnd   =  datestr(ceil(get(w(index(1)),'END')),'yyyy-mm-dd');
    httpLink = [httpServer 'query?net=' network '&sta=' station  '&timewindow=' timeStart ',' timeEnd '&level=sta'];
    %disp(httpLink);
    [s,success] = dmc_xml2struct(httpLink);
    if success
        w(index) = addfield(w(index),'STATION_STARTDATE',datenum(s.StaMessage.Station.StationEpoch.StartDate.Text,'yyyy-mm-ddTHH:MM:SS'));
        w(index) = addfield(w(index),'STATION_ENDDATE',datenum(s.StaMessage.Station.StationEpoch.EndDate.Text,'yyyy-mm-ddTHH:MM:SS'));
        w(index) = addfield(w(index),'STATION_LATITUDE',str2double(s.StaMessage.Station.StationEpoch.Lat.Text));
        w(index) = addfield(w(index),'STATION_LONGITUDE',str2double(s.StaMessage.Station.StationEpoch.Lon.Text));
        w(index) = addfield(w(index),'STATION_ELEVATION',str2double(s.StaMessage.Station.StationEpoch.Elevation.Text));
        w(index) = addfield(w(index),'STATION_NAME',char(s.StaMessage.Station.StationEpoch.Site.Country.Text));
        w(index) = addfield(w(index),'STATION_NUMBEROFCHANNELS',str2double(s.StaMessage.Station.StationEpoch.NumberChannels.Text));
        successList(index) = 1;
    end
end


function v = sr_clamp(v, vLowerB, vUpperB)

% SC_CLAMP: clamp value v

v = max(v, vLowerB);
v = min(v, vUpperB);

end


function x = gpl_curve ( filename, m, n )

%*****************************************************************************80
%
%% GPL_CURVE reads a GPL file of 1D, 2D or 3D data.
%
%  Discussion:
%
%    The GPL file is assumed to consist of a single list of 1D, 2D or 3D data.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 May 2014
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string FILENAME, the name of the input file.
%
%    Input, integer M, the spatial dimension.
%
%    Input, integer N, the number of data values.
%
%    Output, real X(M,N), the data.
%
  x = zeros ( m, n );

  file = fopen ( filename, 'rt' );

  line_num = 0;

  for j = 1 : n

    while ( 1 )

      line_num = line_num + 1;
      s = fgetl ( file );
%
%  Unexpected end of file?
%
      if ( ~ ischar ( s ) )
        fprintf ( 1, '\n' );
        fprintf ( 1, 'GPL_CURVE - Fatal error!\n' );
        fprintf ( 1, '  Unexpected end of file reading line %d\n', line_num );
        error ( 'GPL_CURVE - Fatal error!\n' );
      end
%
%  Unexpected empty line?
%
      if ( length ( s ) < 1 )
        fprintf ( 1, '\n' );
        fprintf ( 1, 'GPL_CURVE - Fatal error!\n' );
        fprintf ( 1, '  Unexpected empty record, reading line %d\n', line_num );
        error ( 'GPL_CURVE - Fatal error!\n' );
      end
%
%  Comments are OK.
%
      if ( s(1) ~= '#' )
        break
      end

    end
%
%  Otherwise, read X
%
    [ values, count ] = sscanf ( s, '%f' );
%
%  Failed to read M things?
%
    if ( count ~= m )
      fprintf ( 1, '\n' );
      fprintf ( 1, 'GPL_CURVE - Fatal error!\n' );
      fprintf ( 1, '  Did not get %d data items on line %d\n', m, line_num );
      error ( 'GPL_CURVE - Fatal error!\n' );
    end

    x(1:m,j) = values(1:m)';

  end

  fclose ( file );

  return
end


function value = p25_autonomous ( )

%*****************************************************************************80
%
%% P25_AUTONOMOUS reports whether problem P25 is autonomous.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    17 February 2013
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Output, integer VALUE, is 1 if the equation is autonomous.
%
  value = 0;

  return
end


function plotPointClouds(M, B, markerm, markerb)
    if (nargin < 4)
        markerm = 'r.';
    end
    if (nargin < 3)
        markerb = 'b.';
    end
    %figure;
    plot3(M(1,:), M(2,:), M(3,:), markerm, B(1,:), B(2,:), B(3,:), markerb, 'MarkerSize',0.8);
    axis off;

end


function ellipsoid_grid_test ( )

%*****************************************************************************80
%
%% ELLIPSOID_GRID_TEST tests the ELLIPSOID_GRID library.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    04 September 2010
%
%  Author:
%
%    John Burkardt
%
  timestamp ( );
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ELLIPSOID_GRID_TEST:\n' );
  fprintf ( 1, '  MATLAB version\n' );
  fprintf ( 1, '  Test the ELLIPSOID_GRID library.\n' );

  ellipsoid_grid_test01 ( );
%
%  Terminate.
%
  fprintf ( 1, '\n' );
  fprintf ( 1, 'ELLIPSOID_GRID_TEST:\n' );
  fprintf ( 1, '  Normal end of execution.\n' );
  fprintf ( 1, '\n' );
  timestamp ( );

  return
end


function [compartmentReactions] = findRxnFromCompartment(model, compartment)
% Finds all the reactions and their identifiers in a compartment of interest.
%
% USAGE:
%
%    [compartmentReactions] = findRxnFromCompartment(model,Compartment)
%
% INPUTS:
%    model:                     COBRA model strcture
%    compartment:               compartment of interest (e.g.: '[m]', '[n]', '[e]', etc.)
%
% OUTPUT:
%    compartmentMetabolites:    List of reactions in the compartment of interest
%
% .. Authors:
%       - written by Diana El Assal 01/06/16
%       - rewritten by Uri David Akavia 6-Jul-2018

if (length(compartment) == 1)
    compartment = ['[' compartment ']'];
end
% Find mets in this compartment
compartmentMets = ~cellfun(@isempty, strfind(model.mets, compartment));
% Find reactions that involve the above mets
compartmentRxns = model.rxns(any(model.S(compartmentMets, :)));
compartmentReactions = [compartmentRxns, printRxnFormula(model, 'rxnAbbrList', compartmentRxns, 'printFlag', false)];


function suite = test_assertVectorsAlmostEqual
initTestSuite;

%===============================================================================
function test_happyCase

A = [1 1e10];
B = [2 1e10];
% All code here should execute with no error.
assertVectorsAlmostEqual(A, B);
assertVectorsAlmostEqual(A, B, 'custom message');

%===============================================================================
function test_failedAssertion

A = [1 1e6];
B = [2 1e6];

f = @() assertVectorsAlmostEqual(A, B);
assertExceptionThrown(f, 'assertVectorsAlmostEqual:tolExceeded');

%===============================================================================
function test_failedAssertionWithCustomMessage

A = [1 1e6];
B = [2 1e6];
f = @() assertVectorsAlmostEqual(A, B, 'my message');
assertExceptionThrown(f, 'assertVectorsAlmostEqual:tolExceeded');

%===============================================================================
function test_nonFloatInputs()
assertExceptionThrown(@() assertVectorsAlmostEqual('hello', 'world'), ...
    'assertVectorsAlmostEqual:notFloat');

%===============================================================================
function test_sizeMismatch()
assertExceptionThrown(@() assertVectorsAlmostEqual(1, [1 2]), ...
    'assertVectorsAlmostEqual:sizeMismatch');

%===============================================================================
function test_finiteAndInfinite()
assertExceptionThrown(@() assertVectorsAlmostEqual([1 2], [1 Inf]), ...
    'assertVectorsAlmostEqual:tolExceeded');

%===============================================================================
function test_infiniteAndInfinite
assertExceptionThrown(@() assertVectorsAlmostEqual([1 Inf], [1 Inf]), ...
    'assertVectorsAlmostEqual:tolExceeded');

%===============================================================================
function test_finiteAndNaN
assertExceptionThrown(@() assertVectorsAlmostEqual([1 2], [1 NaN]), ...
    'assertVectorsAlmostEqual:tolExceeded');

%===============================================================================
function test_NanAndNan
assertExceptionThrown(@() assertVectorsAlmostEqual([1 NaN], [1 NaN]), ...
    'assertVectorsAlmostEqual:tolExceeded');

%===============================================================================
function test_oppositeSignInfs
assertExceptionThrown(@() assertVectorsAlmostEqual([1 Inf], [1 -Inf]), ...
    'assertVectorsAlmostEqual:tolExceeded');


function [nVar, lowerbound, upperbound] = getVarInfo(obj)
    % The function returns the dimension, upper/lower limits of NLP
    % variables.
    %
    % Return values:
    %  nVar: the total dimension of all NLP variables @type
    %  integer
    %  lowerbound: the lower limits @type colvec
    %  upperbound: the upper limits @type colvec

    assert(~isempty(obj.VariableArray),...
        'NonlinearProgram:emptyVarArray',...
        ['No variable has been definied.\n',...
        'Please define NLP variables first.\n']);

    nVar = sum([obj.VariableArray.Dimension]);
    lowerbound = vertcat(obj.VariableArray.LowerBound);
    upperbound = vertcat(obj.VariableArray.UpperBound);

end


%                               manageOptionsForBenchmark.m
%
% This file consists of functions used to check the validity of
% user-provided options, provideds default values
% for those unspecified options and raises warnings for those unnecessary
% but user-provided fields.
%
% manageOptionsForBenchmark invokes helper functions getExtraOpts,
% applyOpts, and warnExtraOpts in the folder util/.
% It is used in the general benchmark interface benchmarkPR.m.
%
%
% PhasePack by Rohan Chandra, Ziyuan Zhong, Justin Hontz, Val McCulloch,
% Christoph Studer, & Tom Goldstein
% Copyright (c) University of Maryland, 2017

% This function integrates the user specified values and default values for
% fields in opts and raises warning for those unnecessary but user-provided
% fields.
% params is as defined in benchmarkPR.m. See its header or User Guide for
% details.
function params = manageOptionsForBenchmark(dataSet, params)

    % Obtain and apply default options recognized by a dataSet
    defaults = getDefaultOptsForBenchmack(dataSet);
    extras = getExtraOpts(params, defaults);
    params = applyOpts(params, defaults, false);

    % Warn the user regarding unrecognized options
    if ~strcmp(dataSet, 'custom')
        warnExtraOpts(extras);
    end
end

% Return a struct that consists of all the special field(initialized to default values)
% for the dataSet
function params = getDefaultOptsForBenchmack(dataSet)
    % General options
    params.verbose = true;           % If true, each trial's result will be reported.
    params.plotType = 'auto';    % The type of the plot generated. It
                                     % currently supports ['semilogy', 'linear','auto'].
    params.numTrials = 1;             % The number of trials each algorithm/dataset
                                     % combination will run.
    params.policy = 'median';        % How to compute the final yvalue used
                                     % for ploting from the yvalues one get
                                     % by running numTrials trials. It
                                     % currently supports
                                     % ['median','average','best',
                                     % 'successRate']
    params.successConstant = 1e-5;   % If the yvalue of the current trial
                                     % is less than it,
                                     % the trial will be counted as a
                                     % success. This parameter will only be
                                     % used when policy='successRate'.
    params.maxTime = 300;            % max time allowed for a single
                                     % algorithm/dataset trial.

    params.recordSignals = false;    % whether record the recovered signal
                                     % at each trial.

    % Specific options
    switch lower(dataSet)
        case '1dgaussian'
            params.n = 10;                        % Length of the unknown
                                                  % signal
            params.m = 80;                        % Number of measurements
            params.isComplex = true;              % If the signal is complex
            params.isNonNegativeOnly = false;     % If the signal is real
                                                  % and non-negative
            params.SNR = inf;                     % Signal-to-noise ratio
        case '2dimage'
            params.imagePath = 'data/shapes.png'; % Image path
            params.L = 12;                        % Number of of masks
                                                  % created
        case 'transmissionmatrix'
            params.n=256;
            params.m=256*20;
            params.isComplex = true;              % If the signal is complex
            params.isNonNegativeOnly = false;     % If the signal is real
                                                  % and non-negative
        otherwise
            error('unknown dataset: %s\n',dataSet);
    end
end


function r8mat_write ( output_filename, m, n, table )

%*****************************************************************************80
%
%% R8MAT_WRITE writes an R8MAT file.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    09 August 2009
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, string OUTPUT_FILENAME, the output filename.
%
%    Input, integer M, the spatial dimension.
%
%    Input, integer N, the number of points.
%
%    Input, real TABLE(M,N), the points.
%

%
%  Open the file.
%
  output_unit = fopen ( output_filename, 'wt' );

  if ( output_unit < 0 )
    fprintf ( 1, '\n' );
    fprintf ( 1, 'R8MAT_WRITE - Error!\n' );
    fprintf ( 1, '  Could not open the output file.\n' );
    error ( 'R8MAT_WRITE - Error!' );
    return;
  end
%
%  Write the data.
%
  for j = 1 : n
    for i = 1 : m
      fprintf ( output_unit, '  %24.16f', table(i,j) );
    end
    fprintf ( output_unit, '\n' );
  end
%
%  Close the file.
%
  fclose ( output_unit );

  return
end


function [out1,out2,out3] = ginput_OH(arg1,strpointertype,xx,yy)

% function [X,Y,BUTTON] = ginput_OH(N,pointertype,xx,yy)
%
% ginput_OH.m has the same functionality as Matlab's ginput.m with
% two additional features:
% 1. From the first click onward the pointer is connected to the previous
%    mouse click by a line.
% 2. Selectable cursor pointer (copied from MYGINPUT by F. Moisy)
%
% INPUT:
% N = number of points
% pointertype: 'fullcrosshair','crosshair','arrow','circle'etc.
%           See "Specifying the Figure Pointer" in Matlab's documentation
%           to see the list of available pointers. (default = 'fullcrosshair')
% xx      : reference for line of first point (used by clickfit_OH)
% yy      : reference for line of first point (used by clickfit_OH)
%
% OUTPUT:
% X     : x-coordinates of the clicked series
% Y     : y-coordinates of the clicked series
% BUTTON : see GINPUT
%
% USES:
% ginput.m rev.  5.32.4.13 (M2009a)
% gline.m rev.  2.12.2.5 (M2009a)
% MYGINPUT by F. Moisy (../fileexchange/12770-myginput)
%
% USED by:
% clickfit_OH.m
%
% Author:   Oscar Hartogensis (oscar.hartogensis at wur.nl)
% Date:     Januari 2010
% Rev:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Adjusted by MYGINPUT and ginput_OH
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if nargin<2 strpointertype='fullcrosshair'; end
if nargin<4 xx=[]; yy=[]; end
first_run = 1;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

out1 = []; out2 = []; out3 = []; y = [];
c = computer;
if ~strcmp(c(1:2),'PC')
   tp = get(0,'TerminalProtocol');
else
   tp = 'micro';
end

if ~strcmp(tp,'none') && ~strcmp(tp,'x') && ~strcmp(tp,'micro'),
   if nargout == 1,
      if nargin == 1,
         out1 = trmginput(arg1);
      else
         out1 = trmginput;
      end
   elseif nargout == 2 || nargout == 0,
      if nargin == 1,
         [out1,out2] = trmginput(arg1);
      else
         [out1,out2] = trmginput;
      end
      if  nargout == 0
         out1 = [ out1 out2 ];
      end
   elseif nargout == 3,
      if nargin == 1,
         [out1,out2,out3] = trmginput(arg1);
      else
         [out1,out2,out3] = trmginput;
      end
   end
else

   fig = gcf;
   figure(gcf);

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Adjusted by ginput_OH
    % Copy-Paste from gline.m rev.  2.12.2.5 (M2009a)
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    draw_fig = gcf;
    ax = get(draw_fig,'CurrentAxes');
    if isempty(ax)
       ax = axes('Parent',draw_fig);
    end

    oldtag = get(draw_fig,'Tag');
    figure(draw_fig);
    if any(get(ax,'view')~=[0 90]),
     set(draw_fig, 'Tag', oldtag);
     error('stats:gline:NotTwoDimensional','GLINE works only for 2-D plots.');
    end

    % Can't do this if another mouse mode is active
    hManager = uigetmodemanager(draw_fig);
    if (~isempty(hManager.CurrentMode))
       error('stats:gline:ModeActive',...
             'Cannot use GLINE while the mouse mode ''%s'' is active.',...
             get(hManager.CurrentMode,'name'))
    end

    % Create an invisible line to preallocate the xor line color.
    xlimits = get(ax,'Xlim');
    x_gl = (xlimits + flipud(xlimits))./2;
    ylimits = get(ax,'Ylim');
    y_gl = (ylimits + flipud(ylimits))./2;
    hline = line(x_gl,y_gl,'Parent',ax,'Visible','off');

    bdown = get(draw_fig,'WindowButtonDownFcn');
    bup = get(draw_fig,'WindowButtonUpFcn');
    bmotion = get(draw_fig,'WindowButtonMotionFcn');
    oldud = get(draw_fig,'UserData');
    %    set(draw_fig,'WindowButtonDownFcn','gline(''down'')')
    %    set(draw_fig,'WindowButtonMotionFcn','gline(''motion'')')
    %    set(draw_fig,'WindowButtonupFcn','')

    ud.hline = hline;
    ud.pts = [xx,yy;xx,yy];
    ud.buttonfcn = {bdown; bup; bmotion};
    ud.oldud = oldud;
    ud.oldtag = oldtag;
    set(draw_fig,'UserData',ud);
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

   if nargin == 0
      how_many = -1;
      b = [];
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   % Adjusted by ginput_OH
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   elseif isempty(arg1)
      how_many = -1;
      b = [];
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   else
      how_many = arg1;
      b = [];
      if  ischar(how_many) ...
            || size(how_many,1) ~= 1 || size(how_many,2) ~= 1 ...
            || ~(fix(how_many) == how_many) ...
            || how_many < 0
         error('MATLAB:ginput:NeedPositiveInt', 'Requires a positive integer.')
      end
      if how_many == 0
         ptr_fig = 0;
         while(ptr_fig ~= fig)
            ptr_fig = get(0,'PointerWindow');
         end
         scrn_pt = get(0,'PointerLocation');
         loc = get(fig,'Position');
         pt = [scrn_pt(1) - loc(1), scrn_pt(2) - loc(2)];
         out1 = pt(1); y = pt(2);
      elseif how_many < 0
         error('MATLAB:ginput:InvalidArgument', 'Argument must be a positive integer.')
      end
   end

   % Suspend figure functions
   state = uisuspend(fig);

   toolbar = findobj(allchild(fig),'flat','Type','uitoolbar');
   if ~isempty(toolbar)
        ptButtons = [uigettool(toolbar,'Plottools.PlottoolsOff'), ...
                     uigettool(toolbar,'Plottools.PlottoolsOn')];
        ptState = get (ptButtons,'Enable');
        set (ptButtons,'Enable','off');
   end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Adjusted by MYGINPUT
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    set(fig,'pointer',strpointertype);  % modified MYGINPUT
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % Adjusted by ginput_OH
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if ~isempty(ud.pts)
        set(draw_fig,'WindowButtonMotionFcn',@motion)
    end
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

   fig_units = get(fig,'units');
   char = 0;

   % We need to pump the event queue on unix
   % before calling WAITFORBUTTONPRESS
   drawnow

   while how_many ~= 0

      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      % Adjusted by ginput_OH
      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      if ~first_run
          ud.pts = [pt(1,1),pt(1,2);pt(1,1),pt(1,2)];
          set(draw_fig,'WindowButtonMotionFcn',@motion)
      end
      %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

      % Use no-side effect WAITFORBUTTONPRESS
      waserr = 0;
      try
	keydown = wfbp;
      catch
	waserr = 1;
      end
      if(waserr == 1)
         if(ishghandle(fig))
            set(fig,'units',fig_units);
	    uirestore(state);
            error('MATLAB:ginput:Interrupted', 'Interrupted');
         else
            error('MATLAB:ginput:FigureDeletionPause', 'Interrupted by figure deletion');
         end
      end
        % g467403 - ginput failed to discern clicks/keypresses on the figure it was
        % registered to operate on and any other open figures whose handle
        % visibility were set to off
        figchildren = allchild(0);
        if ~isempty(figchildren)
            ptr_fig = figchildren(1);
        else
            error('MATLAB:ginput:FigureUnavailable','No figure available to process a mouse/key event');
        end
%         old code -> ptr_fig = get(0,'CurrentFigure'); Fails when the
%         clicked figure has handlevisibility set to callback
      if(ptr_fig == fig)
         if keydown
            char = get(fig, 'CurrentCharacter');
            button = abs(get(fig, 'CurrentCharacter'));
            scrn_pt = get(0, 'PointerLocation');
            set(fig,'units','pixels')
            loc = get(fig, 'Position');
            % We need to compensate for an off-by-one error:
            pt = [scrn_pt(1) - loc(1) + 1, scrn_pt(2) - loc(2) + 1];
            set(fig,'CurrentPoint',pt);
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            % Adjusted by ginput_OH
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
            if ~first_run && ~isempty(ud.pts)
                set(ud.hline,'Xdata',ud.pts(:,1),'Ydata',ud.pts(:,2), 'Visible','off');
            end
            %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
         else
            button = get(fig, 'SelectionType');
            if strcmp(button,'open')
               button = 1;
            elseif strcmp(button,'normal')
               button = 1;
            elseif strcmp(button,'extend')
               button = 2;
            elseif strcmp(button,'alt')
               button = 3;
            else
               error('MATLAB:ginput:InvalidSelection', 'Invalid mouse selection.')
            end
         end
         pt = get(gca, 'CurrentPoint');

         how_many = how_many - 1;

         if(char == 13) % & how_many ~= 0)
            % if the return key was pressed, char will == 13,
            % and that's our signal to break out of here whether
            % or not we have collected all the requested data
            % points.
            % If this was an early breakout, don't include
            % the <Return> key info in the return arrays.
            % We will no longer count it if it's the last input.
            break;
         end

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        % Adjusted by ginput_OH
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        first_run = 0;
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

         out1 = [out1;pt(1,1)];
         y = [y;pt(1,2)];
         b = [b;button];
      end
   end

   uirestore(state);
   if ~isempty(toolbar) && ~isempty(ptButtons)
        set (ptButtons(1),'Enable',ptState{1});
        set (ptButtons(2),'Enable',ptState{2});
   end
   set(fig,'units',fig_units);

   if nargout > 1
      out2 = y;
      if nargout > 2
         out3 = b;
      end
   else
      out1 = [out1 y];
   end

   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   % Adjusted by ginput_OH
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   if ~first_run && ~isempty(ud.pts)
       set(ud.hline,'Xdata',ud.pts(:,1),'Ydata',ud.pts(:,2), 'Visible','off');
   end
   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Adjusted by ginput_OH
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function motion(varargin)
   % Copy-Paste from gline.m (case 'motion') rev.  2.12.2.5 (M2009a)
   set(ud.hline,'Xdata',ud.pts(:,1),'Ydata',ud.pts(:,2), ...
        'linestyle','-', 'linewidth', 1.5, 'Color','r','Visible','on');
   Pt2 = get(ax,'CurrentPoint');
   Pt2 = Pt2(1,1:2);
   ud.pts(2,:) = Pt2;
   set(draw_fig,'UserData',ud);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function key = wfbp
%WFBP   Replacement for WAITFORBUTTONPRESS that has no side effects.

fig = gcf;
current_char = [];

% Now wait for that buttonpress, and check for error conditions
waserr = 0;
try
  h=findall(fig,'type','uimenu','accel','C');   % Disabling ^C for edit menu so the only ^C is for
  set(h,'accel','');                            % interrupting the function.
  keydown = waitforbuttonpress;
  current_char = double(get(fig,'CurrentCharacter')); % Capturing the character.
  if~isempty(current_char) && (keydown == 1)           % If the character was generated by the
	  if(current_char == 3)                       % current keypress AND is ^C, set 'waserr'to 1
		  waserr = 1;                             % so that it errors out.
	  end
  end

  set(h,'accel','C');                                 % Set back the accelerator for edit menu.
catch
  waserr = 1;
end
drawnow;
if(waserr == 1)
   set(h,'accel','C');                                % Set back the accelerator if it errored out.
   error('MATLAB:ginput:Interrupted', 'Interrupted');
end

if nargout>0, key = keydown; end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

end

end


function test_suite = test_comparisonMessage
%test_comparisonMessage Unit test for comparisonMessage.

%   Steven L. Eddins
%   Copyright 2009 The MathWorks, Inc.

initTestSuite;

function test_happyCase
s = xunit.utils.comparisonMessage('user message', 'assertion message', ...
    [1 2 3], 'hello');
c = xunit.utils.stringToCellArray(s);

expected_output = { 'user message'
    'assertion message'
    ''
    'First input:'
    '     1     2     3'
    ''
    'Second input:'
    'hello'};

assertEqual(c, expected_output);


function y = cvx_basis( x )
y = x.basis_;

% 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.


classdef Rx < adi.AD9361.Base & adi.AD9361.TuneAGC & ...
        adi.common.Rx
    % adi.AD9361.Rx Receive data from the AD9361 transceiver
    %   The adi.AD9361.Rx System object is a signal source that can receive
    %   complex data from the AD9361.
    %
    %   rx = adi.AD9361.Rx;
    %   rx = adi.AD9361.Rx('uri','192.168.2.1');
    %
    %   AD9361 Datasheet
    %
    %   See also adi.FMComms2.Rx, adi.FMComms3.Rx, adi.FMComms5.Rx

    properties
        %CenterFrequency Center Frequency
        %   RF center frequency, specified in Hz as a scalar. The
        %   default is 2.4e9.  This property is tunable.
        CenterFrequency = 2.4e9;
        %SamplingRate Sampling Rate
        %   Baseband sampling rate in Hz, specified as a scalar
        %   from 65105 to 61.44e6 samples per second.
        SamplingRate = 3e6;
        %RFBandwidth RF Bandwidth
        %   RF Bandwidth of front-end analog filter in Hz, specified as a
        %   scalar from 200 kHz to 56 MHz.
        RFBandwidth = 3e6;
    end

    properties
        %GainControlModeChannel0 Gain Control Mode Channel 0
        %   specified as one of the following:
        %   'slow_attack' — For signals with slowly changing power levels
        %   'fast_attack' — For signals with rapidly changing power levels
        %   'manual' — For setting the gain manually with the Gain property
        %   'hybrid' — For configuring hybrid AGC mode
        GainControlModeChannel0 = 'slow_attack';
        %GainChannel0 Gain Channel 0
        %   Channel 0 gain, specified as a scalar from -4 dB to 71 dB. The acceptable
        %   minimum and maximum gain setting depends on the center
        %   frequency.
        GainChannel0 = 10;
        %GainControlModeChannel1 Gain Control Mode Channel 1
        %   specified as one of the following:
        %   'slow_attack' — For signals with slowly changing power levels
        %   'fast_attack' — For signals with rapidly changing power levels
        %   'manual' — For setting the gain manually with the Gain property
        %   'hybrid' — For configuring hybrid AGC mode
        GainControlModeChannel1 = 'slow_attack';
        %GainChannel1 Gain Channel 1
        %   Channel 1 gain, specified as a scalar from -4 dB to 71 dB. The acceptable
        %   minimum and maximum gain setting depends on the center
        %   frequency.
        GainChannel1 = 10;
    end

    properties (Nontunable)
        %DigitalLoopbackMode Digital Loopback Mode
        %   Option to set digital loopback mode, specified as 0,
        %   1 or 2. Allows either to digitally loopback TX data
        %   into the RX path or vice versa.
        %    Value   |    Mode
        %   ---------------------------
        %      0     |   Disable
        %      1     |   Digital TX -> Digital RX
        %      2     |   RF RX -> RF TX
        LoopbackMode = 0;
    end

    properties (Nontunable, Logical) % MUST BE NONTUNABLE OR SIMULINK WARNS
        %EnableQuadratureTracking Enable Quadrature Tracking
        %   Option to enable quadrature tracking, specified as true or
        %   false. When this property is true, IQ imbalance compensation is
        %   applied to the input signal.
        EnableQuadratureTracking = true;
        %EnableRFDCTracking Enable RFDC Tracking
        %   Option to enable RF DC tracking, specified as true or false.
        %   When this property is true, an RF DC blocking filter is applied
        %   to the input signal.
        EnableRFDCTracking = true;
        %EnableBasebandDCTracking Enable Baseband DC Tracking
        %   Option to enable baseband DC tracking, specified as true or
        %   false. When this property is true, a baseband DC blocking
        %   filter is applied to the input signal.
        EnableBasebandDCTracking = true;
    end

    properties
        %RFPortSelect RF Port Select
        %    'A_BALANCED'
        %    'B_BALANCED'
        %    'C_BALANCED'
        %    'A_N'
        %    'A_P'
        %    'B_N'
        %    'B_P'
        %    'C_N'
        %    'C_P'
        %    'TX_MONITOR1'
        %    'TX_MONITOR2'
        %    'TX_MONITOR1_2'
        RFPortSelect = 'A_BALANCED';
    end

    properties(Constant, Hidden)
        GainControlModeChannel0Set = matlab.system.StringSet({ ...
            'manual','fast_attack','slow_attack','hybrid'});
        GainControlModeChannel1Set = matlab.system.StringSet({ ...
            'manual','fast_attack','slow_attack','hybrid'});
        RFPortSelectSet = matlab.system.StringSet({ ...
            'A_BALANCED', 'B_BALANCED', 'C_BALANCED',...
            'A_N', 'A_P', 'B_N', 'B_P', 'C_N', 'C_P',...
            'TX_MONITOR1', 'TX_MONITOR2', 'TX_MONITOR1_2'});
    end

    properties (Hidden, Nontunable, Access = protected)
        isOutput = false;
    end

    properties(Nontunable, Hidden, Constant)
        Type = 'Rx';
        channel_names = {'voltage0','voltage1','voltage2','voltage3'};
    end

    properties (Nontunable, Hidden)
        devName = 'cf-ad9361-lpc';
    end

    methods
        %% Constructor
        function obj = Rx(varargin)
            coder.allowpcode('plain');
            obj = obj@adi.AD9361.Base(varargin{:});
        end
        % Check RFPortSelect
        function set.RFPortSelect(obj, value)
            obj.RFPortSelect = value;
            if obj.ConnectedToDevice
                obj.setAttributeRAW('voltage0','rf_port_select',value,false);
            end
        end
        % Check GainControlModeChannel0
        function set.GainControlModeChannel0(obj, value)
            obj.GainControlModeChannel0 = value;
            if obj.ConnectedToDevice
                id = 'voltage0';
                obj.setAttributeRAW(id,'gain_control_mode',value,false);
            end
        end
        % Check GainControlModeChannel1
        function set.GainControlModeChannel1(obj, value)
            obj.GainControlModeChannel1 = value;
            if obj.ConnectedToDevice
                id = 'voltage1';
                obj.setAttributeRAW(id,'gain_control_mode',value,false);
            end
        end
        % Check GainChannel0
        function set.GainChannel0(obj, value)
            validateattributes( value, { 'double','single' }, ...
                { 'real', 'scalar', 'finite', 'nonnan', 'nonempty', '>=', -4,'<=', 71}, ...
                '', 'Gain');
            assert(mod(value,1/4)==0, 'Gain must be a multiple of 0.25');
            obj.GainChannel0 = value;
            if obj.ConnectedToDevice && strcmp(obj.GainControlModeChannel0,'manual') %#ok<MCSUP>
                id = 'voltage0';
                obj.setAttributeLongLong(id,'hardwaregain',value,false);
            end
        end
        % Check GainChannel1
        function set.GainChannel1(obj, value)
            validateattributes( value, { 'double','single' }, ...
                { 'real', 'scalar', 'finite', 'nonnan', 'nonempty', '>=', -4,'<=', 71}, ...
                '', 'Gain');
            assert(mod(value,1/4)==0, 'Gain must be a multiple of 0.25');
            obj.GainChannel1 = value;
            if obj.ConnectedToDevice && strcmp(obj.GainControlModeChannel1,'manual') %#ok<MCSUP>
                id = 'voltage1';
                obj.setAttributeLongLong(id,'hardwaregain',value,false);
            end
        end
        % Check EnableQuadratureTracking
        function set.EnableQuadratureTracking(obj, value)
            obj.EnableQuadratureTracking = value;
            if obj.ConnectedToDevice
                id = 'voltage0';
                obj.setAttributeBool(id,'quadrature_tracking_en',value,false);
            end
        end
        % Check EnableRFDCTracking
        function set.EnableRFDCTracking(obj, value)
            obj.EnableRFDCTracking = value;
            if obj.ConnectedToDevice
                id = 'voltage0';
                obj.setAttributeBool(id,'rf_dc_offset_tracking_en',value,false);
            end
        end
        % Check EnableRFDCTracking
        function set.EnableBasebandDCTracking(obj, value)
            obj.EnableBasebandDCTracking = value;
            if obj.ConnectedToDevice
                id = 'voltage0';
                obj.setAttributeBool(id,'bb_dc_offset_tracking_en',value,false);
            end
        end
        % Check CenterFrequency
        function set.CenterFrequency(obj, value)
            if isa(obj,'adi.AD9363.Rx')
                validateattributes( value, { 'double','single' }, ...
                    { 'real', 'positive','scalar', 'finite', 'nonnan', 'nonempty','integer','>=',325e6,'<=',3.8e9}, ...
                    '', 'CenterFrequency');
            else
                validateattributes( value, { 'double','single' }, ...
                    { 'real', 'positive','scalar', 'finite', 'nonnan', 'nonempty','integer','>=',70e6,'<=',6e9}, ...
                    '', 'CenterFrequency');
            end
            obj.CenterFrequency = value;
            if obj.ConnectedToDevice
                id = sprintf('altvoltage%d',strcmp(obj.Type,'Tx'));
                obj.setAttributeLongLong(id,'frequency',value,true,4);
            end
        end
        % Check RFBandwidth
        function set.RFBandwidth(obj, value)
            if isa(obj,'adi.AD9363.Rx')
                validateattributes( value, { 'double','single' }, ...
                    { 'real', 'positive','scalar', 'finite', 'nonnan', 'nonempty','integer','>=',200e3,'<=',20e6}, ...
                    '', 'RFBandwidth');
            else
                validateattributes( value, { 'double','single' }, ...
                    { 'real', 'positive','scalar', 'finite', 'nonnan', 'nonempty','integer','>=',200e3,'<=',56e6}, ...
                    '', 'RFBandwidth');
            end
            obj.RFBandwidth = value;
            if obj.ConnectedToDevice && ~obj.EnableCustomFilter
                id = 'voltage0';
                obj.setAttributeLongLong(id,'rf_bandwidth',value,strcmp(obj.Type,'Tx'),30);
            end
        end
        % Check SampleRate
        function set.SamplingRate(obj, value)
            if isa(obj,'adi.AD9363.Rx')
                validateattributes( value, { 'double','single' }, ...
                    { 'real', 'positive','scalar', 'finite', 'nonnan', 'nonempty','integer','>=',520833,'<=',20e6}, ...
                    '', 'SamplesPerFrame');
            else
                validateattributes( value, { 'double','single' }, ...
                    { 'real', 'positive','scalar', 'finite', 'nonnan', 'nonempty','integer','>=',520833,'<=',61.44e6}, ...
                    '', 'SamplesPerFrame');
            end

            obj.SamplingRate = value;
            if obj.ConnectedToDevice && ~obj.EnableCustomFilter
                if libisloaded('libad9361')
                    calllib('libad9361','ad9361_set_bb_rate',obj.iioDevPHY,int32(value));
                else
                    id = 'voltage0';
                    obj.setAttributeLongLong(id,'sampling_frequency',value,true,4);
                end
            end
        end
        function set.LoopbackMode(obj, value)
            validateattributes( value, { 'double','single', 'uint32' }, ...
                { 'real', 'nonnegative','scalar', 'finite', 'nonnan', 'nonempty','integer','>=',0,'<=',2}, ...
                '', 'LoopbackMode');
            obj.LoopbackMode = value;
            if obj.ConnectedToDevice
                obj.setDebugAttributeLongLong('loopback',value);
            end
        end
    end

    %% API Functions
    methods (Hidden, Access = protected)

        function setupInit(obj)
            % Write all attributes to device once connected through set
            % methods
            setupLibad9361(obj);
            % Do writes directly to hardware without using set methods.
            % This is required sine Simulink support doesn't support
            % modification to nontunable variables at SetupImpl

            % Gains
            obj.setAttributeRAW('voltage0','gain_control_mode',obj.GainControlModeChannel0,false);
            if obj.channelCount>2
                obj.setAttributeRAW('voltage1','gain_control_mode',obj.GainControlModeChannel1,false);
            end
            if strcmp(obj.GainControlModeChannel0,'manual')
                obj.setAttributeLongLong('voltage0','hardwaregain',obj.GainChannel0,false);
            end
            if strcmp(obj.GainControlModeChannel1,'manual') && (obj.channelCount>2)
                obj.setAttributeLongLong('voltage1','hardwaregain',obj.GainChannel1,false);
            end
            % Trackings
            obj.setAttributeBool('voltage0','quadrature_tracking_en',obj.EnableQuadratureTracking,false);
            obj.setAttributeBool('voltage0','rf_dc_offset_tracking_en',obj.EnableRFDCTracking,false);
            obj.setAttributeBool('voltage0','bb_dc_offset_tracking_en',obj.EnableBasebandDCTracking,false);
            id = sprintf('altvoltage%d',strcmp(obj.Type,'Tx'));
            obj.setAttributeLongLong(id,'frequency',obj.CenterFrequency ,true,4);
            % Loopback Mode
            obj.setDebugAttributeLongLong('loopback', obj.LoopbackMode);

            % Sample rates and RF bandwidth
            if  ~obj.EnableCustomFilter
                if libisloaded('libad9361')
                    calllib('libad9361','ad9361_set_bb_rate',obj.iioDevPHY,int32(obj.SamplingRate));
                else
                    obj.setAttributeLongLong('voltage0','sampling_frequency',obj.SamplingRate,true,4);
                    obj.setAttributeLongLong('voltage0','rf_bandwidth',obj.RFBandwidth ,strcmp(obj.Type,'Tx'));
                end
            else
                writeFilterFile(obj);
            end
            obj.setAttributeRAW('voltage0','rf_port_select',obj.RFPortSelect,false);

            if (obj.CustomAGC)
                % Initialize hardware to reflect debug attribute changes
                obj.WriteDebugAttributes();
                obj.setDebugAttributeLongLong();
                obj.setDebugAttributeBool();
                obj.WriteToRegisters();
            end

        end

    end

end