%-------------------------------------------------------------------------%
% Part of array visualizer for CoF applications as part of my thesis 
% project titled 'High-density interconnect technology optimised for 
% flexible implants'. This is the main script of the optimizer.
% Full documentation can be found in my thesis report.
%
% Author:   T.B. Hosman
% E-mail:   timhosman@posteo.net
% Version:  1.2
% Created:  01/08/2019
% Modified: 22/08/2019
%-------------------------------------------------------------------------%

close all
clear variables

%% Constants
ARRAY_SIZE = 200; % number of pitch sizes to calculate
PAD_SIZE = 36;    % microns
N_PADS = 10000;   % # of pads
LAYERS = 4;       % number of layers
LW_MIN = 7;       % minimum track width in microns
LS_MIN = 7;       % minimum spacing between tracks in microns
VPS_MIN = 7;      % minimum spacing between via pads in microns
VO_MIN = 10;      % minimum size of via in microns
VLO_MIN = 3.5;    % minimum pad size beyond pad in microns

%% Extracted constants
PITCH_MIN = PAD_SIZE + VPS_MIN;  % minimum pitch between pads in microns
PITCH_ADD = LW_MIN + LS_MIN;     % add. pitch required to route extra line
VIA_SIZE = VO_MIN + 2 * VLO_MIN; % minimum width of a via
PITCH_EE_TOP_MIN = PITCH_MIN - PAD_SIZE;% edge-edge distance top layer pads
PITCH_EE_VIA_MIN = PITCH_MIN - VIA_SIZE;% edge-edge distance between vias

%% Array initialization
CCPitchArray = linspace(PITCH_MIN, PITCH_MIN + ARRAY_SIZE - 1, ...
    ARRAY_SIZE); % generate center-center pitch array
topEEPitchArray = CCPitchArray - PAD_SIZE;% generate distances between pads
viaEEPitchArray = CCPitchArray - VIA_SIZE;% generate distances between vias
NPadsActual = zeros(1,ARRAY_SIZE);

%% Calculate number of routable rows
topRArrayUR = 1 + (topEEPitchArray - VPS_MIN) / PITCH_ADD;
viaRArrayUR = 1 + (viaEEPitchArray - VPS_MIN) / PITCH_ADD;
topRArray = floor(topRArrayUR); % round down
viaRArray = floor(viaRArrayUR); % round down
totalRArray = topRArray + (LAYERS - 1) * viaRArray;

%% Chip size calculations
dimensionArrayUm = (N_PADS / 4 ./ totalRArray + totalRArray + 1) ...
    .* CCPitchArray;
dimensionArrayCm = dimensionArrayUm / 10000;
sectorLengthArrayUm = dimensionArrayUm - 2 * CCPitchArray;
sectorLengthArrayCm = sectorLengthArrayUm / 10000;
outerPadsArrayUR = dimensionArrayUm ./ CCPitchArray - 1;
outerPadsArray = ceil(outerPadsArrayUR); % ensures we have at least N_PADS

%% Calculate actual number of pads
smallestFullArrayIndex = 0;
for n=1:ARRAY_SIZE
    [NPadsActual(n), ~, rFull] = ...
    generate_visual(outerPadsArray(n),totalRArray(n),false);
    % Check if a full-array configuration was found
    if (rFull && (smallestFullArrayIndex == 0))
        smallestFullArrayIndex = n;
    end
end

%% Verify theoretical calculations
syms c;
ver3 = zeros(1,ARRAY_SIZE);
ver8 = zeros(1,ARRAY_SIZE);
ver9 = zeros(1,ARRAY_SIZE);
%---------------------- verify formula 3.3 ----------------------%
for iArray=1:ARRAY_SIZE
    ver3(iArray) = sectorLengthArrayUm(iArray) / CCPitchArray(iArray);
end

% give result to user
if (round(outerPadsArrayUR, 4) == round(ver3 + 1, 4)) 
    fprintf('Formula 3.3 PASS\n')
else warning('Formula 3.3 not satisfied')
end

%---------------------- verify formula 3.8 ----------------------%
for iArray=1:ARRAY_SIZE
    ver8(iArray) = totalRArray(iArray) * sectorLengthArrayUm(iArray) / ...
        CCPitchArray(iArray) - symsum(2*(c-1), c, 1, totalRArray(iArray));
end
% give result to user
if all(ver8 == ver8(1)) fprintf('Formula 3.8 PASS\n')
else warning('Formula 3.8 not satisfied')
end

%---------------------- verify formula 3.9 ----------------------%
for iArray=1:ARRAY_SIZE
    tmp = totalRArray(iArray) * (sectorLengthArrayUm(iArray) / ...
        CCPitchArray(iArray) - totalRArray(iArray) + 1);
    ver9(iArray) = round(tmp,4); % filter small rounding errors
end
% give result to user
if all(ver9 == ver9(1)) fprintf('Formula 3.9 PASS\n')
else warning('Formula 3.9 not satisfied')
end

%---------------------- verify formula 3.10 ----------------------%
for iArray=1:ARRAY_SIZE
    ver10(iArray) = (totalRArray(iArray) - 1) * ...
        (sectorLengthArrayUm(iArray) / CCPitchArray(iArray) ...
        - totalRArray(iArray));
end
% give result to user
ver10 = round(ver10 + outerPadsArrayUR - 1, 4);
if all(ver10 == ver10(1)) fprintf('Formula 3.10 PASS\n')
else warning('Formula 3.10 not satisfied')
end

%---------------------- verify formula 3.11 ----------------------%
for iArray=1:ARRAY_SIZE
    ver11(iArray) = N_PADS / 4 - ((totalRArray(iArray) - 1) * ...
        (sectorLengthArrayUm(iArray) / CCPitchArray(iArray) ...
        - totalRArray(iArray)));
end
% give result to user
if (round(ver11 + 1, 4) == round(outerPadsArrayUR, 4)) 
    fprintf('Formula 3.11 PASS\n')
else warning('Formula 3.11 not satisfied')
end

%% Output to user

% Plot chip size over pitch
plot(CCPitchArray,dimensionArrayCm);
xlabel('pitch [um]');
ylabel('chip size [cm]');
axis tight;

% Plot smallest design
figure;
[minChipDimension, smallestChipIndex] = min(dimensionArrayCm);
[NPadsActual(smallestChipIndex), visualizerArray] = ...
    generate_visual(outerPadsArray(smallestChipIndex), ...
    totalRArray(smallestChipIndex),false);
visualizerArrayScaled  = plot_visual(visualizerArray, PAD_SIZE, ...
    topEEPitchArray(smallestChipIndex), 1);

% Print values of smallest design
fprintf('\n');
fprintf('<strong>Smallest design will have the following');
fprintf(' specifications:</strong>\n');
fprintf('Chip size:\t\t\t%4.3f cm\n', minChipDimension);
fprintf('Number of pads:\t\t%d \n', NPadsActual(smallestChipIndex));
fprintf('Pad size:\t\t\t%d um\n', PAD_SIZE);
fprintf('c-c pad pitch:\t\t%d um\n', CCPitchArray(smallestChipIndex));
fprintf('Rows:\t\t\t\t%d\n', totalRArray(smallestChipIndex));
fprintf('Outer pads:\t\t\t%d\n', outerPadsArray(smallestChipIndex));
fprintf('Number of layers:\t%d\n', LAYERS);
fprintf('\n');

if (smallestFullArrayIndex ~= 0)
% Plot smallest full-array design
figure;
[NPadsActual(smallestFullArrayIndex), visualizerArray] = ...
    generate_visual(outerPadsArray(smallestFullArrayIndex), ...
    totalRArray(smallestFullArrayIndex),false);
visualizerArrayScaled  = plot_visual(visualizerArray, PAD_SIZE, ...
    topEEPitchArray(smallestFullArrayIndex), 1);

% Print values of full-array design
fprintf('\n');
fprintf('<strong>Smallest full-array design will have the following');
fprintf(' specifications:</strong>\n');
fprintf('Chip size:\t\t\t%4.3f cm\n', ...
    dimensionArrayCm(smallestFullArrayIndex));
fprintf('Number of pads:\t\t%d \n', NPadsActual(smallestFullArrayIndex));
fprintf('Pad size:\t\t\t%d um\n', PAD_SIZE);
fprintf('c-c pad pitch:\t\t%d um\n', CCPitchArray(smallestFullArrayIndex));
fprintf('Rows:\t\t\t\t%d\n', totalRArray(smallestFullArrayIndex));
fprintf('Outer pads:\t\t\t%d\n', outerPadsArray(smallestFullArrayIndex));
fprintf('Number of layers:\t%d\n', LAYERS);
fprintf('\n');

else 
    fprintf('<strong>No full-array design in range</strong>\n');
end

clear n tmp c iArray;   % clean output workspace