substitute_atom.m

Contents

Version

2.11

Contact

Please report problems/bugs to michael.holmboe@umu.se

Examples

  1. atom = substitute_atom(atom,Box_dim,5,'Al','Mgo',5.5) % Basic input arguments
  2. atom = substitute_atom(atom,Box_dim,5,'Al','Mgo',5.5,2,'Si','Al',5.5) % Will perform both octahedral and tetrahedral replacements
  3. atom = substitute_atom(atom,Box_dim,5,'Al','Mgo',5.5,2,'Si','Al',5.5,-2.5,12.5,3) % Only subst. between z>-2.5 and z<12.5 in the z-direction (3).
function atom = substitute_atom(atom,Box_dim,NumOctSubst,O1,O2,minO2O2_dist,varargin)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% If you want to replicate the box, edit this section. UCinX,UCinY,UCinY will not be used when building edges
% clear all;
% UCinX = 6;                      % Number of Unit cells in x direction
% UCinY = 4;                      % Number of Unit cells in y direction
% UCinZ = 1;                      % Number of Unit cells in z direction. This must be 1 (I think)
% % %% Some suggested settings
% NumOctSubst=16;                 % How many octahedral substituitions do you want,
% NumTetSubst=4;                  % How many tetrahedral substituitions do you want
% O1={'Al'}; O2={'Mgo'};  % Mgo   % O1 will get replaced by O2 NumOctSubst times
% T1={'Si'}; T2={'Alt'};  % Alt   % T1 will get replaced by T2 NumTetSubst times
% minO2O2_dist=5.5;               % Minimum O2/O2 substitutions distance in Å, you may decrease it to 4.5 if you add alot of charge
% minT2T2_dist=5.5;               % Minimum T2/T2 substitutions distance in Å, you may decrease it to 4.5 if you add alot of charge

shift_z=0;
if (sum([atom.z])/size(atom,2)) > 1
    shift_z=sum([atom.z])/size(atom,2); % Average z-position
    atom=translate_atom(atom,[0 0 -shift_z]) % Make the atom struct centrosymmetrish around z=0
end

if ~iscell(O1)
    disp('Converting O1 to cell')
    O1={O1};
end
if ~iscell(O2)
    disp('Converting O2 to cell')
    O2={O2};
end

if nargin > 6
    NumTetSubst=cell2mat(varargin(1));
    if iscell(varargin(2))>0
        %         T1=varargin{2}(:)
        %         T2=varargin{3}(:)
        T1=varargin{2}
        T2=varargin{3}
    else
        T1=varargin(2)
        T2=varargin(3)
    end
    minT2T2_dist=cell2mat(varargin(4))

    if ~iscell(T1)
        disp('Converting T1 to cell')
        T1={T1}
    end

    if ~iscell(T2)
        disp('Converting T2 to cell')
        T2={T2}
    end
else
    NumTetSubst=0;
    T1=O1; T2=O2;  % Alt   % T1 will get replaced by T2 NumTetSubst times
    minT2T2_dist=5.5;      % Minimum T2/T2 substitutions distance in Å, you may decrease it to 4.5 if you add alot of charge
end

if nargin > 10
    % Limits for the isosubstitution sites, can be useful to exclude regions for substitutions
    lolimit=varargin{5};% 35; % Arbitrary low number
    hilimit=varargin{6};% 85;  % Arbitrary high number
    dimension=varargin{7};    % meaning == 1=x, 2=y, 3=z
else
    % Limits for the isosubstitution sites, can be useful to exclude regions for substitutions
    lolimit=-1000000000;% 35; % Arbitrary low number
    hilimit=100000000;% 85;  % Arbitrary high number
    dimension=3;    % meaning == 1=x, 2=y, 3=z
end
% Total n of substitutions
NumTotalSubst=NumOctSubst+NumTetSubst;

ind_O1=sort([find(strcmp([atom.type],O1)) find(strcmp([atom.type],O2))]);
XYZ_labels=[atom.type]';
XYZ_data = [[atom.x]' [atom.y]' [atom.z]'];
O2_atom=[]; % New addition...

if NumOctSubst>0

    O1_atom=atom(ind_O1);
    O1_Index=1:size(O1_atom,2);%find(strcmpi(O1,strtrim(XYZ_labels(:,1))));
    O1_labels=[O1_atom.type];%XYZ_labels(O1_Index);
    O1_data=[[O1_atom.x]' [O1_atom.y]' [O1_atom.z]']; %XYZ_data(O1_Index,1:3);
    Ave_Oct_z=mean(O1_data(:,3));
    rand_O1_Index=O1_Index(randperm(length(O1_Index)));
    O1_dist_matrix = dist_matrix_atom(O1_atom,Box_dim);

    i=1; nOctlo=0; nOcthi=0; nOctmid=0; Oct_subst_index=[];%rand_O1_Index(1);
    while (nOctlo+nOcthi+nOctmid)<=NumOctSubst
        ind_O2=find(strcmp([O1_atom.type],O2));
        O=intersect(ind_O2,find(O1_dist_matrix(rand_O1_Index(i),:)<minO2O2_dist));
        if length(O)<1 && nOctlo<NumOctSubst && lolimit<O1_data(rand_O1_Index(i),dimension) && hilimit>O1_data(rand_O1_Index(i),dimension)
            %             O1_data(rand_O1_Index(i),2);
            if nOctlo < NumOctSubst/2 && XYZ_data(ind_O1(rand_O1_Index(i)),3)<Ave_Oct_z %&& ceil(XYZ_data(rand_O1_Index(i),3)*100)/100<=Ave_Oct_z;
                Oct_subst_index=[Oct_subst_index; rand_O1_Index(i)];
                nOctlo=nOctlo+1;
                [O1_atom(rand_O1_Index(i)).type]=O2;
            elseif nOcthi < NumOctSubst/2 && XYZ_data(ind_O1(rand_O1_Index(i)),3)>Ave_Oct_z  %&& ceil(XYZ_data(rand_O1_Index(i),3)*100)/100>=Ave_Oct_z;
                Oct_subst_index=[Oct_subst_index; rand_O1_Index(i)];
                nOcthi=nOcthi+1;
                [O1_atom(rand_O1_Index(i)).type]=O2;
            elseif (nOctlo+nOcthi+nOctmid) < NumOctSubst && XYZ_data(ind_O1(rand_O1_Index(i)),3)==Ave_Oct_z
                Oct_subst_index=[Oct_subst_index; rand_O1_Index(i)];
                nOctmid=nOctmid+1;
                [O1_atom(rand_O1_Index(i)).type]=O2;
            end
        end

        if (nOctlo+nOcthi+nOctmid) == NumOctSubst
            break
        end
        if i == length(O1_data)
            disp('Stopped the loop')
            %             sort(rand_O1_Index(1:i))
            nOctlo
            nOcthi
            nOctmid
            % pause(3)
            break
        end
        i=i+1;
    end
    XYZ_labels(ind_O1(Oct_subst_index))=O2;
    [atom(ind_O1(Oct_subst_index)).type]=deal(O2);
    O2_atom=atom((ind_O1(Oct_subst_index)));
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if NumTetSubst>0

    ind_T1=find(strcmp([atom.type],T1));
    ind_O2=find(strcmp([atom.type],O2));
    T1_atom=atom(ind_T1);
    assignin('caller','ind_T1',ind_T1);
    assignin('caller','T1_atom',T1_atom);
    T1O2_atom=[T1_atom O2_atom];
    T1_Index=1:size(T1_atom,2);%find(strcmpi(O1,strtrim(XYZ_labels(:,1))));
    T1_labels=[T1_atom.type];
    T1_data=[[T1_atom.x]' [T1_atom.y]' [T1_atom.z]']; %XYZ_data(O1_Index,1:3);
    Ave_Tet_z=mean(T1_data(:,3));
    rand_T1_Index=T1_Index(randperm(length(T1_Index)));
    T1_dist_matrix = dist_matrix_atom(T1_atom,Box_dim);
    if  NumOctSubst>0
        T1O2_dist_matrix = dist_matrix_atom(T1_atom,O2_atom,Box_dim);% dist_matrixes_atom(T1_atom,O2_atom,Box_dim);
    else
        T1O2_dist_matrix=[];
        Oct_subst_index=[];
    end
    i=2; nTetlo=0; nTethi=0; All_subst_index=Oct_subst_index; Tet_subst_index=[];%(1)= rand_T1_Index(1);
    while (nTetlo+nTethi)<=NumTetSubst
        ind_T2=find(strcmp([T1_atom.type],T2));
        ind_T2=find(strcmp([T1_atom.type],T2));
        T=intersect(ind_T2,find(T1_dist_matrix(rand_T1_Index(i),:)<minT2T2_dist));
        if numel(T1O2_dist_matrix)>1
            TO=T1O2_dist_matrix(rand_T1_Index(i),:);
            TO=TO(TO<minT2T2_dist);
        else
            TO=[];
        end
        if length(T)<1 && length(TO)<1 &&  nTetlo < NumTetSubst && lolimit < T1_data(rand_T1_Index(i),dimension) && hilimit > T1_data(rand_T1_Index(i),dimension)
            if nTetlo < NumTetSubst/2 && ceil(XYZ_data(ind_T1(rand_T1_Index(i)),3)*100)/100<=Ave_Tet_z
                All_subst_index=[All_subst_index; rand_T1_Index(i)];
                Tet_subst_index=[Tet_subst_index; rand_T1_Index(i)];
                nTetlo=nTetlo+1;
                [T1_atom(rand_T1_Index(i)).type]=T2;
            elseif nTethi < NumTetSubst/2 && ceil(XYZ_data(ind_T1(rand_T1_Index(i)),3)*100)/100>=Ave_Tet_z
                All_subst_index=[All_subst_index; rand_T1_Index(i)];
                Tet_subst_index=[Tet_subst_index; rand_T1_Index(i)];
                nTethi=nTethi+1;
                [T1_atom(rand_T1_Index(i)).type]=T2;
            end
        end
        if (nTetlo+nTethi) == NumTetSubst
            break
        end
        if i == length(T1_data)
            disp('Stopped the loop')
            % pause(3)
            break
        end
        i=i+1;
    end

    XYZ_labels(ind_T1(Tet_subst_index))=T2;
    [atom(ind_T1(Tet_subst_index)).type]=deal(T2);

    if nTetlo==nTethi && (nTetlo+nTethi) == NumTetSubst
        disp('Second substitution success!!!')
    else
        disp('Second substitution not optimal!!!')
        % pause(3)
    end

end

if abs(shift_z)>0
    atom=translate_atom(atom,[0 0 shift_z]) % Shift the atom structs z-coordinates back to the original
end

if NumOctSubst>0
    atom_O2=atom(find(strcmpi([atom.type],O2)));
    O2_distmatrix=dist_matrix_atom(atom_O2,Box_dim);
    disp('Minimum O2O2_dist is in Å')
    min(O2_distmatrix(2:end,1))
end

if NumTetSubst>0
    atom_T2=atom(sort([find(strcmpi([atom.type],T2)) find(strcmpi([atom.type],O2))]));
    T2_distmatrix=dist_matrix_atom(atom_T2,Box_dim);
    disp('Minimum minT2T2_dist is in Å')
    min(T2_distmatrix(2:end,1))

    if NumOctSubst>0
        T2O2_distmatrix=dist_matrix_atom(atom_T2,atom_O2,Box_dim);
        disp('Minimum minT2O2_dist is in Å')
        min(T2O2_distmatrix(2:end,1))
    end

end

if NumOctSubst>0
    if (nOctlo==nOcthi && (nOctlo+nOcthi) == NumOctSubst) || nOctmid == NumOctSubst
        disp('First substitution success!!!')
    else
        disp('First substitution not optimal!!!')
        try
            nOctlo
            nOcthi
            nOctmid
            assignin('caller','nOctlo',nOctlo)
            assignin('caller','nOcthi',nOcthi)
            assignin('caller','nOctmid',nOctmid)
        catch
            disp('No first subst...')
        end

    end
end

if NumTetSubst>0
    if (nTetlo==nTethi && (nTetlo+nTethi) == NumTetSubst)
        disp('Second substitution success!!!')
    else
        disp('Second substitution not optimal!!!')
        try
            nTetlo
            nTethi
            assignin('caller','nTetlo',nTetlo)
            assignin('caller','nTethi',nTethi)
        catch
            disp('No second subst...')
        end

    end
end

composition_atom(atom);