function [hcMatrix, upVector, fractionCorrected] = ensureProperDecData(...
    hcMatrixDynamic, upVector, pbeDef)
% check if unified partitions are right and correct of required
%
% Note that the resulting hcMatrix is either formulated in the embedding 
%   proper representation (option useEmbedding
%
% THIS IS NO USER FUNCTION

% The elk-library: convex geometry applied to crystallization modeling.
%   Copyright (C) 2013 Alexander Reinhold
%
% 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/>.

%% shortcuts
nDecCoordinate = pbeDef.nDecCoordinate;
rowFilter = false(1, size(hcMatrixDynamic, 1));
rowFilter(1:pbeDef.nDecCoordinate) = true;
% empty hcMatrix
if isempty(hcMatrixDynamic)
    fractionCorrected = 0;
    return
end
% incomplete decompositions
if ~pbeDef.dec.isComplete
    fractionCorrected = 0;
    return
end

%% some preparation
% tolerances
tolVector = computePositionTolVector(hcMatrixDynamic(1:nDecCoordinate, :), pbeDef.optionStruct);
% the correct filter to allow dynamic update of unified partition
%   information in solver states (this computation here is made freshly for
%   each time step.. ..the unified parition is not a state variable for the
%   ODE solver)
correctFilter = false(size(upVector));
% if the unified partition is still OK, the vector is also still
%   valid/confined.
hcMatrix = hcMatrixDynamic;

%% shortcut for incomplete representations
if ~pbeDef.dec.isComplete
    % in this case, there is only one unified partition
    upVector = ones(1, size(hcMatrix, 2));
    
    % .. but the hcMatrix might be required in the (extended) embedding:
    if pbeDef.optionStruct.useEmbeddingPartitions
        hcMatrix(rowFilter, :) = pbeDef.dec.properEmbedding.mappingNewToProper * ...
            hcMatrix(rowFilter, :);
    end
end

% distinguish cases which use the embedding and which use the original
if (pbeDef.dec.isProper && pbeDef.dec.isComplete) || ...
        ~pbeDef.optionStruct.useEmbeddingPartitions
    
    % normal case of a proper representation
    
    % if the growth rate is not adapted, validity must be ensured
    %   before the unified partition is checked
    if ~pbeDef.optionStruct.limitGrowthRate
        hcMatrix(rowFilter, :) = mapToConfinementCone(...
            hcMatrix(rowFilter, :), pbeDef.dec);
    end
        
        
    for upIndex = 1:pbeDef.dec.nPU
        % we handle only pivots of the current unified partition
        thisFilter = upVector == upIndex;
        % skip if nothing to do
        if ~any(thisFilter), continue;end;
        
        % are they in - we filter here for true, when the upVector needs
        %   correction
        thisFilter(thisFilter) = max(...
            pbeDef.dec.unifiedPartition{upIndex}.A * ...
            hcMatrix(1:pbeDef.nDecCoordinate, thisFilter), ...
            [], 1) > tolVector(thisFilter);
        
        % correct if required
        if any(thisFilter)
            % only if growth rate limiting is active, validity must be
            % corrected here. The other case is handled above.
            if pbeDef.optionStruct.limitGrowthRate
                hcMatrix(rowFilter, thisFilter) = mapToConfinementCone(...
                    hcMatrix(rowFilter, thisFilter), pbeDef.dec);
            end    
            
            upVector(thisFilter) = computePartitionIndexDec(...
                pbeDef.dec, hcMatrix(rowFilter, thisFilter), ...
                tolVector(thisFilter), 1);

            correctFilter = correctFilter | thisFilter;
        end
        
    end
elseif pbeDef.optionStruct.useEmbeddingPartitions
    % create a hcMatrix that is already in embedding but without extra
    %   coordinates
    hcMatrixLocal = pbeDef.dec.properData.mappingNewToProper * ...
        hcMatrix(rowFilter, :);
    % again, it only makes sense to check valid vectors
    hcMatrixLocal = mapToConfinementCone(...
        hcMatrixLocal, pbeDef.dec.properData);
    
    % cycle through partitions in the embedding
    for upIndex = 1:pbeDef.dec.properData.nPU
        % we handle only pivots of the current unified partition
        thisFilter = upVector == upIndex;
        % skip if nothing to do
        if ~any(thisFilter), continue;end;
        
        % are they in - we filter here for true, when the upVector needs
        %   correction
        thisFilter(thisFilter) = max(...
            pbeDef.dec.properData.unifiedPartition{upIndex}.A * ...
            hcMatrixLocal(:, thisFilter), ...
            [], 1) > tolVector(thisFilter);
        
        % correct if required
        if any(thisFilter)
            hcMatrixLocal(:, thisFilter) = mapToConfinementCone(...
                hcMatrixLocal(:, thisFilter), pbeDef.dec.properData);
            
            upVector(thisFilter) = computePartitionIndexDec(...
                pbeDef.dec.properData, hcMatrixLocal(:, thisFilter), ...
                tolVector(thisFilter), 1);
            
            correctFilter = correctFilter | thisFilter;
        end
        
    end 
    
    % but we might need to add the additional coordinates again
    hcMatrix = [hcMatrixLocal; hcMatrix(~rowFilter, :)];
else
    error('elk:pbeSolver:inputError', ['The given representation is neither ' ...
        'proper, nor improper but complete, nor incomplete. This does not ' ...
        'makes sense. Please check your decomposition, dude.']);
end


if any(correctFilter)
    fractionCorrected = sum(correctFilter) / length(correctFilter);
else
    fractionCorrected = 0;
end