function dec = appendPartitionDataForEmbedding(dec, partitionData, zerotol)
% append embedding (unified) partition data
%
% this function is supposed to be used whenever an appendUnifiedPartition
%   was called as it adds information to the last unified partition(!)
%
% The following fields are added:
%   .this: data that is true for vectors in the interior of the domain
%   .projection: several projection matrices that apply
%   .embeddingDomain: representation of partition in proper embedding
%   .boundary: information on the boundaries of the partition and the
%       neighbours of that partition
%
% 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/>.

%% unified partition index
this.embeddingUnifiedIndex = partitionData.unifiedIndex;

%% validity projection (by partition)
% projection information for all facets that HAVE disappeared for
%   hC-vectors in the interior of that partition. 
projection.invalidConstraintIndexVector = ...
    partitionData.debug.projectionData.violatedConstraintIndexVector;
projection.invalidGroupIndexVector = ...
    partitionData.debug.projectionData.invalidFacetGroupVector;
projection.projectionIndexVector = ...
    partitionData.debug.projectionData.projectionIndexVector;

% the required validity projection (this does not yet map to the
%    corresponding subspace in the proper embedding)
projection.validity = partitionData.validityProjectionMatrix;

% direct maping FROM embedding proper representation (assuming
%   the hE-vector is on the proper domain in hE-space, if not we take
%   the closest hE vector with that property)
projection.fromProper = pinv(projection.validity*...
    dec.properData.mappingNewToProper);

% the projection that uses validity projection (if possible) to
%    reach the corresponding subspace in the proper embedding
projection.validityOntoSubspace = ...
    projection.validity*dec.properData.mappingNewToProper*...
    projection.fromProper;

% orthogonal projection onto the corresponding subspace (in
%   embedding space)
thisOrth = orth(projection.validity*...
    dec.properData.projectionMatrix);
projection.orthogonalOntoSubspace = thisOrth*thisOrth';
thisNull = null(projection.orthogonalOntoSubspace);

%% representation in proper embedding
% the concise representation of the domain in embedding space covered
%   by the unified partition was already constructed and saved in the
%   partition generation
embeddingDomain.hrep.A = partitionData.debug.embeddingConstraintMatrix;
%! DEV: therefore, the old code is deprecated:
% thisEmbedding.hrep.A = dec.unifiedPartition{end}.A * pinv(...
%     thisEmbedding.validityProjection*...
%     dec.properData.mappingNewToProper);
%/
embeddingDomain.hrep.h = zeros(size(embeddingDomain.hrep.A, 1), 1);
% also save a reduced form
embeddingDomain.hrepReduced = reduceHrep(embeddingDomain.hrep);
% the strict representation of the domain above:
embeddingDomain.hrepStrict.A = [embeddingDomain.hrep.A; ...
    thisNull'; -1*thisNull'];
embeddingDomain.hrepStrict.h = [embeddingDomain.hrep.h; ...
    zeros(2*size(thisNull, 2), 1)];

%% validity projection filter (for confinement mapping)
% For the confinement mapping of growth vectors, the current partition of
%   the hC-vector is pivotal. If a given boundary from
%   properData.confinementMapping must be considered and, hence, the 
%   corresponding facet validity applies depends on the confinement 
%   condition. To ensure the right decision, the representation of the
%   boundaries in the improper space must be considered.
constraintMatrix = dec.properData.confinementMappingData.A * ...
    dec.properData.mappingNewToProper;
responsibleGroupVector = ...
    dec.properData.confinementMappingData.responsibleVector;
projection.applyConstraintFilter = false(1, size(constraintMatrix, 1));
directionMatrix = dec.properData.confinementMappingData.directionMatrix;
for iCon = 1:size(constraintMatrix, 1)
    % Ignore the constraint when it indicates a zero-mapping (dissolution,
    %   disappearing shape)
    if responsibleGroupVector(iCon) == dec.properData.nC+1
        continue;
    end
    
    % Ignore constraints for which the facet groups have already
    %   disappeared by the current partition. The projection might switch
    %   in this case, but if it was confined beforehand, it will be
    %   confined thereafter.
    if any(projection.invalidGroupIndexVector == ...
           responsibleGroupVector(iCon));
       continue;
    end
    
    % We also ignore a constraint that has now a zero-vector as normal
    %   vector. These constraints will always be fulfilled.
    if all(constraintMatrix(iCon, :) < zerotol)
        continue;
    end
    
    % Now we have to check confinement. A unique list of facet groups that
    %   already have disappeared are:
    thisDisappearedGroupVector = projection.invalidGroupIndexVector;
    % These indices cannot contain (nC+1) since all partitions are inside
    %   the empty-polytope-cone. They also cannot contain the current
    %   direction (see above).
    % Usually only one group disappears but when two constraints are
    %   equivalent in hC-space, then the corresponding facet groups also
    %   disappear at the same time. Both of these constraints must then be
    %   considered even though none would indicate unconfinement
    %   separately.
    thisConstraintFilter = all(abs(bsxfun(@minus, ...
        constraintMatrix, constraintMatrix(iCon, :))) < zerotol, 2);
    thisGroupVector = unique([thisDisappearedGroupVector ...
        responsibleGroupVector(thisConstraintFilter)]);
    if rank([directionMatrix(:, thisGroupVector) ...
             dec.properData.mappingNewToProper]) == ...
             length(thisGroupVector) + dec.nC
        continue;
    else
        projection.applyConstraintFilter(iCon) = true;
    end
end


% save results
dec.unifiedPartition{end}.projection = projection;
dec.unifiedPartition{end}.embeddingDomain = embeddingDomain;
% dec.unifiedPartition{end}.boundary = boundary;
dec.unifiedPartition{end}.this = this;
   