addValidityMappingData

PURPOSE ^

add data to identify vanished facets and map to validity cone

SYNOPSIS ^

function dec = addValidityMappingData(dec, zerotol)

DESCRIPTION ^

 add data to identify vanished facets and map to validity cone

 THIS FUNCTION IS NO USER FUNCTION.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function dec = addValidityMappingData(dec, zerotol)
0002 % add data to identify vanished facets and map to validity cone
0003 %
0004 % THIS FUNCTION IS NO USER FUNCTION.
0005 
0006 % The elk-library: convex geometry applied to crystallization modeling.
0007 %   Copyright (C) 2012 Alexander Reinhold
0008 %
0009 % This program is free software: you can redistribute it and/or modify it
0010 %   under the terms of the GNU General Public License as published by the
0011 %   Free Software Foundation, either version 3 of the License, or (at your
0012 %   option) any later version.
0013 %
0014 % This program is distributed in the hope that it will be useful, but
0015 %   WITHOUT ANY WARRANTY; without even the implied warranty of
0016 %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0017 %   General Public License for more details.
0018 %
0019 % You should have received a copy of the GNU General Public License along
0020 %   with this program.  If not, see <http://www.gnu.org/licenses/>.
0021 
0022 %% data structure
0023 % Draft of the gathered information in boundaryData:
0024 %     .A       - boundary facet normals in nC-dimensional space
0025 %     .nBoundary - total number of rows in A
0026 %     .responsibleVector - a vector that indicates the facet (group) that
0027 %                disappears given corresponding to the constraint in A.
0028 %     .directionMatrix - the collection of directions (column vectors) in
0029 %                hC-space which is used to correct a specific boundary
0030 %                (column). It contains nan, when mapping is not possible
0031 %                without changing a valid facet and inf when mapping
0032 %                to the origin would be appropriate. In the latter case,
0033 %                the boundary indicates the disappearance of all facets at
0034 %                once.
0035 
0036 %% prepare setup
0037 % copy constraints
0038 dec.confinementMappingData.A = dec.facetValidityData.A;
0039 % predefine assigned directions (per constraint)
0040 dec.confinementMappingData.responsibleVector = ...
0041     nan(1, size(dec.confinementMappingData.A, 1));
0042 % predefine possible projection sets (per facet)
0043 dec.confinementMappingData.projectionData = struct([]);
0044 % predefine the directions
0045 dec.confinementMappingData.directionMatrix = nan([dec.nC dec.nC+1]);
0046 % local copy
0047 responsibleMatrix = dec.facetValidityData.responsibleMatrix;
0048 
0049 %% generate zero-projection data
0050 dec.confinementMappingData.responsibleVector(...
0051     responsibleMatrix(responsibleMatrix(:, 2) == (dec.nH + 1), 1)) = dec.nC+1;
0052 dec.confinementMappingData.projectionData(dec.nC+1).A = zeros(0, dec.nC);
0053 dec.confinementMappingData.projectionData(dec.nC+1).responsibleMatrix = ...
0054     zeros(0, 3);
0055 dec.confinementMappingData.projectionData(dec.nC+1).projectionList = ...
0056     {zeros(dec.nC)};
0057 % delete all entries for these constraints, they appear for all facets
0058 for iConstraint = find(dec.confinementMappingData.responsibleVector == (dec.nC+1))
0059     responsibleMatrix(responsibleMatrix(:, 1) == iConstraint, :) = [];
0060 end
0061 
0062 %% generate facet group projections
0063 % construct unique non-zero rows
0064 [directionMatrix facetIndexVector, directionIndexVector] = ...
0065     unique(dec.mappingReducedToFull, 'rows');
0066 % Zero rows in the direction matrix occure when the position was fixed
0067 %   by the decomposition algorithm. These direction must be considered
0068 %   with some precaution. They must be treated separately. Therefore, we
0069 %   identify the original zero rows and multiply them appropriately.
0070 zeroRowFilter = all(dec.mappingReducedToFull < zerotol, 2);
0071 zeroRowIndexFilter = find(zeroRowFilter);
0072 % if there is only one zero row then the above is already correct. If there
0073 %   are more zero rows, we must append some zero-row directions.
0074 if sum(zeroRowFilter) > 1
0075     % find the current zero-row index
0076     thisZeroIndex = find(all(directionMatrix < zerotol, 2));
0077     % add zero rows
0078     directionMatrix = [directionMatrix zeros(sum(zeroRowFilter)-1, dec.nC)];
0079     % substitute direction indices
0080     zeroDirIndexVector = find(directionIndexVector == thisZeroIndex);
0081     directionIndexVector(zeroDirIndexVector) = zeroRowIndexFilter;
0082 end
0083 
0084 nDir = size(directionMatrix, 1);
0085 
0086 for iDir = 1:nDir
0087 
0088     % ---
0089     % identify facet(s) for direction
0090     thisFacetIndex = find(directionIndexVector == iDir, 1, 'first');
0091     isZeroDir = any(zeroRowIndexFilter == thisFacetIndex);
0092     
0093     % ---
0094     % identify mapping direction (null space)
0095     thisDirectionFilter = true(1, nDir);
0096     thisDirectionFilter(iDir) = false;
0097     % Things are different when iDir indicates a zero row, therefore the
0098     % separate treatment:
0099     if ~isZeroDir
0100         % The projection direction equals the null space of the oblique
0101         %   projection that is to be constructed. While this direction is
0102         %   not important for the handling of the proper representation, it
0103         %   becomes valuable as soon as an improper representation is
0104         %   constructed.
0105         dec.confinementMappingData.directionMatrix(:, iDir) = null(...
0106             directionMatrix(thisDirectionFilter, :));
0107         
0108         % For the construction of the obligue projection, we require the
0109         %   orthogonal complement of the null space (see wikipedia).
0110         %! DEV: this line was used beforehand.. ..and can't be right in
0111         %       general. It is only a proper result if the selected
0112         %       direction is already orthogonal to all other directions.
0113 %         thisOrthNull = orth(directionMatrix(thisDirectionFilter, :)');
0114         % we use this new line:
0115         thisOrthNull = null(dec.confinementMappingData.directionMatrix(:, iDir)');
0116     else
0117         % Things are different for a zero row that was introduced to fix the
0118         %   position. The disappearance of this facet also implies that the
0119         %   position is not fixed anymore. The nullspace is, hence, computed
0120         %   from this degree of freedom. Assuming this facet has
0121         %   disappeared, we temporarly ignore the facet
0122         tmpA = dec.A; tmpA(thisFacetIndex, :) = [];
0123         tmpMc = dec.constraintMatrix; tmpMc(:, thisFacetIndex) = [];
0124         tmpMapToH = dec.mappingReducedToFull; tmpMapToH(thisFacetIndex, :) = [];
0125         tmpMapFromH = pinv(tmpMapToH);
0126         % obtain free direction via singular value decomposition
0127         [U S V] = svd(tmpMc * tmpA);
0128         % The direction in which we can move freely is:
0129         %     x0 = V(:, end)
0130         %   which is applied according to:
0131         %     h' = h + A*x0.
0132         %   Scince h fulfills tmpMc*h=0 and h' is computed so that it
0133         %   fulfills tmpMc*h', its difference also fulfills this
0134         %   constraint so that hC is:
0135         thisDirHc = tmpMapFromH*tmpA*V(:, end);
0136         % This is the null space and we need the orthogonal complement.
0137         thisOrthNull = null(thisDirHc');
0138     end
0139     
0140     % ---
0141     % determine range and construct projection(s)
0142     
0143     % identify assigned constraints (range)
0144     dec.confinementMappingData.responsibleVector(responsibleMatrix(...
0145           responsibleMatrix(:, 2) == thisFacetIndex, 1)) = iDir;
0146     thisConstraintFilter = dec.confinementMappingData.responsibleVector == iDir;
0147     
0148     % fill projection data (one for each constraint)
0149     thisProjectionData = appendProjectionData([], dec.nC);
0150     for iConstraint = find(thisConstraintFilter)
0151         % the facet is spanned by the following base vectors that are
0152         %   constructed from the orthogonal null space, spanned by the
0153         %   facet normal. Hence, we take the null space of the null space
0154         %   for the range of the projection onto the facet.
0155         thisRange = null(dec.confinementMappingData.A(iConstraint, :));
0156         
0157         % the obligue projection is now:
0158         thisProjection = thisRange * inv(...
0159             thisOrthNull' * thisRange) * thisOrthNull';
0160         % it must map to the group validity cone:
0161         %   Av * P * hC <= 0
0162         thisConstraint = ...
0163             dec.confinementMappingData.A(thisConstraintFilter, :) * ...
0164             thisProjection;
0165         % .. and - the projection must actually be valid. This is redundant
0166         %   to the constraints that are checked in confinementMappingData.A
0167         %   but this check is required for completeness when dealing with
0168         %   projections of proper decompositions. There, the whole validity
0169         %   of this projection is required.
0170         thisConstraint = [thisConstraint; ...
0171                           -1*dec.confinementMappingData.A(iConstraint, :)];
0172         % assign results
0173         thisProjectionData = appendProjectionData(thisProjectionData, ...
0174             thisConstraint, thisProjection, zerotol);
0175     end
0176     dec.confinementMappingData.projectionData(iDir) = thisProjectionData;  
0177 end
0178 
0179 % add something that is used only for improper representations
0180 dec.confinementMappingData.ignoreFadeOut = [];

Generated on Sat 18-Jul-2015 16:45:31 by m2html © 2005