bond_angle_atom.m

Contents

Version

2.11

Contact

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

Examples

  1. atom=bond_angle_atom(atom,Box_dim) % Basic input arguments
  2. atom=bond_angle_atom(atom) % When PBC is not important
  3. atom=bond_angle_atom(atom,Box_dim,1.25,2.25) % Allows setting the rmaxshort and rmaxlong
  4. atom=bond_angle_atom(atom,Box_dim,1.25,2.25,'more') % Will write more info to the calling workspace
function atom=bond_angle_atom(atom,varargin)

tic

if nargin<=4
    if nargin<4
        if nargin==1
            Box_dim=1e6*[1 1 1]; % Dummy Box_dim, when the PBC is not important
        else
            Box_dim=varargin{1};
        end
        rmaxshort=1.25;
        rmaxlong=2.25;
    else
        Box_dim=varargin{1};
        rmaxshort=varargin{2};
        rmaxlong=varargin{3};
    end
elseif nargin>4
    Box_dim=varargin{1};
    rmaxshort=varargin{2};
    rmaxlong=varargin{3};
end

nAtoms=size(atom,2);
% max_short_dist=1.2;
% max_long_dist=2.3;

XYZ_labels=[atom.type]';
XYZ_data=single([[atom.x]' [atom.y]' [atom.z]']); % use of single instead of double

lx=Box_dim(1);ly=Box_dim(2);lz=Box_dim(3);
if length(Box_dim) > 3
    xy=Box_dim(6);xz=Box_dim(8);yz=Box_dim(9);
else
    xy=0;xz=0;yz=0;
end

close_count=1;
Bond_index=single(zeros(4*size(XYZ_data,1),3)); % use of single instead of double
Angle_index=single(zeros(4*size(XYZ_data,1),4)); % use of single instead of double
dist_matrix=single(zeros(nAtoms,nAtoms)); % use of single instead of double
% dist_matrix = dist_matrix_atom(atom,Box_dim); % Do this if you want to calc dist_matrix_atom first
b=1;a=1; overlap_index=[];
for i = 1:size(XYZ_data,1)

    %     disp('Setting max_neigh_distance to... ')
    %     max_neigh_distance = max_long_dist %2.25; % Set large max_neigh_distance so that we can find Si-O-H and Al-OH2 bonds %max_long_dist;%2.3
    %     disp('If you have problems, change back to 2.25 on line 43 in bond_angle_atom()')
    %     max_neigh_distance = max_long_dist; % Change to 2.25 if adding edge bonds

    if strcmpi(strtrim(XYZ_labels(i)),'Oalhh') || strcmp(strtrim(XYZ_labels(i)),'Osih')
        if rmaxlong < 2.25
            max_neigh_distance = 2.25;
        else
            max_neigh_distance = rmaxlong;
        end
    else
        max_neigh_distance = rmaxlong;
    end
    %                 disp('Looking for M-O-H bonds')

    if length(Box_dim)>3
        %Calculate Distance Components for triclic cell
        rz = XYZ_data(i,3) - XYZ_data(:,3);
        ry = XYZ_data(i,2) - XYZ_data(:,2);
        rx = XYZ_data(i,1) - XYZ_data(:,1);

        z_gt_ind=find(rz > lz/2); z_lt_ind=find(rz < - lz/2);
        rz(z_gt_ind) = rz(z_gt_ind) - lz;
        rz(z_lt_ind) = rz(z_lt_ind) + lz;
        rx(z_gt_ind) = rx(z_gt_ind) - xz;
        rx(z_lt_ind) = rx(z_lt_ind) + xz;
        ry(z_gt_ind) = ry(z_gt_ind) - yz;
        ry(z_lt_ind) = ry(z_lt_ind) + yz;

        y_gt_ind=find(ry > ly/2); y_lt_ind=find(ry < - ly/2);
        ry(y_gt_ind) = ry(y_gt_ind) - ly;
        ry(y_lt_ind) = ry(y_lt_ind) + ly;
        rx(y_gt_ind) = rx(y_gt_ind) - xy;
        rx(y_lt_ind) = rx(y_lt_ind) + xy;

        x_gt_ind=find(rx > lx/2); x_lt_ind=find(rx < - lx/2);
        rx(x_gt_ind) = rx(x_gt_ind) - lx;
        rx(x_lt_ind) = rx(x_lt_ind) + lx;
    else
        %Calculate Distance Components for ortogonal cell

        rz = XYZ_data(i,3) - XYZ_data(:,3);
        z_gt_ind=find(rz > lz/2); z_lt_ind=find(rz < - lz/2);
        rz(z_gt_ind) = rz(z_gt_ind) - lz;
        rz(z_lt_ind) = rz(z_lt_ind) + lz;

        ry = XYZ_data(i,2) - XYZ_data(:,2);
        y_gt_ind=find(ry > ly/2); y_lt_ind=find(ry < - ly/2);
        ry(y_gt_ind) = ry(y_gt_ind) - ly;
        ry(y_lt_ind) = ry(y_lt_ind) + ly;

        rx = XYZ_data(i,1) - XYZ_data(:,1);
        x_gt_ind=find(rx > lx/2); x_lt_ind=find(rx < - lx/2);
        rx(x_gt_ind) = rx(x_gt_ind) - lx;
        rx(x_lt_ind) = rx(x_lt_ind) + lx;

    end

    r = sqrt( rx(:,1).^2 + ry(:,1).^2 + rz(:,1).^2 ); % distance calc.
    bond_in=intersect(find(r > 0), find(r < max_neigh_distance));
    dist_matrix(:,i)=r;


    % Else if we already called dist_matrix_atom...
    %     r = dist_matrix(:,i);
    %     rx= X_dist(:,i);
    %     ry= Y_dist(:,i);
    %     rz= Z_dist(:,i);
    %     bond_in=intersect(find(r > 0), find(r < max_neigh_distance));
    %


    n=1;
    Neigh_ind=zeros(12,1);Neigh_vec=zeros(12,3);
    for j=1:length(bond_in)
        if [atom(i).molid]==[atom(bond_in(j)).molid] && (strncmpi([atom(i).type],[atom(bond_in(j)).type],1) == 0)
            % Original, uncomment this section
            % max_distance = max_short_dist;
            % Only test
            if strncmpi(strtrim(XYZ_labels(i)),'H',1) || strncmpi(strtrim(XYZ_labels(bond_in(j))),'H',1)
                max_distance = rmaxshort;
            elseif strcmpi(strtrim(XYZ_labels(i)),'Oalhh') || strcmp(strtrim(XYZ_labels(i)),'Osih')
                if rmaxlong < 2.25
                    max_distance = 2.25;
                else
                    max_distance = rmaxlong;
                end
                %                 disp('Looking for M-O-H bonds')
            else
                max_distance = rmaxlong;
            end

            if r(bond_in(j)) < 0.6
                disp('Atoms too close!!!')
                r(bond_in(j))
                [i,bond_in(j)]
                XYZ_labels(i)
                XYZ_labels(bond_in(j))
                XYZ_data(i,:)
                XYZ_data(bond_in(j),:)
                overlap_index=[overlap_index; {i bond_in(j) r(bond_in(j)) XYZ_labels(i) XYZ_labels(bond_in(j)) XYZ_data(i,:) XYZ_data(bond_in(j),:)}];
            elseif r(bond_in(j)) > max_distance && r(bond_in(j)) < 1.25
                disp('Atoms pretty close...')
                r(bond_in(j))
                [i,bond_in(j)]
                XYZ_labels(i)
                XYZ_labels(bond_in(j))
                XYZ_data(i,:)
                XYZ_data(bond_in(j),:)
                close_count=close_count+1;
                overlap_index=[overlap_index; {i bond_in(j) r(bond_in(j)) XYZ_labels(i) XYZ_labels(bond_in(j)) XYZ_data(i,:) XYZ_data(bond_in(j),:)}];
            end
            if r(bond_in(j)) > max_distance/3 && r(bond_in(j)) < max_distance %strncmpi(XYZ_labels(i),strtrim(XYZ_labels(j)),1) == 0;
                if strncmpi(strtrim(XYZ_labels(i)),{'OW'},2)% || strncmpi(strtrim(XYZ_labels(bond_in(j))),{'OW'},2); % < bond_in(j) && ismember(XYZ_labels(i),{'Ow','Hw','OW','HW','HW1','HW2'}) > 0;
                    if bond_in(j) > i && bond_in(j) < i+3 %strncmpi(strtrim(XYZ_labels(i)),{'Ow'},2) && bond_in(j) > i && bond_in(j) < i+3;
                        Bond_index(b,1)= min([i bond_in(j)]);
                        Bond_index(b,2)= max([i bond_in(j)]);
                        Bond_index(b,3)= r(bond_in(j));
                        b=b+1;
                        if r(bond_in(j)) < rmaxshort % This should always be true right?
                            Neigh_ind(n,1)= bond_in(j);
                            Neigh_vec(n,1:3) = [rx(bond_in(j)) ry(bond_in(j)) rz(bond_in(j))];
                            n=n+1;
                        end
                    end
                elseif strncmpi(strtrim(XYZ_labels(i)),{'HW'},2)
                    % disp('HW')
                elseif strncmpi(strtrim(XYZ_labels(i)),{'H'},1) && strncmpi(strtrim(XYZ_labels(bond_in(j))),{'H'},1)
                    %                     disp('disallowed a H-H bond')
                elseif ismember({'H'},[XYZ_labels(i) XYZ_labels(bond_in(j))]) > 0 || ismember({'Oalhh'},[XYZ_labels(i) XYZ_labels(bond_in(j))]) > 0 || ismember({'Osih'},[XYZ_labels(i) XYZ_labels(j)]) > 0 && ismember(XYZ_labels(bond_in(j)),{'Ow','Hw','OW','HW','HW1','HW2'}) == 0
                    Bond_index(b,1)= min([i bond_in(j)]);
                    Bond_index(b,2)= max([i bond_in(j)]);
                    Bond_index(b,3)= r(bond_in(j));
                    b=b+1;
                    if r(bond_in(j)) < max_distance % This should always be true right?
                        Neigh_ind(n,1)= bond_in(j);
                        Neigh_vec(n,1:3) = [rx(bond_in(j)) ry(bond_in(j)) rz(bond_in(j))];
                        n=n+1;
                    end
                elseif ~strncmpi(strtrim(XYZ_labels(i)),{'OW'},2) || ~strncmpi(strtrim(XYZ_labels(i)),{'HW'},2)
                    if bond_in(j) < i
                        Bond_index(b,1)= min([i bond_in(j)]);
                        Bond_index(b,2)= max([i bond_in(j)]);
                        Bond_index(b,3)= r(bond_in(j));
                        b=b+1;
                    end
                    if r(bond_in(j)) < max_distance % This should always be true right?
                        Neigh_ind(n,1)= bond_in(j);
                        Neigh_vec(n,1:3) = [rx(bond_in(j)) ry(bond_in(j)) rz(bond_in(j))];
                        n=n+1;
                    end
                end
            end

        end % test

        Neigh_ind(~any(Neigh_ind,2),:) = [];
        Neigh_vec(~any(Neigh_vec,2),:) = [];

        for v=1:size(Neigh_ind,1)
            for w=1:size(Neigh_ind,1) % From v or from 1?
                angle=rad2deg(atan2(norm(cross(Neigh_vec(v,:),Neigh_vec(w,:))),dot(Neigh_vec(v,:),Neigh_vec(w,:))));
                if angle > 0 && angle <= 150 % Do we need this??
                    if v < w
                        Angle_index(a,1)= Neigh_ind(v,1);
                        Angle_index(a,2)= i;
                        Angle_index(a,3)= Neigh_ind(w,1);
                        Angle_index(a,4)= angle;
                        Angle_index(a,5:7)= Neigh_vec(v,:);
                        Angle_index(a,8:10)= Neigh_vec(w,:);
                        a=a+1;
                    else
                        Angle_index(a,1)= Neigh_ind(w,1);
                        Angle_index(a,2)= i;
                        Angle_index(a,3)= Neigh_ind(v,1);
                        Angle_index(a,4)= angle;
                        Angle_index(a,5:7)= Neigh_vec(w,:);
                        Angle_index(a,8:10)= Neigh_vec(v,:);
                        a=a+1;
                    end
                end
            end
        end
    end
    if mod(i,1000)==1
        if i-1>0
            i-1
        end
    end
end


[Y,I]=sort(Bond_index(:,1));
Bond_index=Bond_index(I,:);
Bond_index = unique(Bond_index,'rows','stable');

[Y,I]=sort(Angle_index(:,1));
Angle_index=Angle_index(I,:);
Angle_index = unique(Angle_index,'rows','stable');

[Y,I]=sort(Angle_index(:,2));
Angle_index=Angle_index(I,:);
Angle_index = unique(Angle_index,'rows','stable');

overlap_index=overlap_index(1:size(overlap_index,1)/2,:);
% [Y,I]=sort(cell2mat(overlap_index(:,2)));
% overlap_index=overlap_index(I,:);
% overlap_index = unique(overlap_index,'rows','stable');

Bond_index(~any(Bond_index,2),:) = [];
Angle_index(~any(Angle_index,2),:) = [];
% overlap_index(~any(overlap_index,2),:) = [];

nBonds=size(Bond_index,1);
nAngles=size(Angle_index,1);

if nargin > 4 %% This will print a whole lot more info to the calling workspace
    % Set a cutoff vector
    rmax=repmat(max_neigh_distance,nAtoms,1);
    % Reduce the cutoff vector for H - X
    rmax(strncmpi(strtrim(XYZ_labels),'H',1))=1.25;
    for i=1:size(atom,2)
        Neigh_ind=intersect(find(dist_matrix(:,i)>0),find(dist_matrix(:,i)<rmax(i)));%radius_ion([atom.type])));
        Neigh_dist=dist_matrix(Neigh_ind,i);
        atom(i).neigh.type = [atom(Neigh_ind).type]';
        atom(i).neigh.index = Neigh_ind;
        atom(i).neigh.dist = Neigh_dist;
        atom(i).neigh.coords = [[atom(Neigh_ind).x]' [atom(Neigh_ind).y]' [atom(Neigh_ind).z]']; % PBC NOT TAKEN INTO ACCOUNT!!!
        atom(i).bond.type = [];
        atom(i).bond.index = [];
        atom(i).bond.dist = [];
        atom(i).angle.type = [];
        atom(i).angle.index = [];
        atom(i).angle.angle = [];
        atom(i).angle.vec1 = [];
        atom(i).angle.vec2 = [];

        if ismember(i,Bond_index(:,1:2))
            [A,B]=find(Bond_index(:,1:2)==i);
            atom(i).bond.type = 1;
            atom(i).bond.index = Bond_index(A,1:2);
            atom(i).bond.dist = Bond_index(A,3);
            if ismember(i,Angle_index(:,1:3))
                %                 [C,D]=find(Angle_index(:,1:3)==i);
                [C,D]=find(Angle_index(:,2)==i);
                atom(i).angle.type = 1;
                atom(i).angle.index = Angle_index(C,1:3);
                atom(i).angle.angle = Angle_index(C,4);
                atom(i).angle.vec1 = Angle_index(C,5:7);
                atom(i).angle.vec2 = Angle_index(C,8:10);
            end
        end
        if mod(i,1000)==1
            if i-1>0
                i-1
            end
        end
    end

    %%%%%%%%%%

    Atom_labels=unique([atom.type]);
    for i=1:length(Atom_labels)
        label_ind=find(strcmpi([atom.type],Atom_labels(i)));
        Tot_dist=[];Tot_CN=[];Tot_type=[];Tot_index=[];Tot_angleindex=[];Tot_bondindex=[];Tot_neighindex=[];Tot_coords=[];Tot_bonds=[];Tot_angles=[];
        for j=label_ind
            if numel([atom(j).neigh])>0
                Tot_index=[Tot_index; repmat(j,numel([atom(j).neigh.index]),1)];
                Tot_dist=[Tot_dist; [atom(j).neigh.dist]];
                CN_temp=numel([atom(j).neigh.dist]);
                Tot_CN=[Tot_CN;CN_temp*ones(CN_temp,1)];
                Tot_type=[Tot_type; [atom(j).neigh.type]];
                Tot_neighindex=[Tot_neighindex; [atom(j).neigh.index]];
                Tot_coords=[Tot_coords; [atom(j).neigh.coords]];
            end

            if numel([atom(j).bond])>0
                Tot_bondindex=[Tot_bondindex; [atom(j).bond.index]];
                Tot_bonds=[Tot_bonds; [atom(j).bond.dist]];
            end
            if numel([atom(j).angle])>0
                Tot_angleindex=[Tot_angleindex; [atom(j).angle.index]];
                Tot_angles=[Tot_angles; [atom(j).angle.angle]];
            end
        end
        try
            assignin('caller',strcat(char(Atom_labels(i)),'_dist')',[num2cell(Tot_index) num2cell(Tot_neighindex) Tot_type num2cell(Tot_dist) num2cell(Tot_CN)]);
            assignin('caller',strcat(char(Atom_labels(i)),'_coords')',[[atom(Tot_neighindex).x]' [atom(Tot_neighindex).y]' [atom(Tot_neighindex).z]']);
            assignin('caller',strcat(char(Atom_labels(i)),'_bonds')',[Tot_bondindex Tot_bonds]);
            assignin('caller',strcat(char(Atom_labels(i)),'_angles')',[Tot_angleindex Tot_angles]);
            assignin('caller',strcat(char(Atom_labels(i)),'_atom')',atom(ismember([atom.type],Atom_labels(i))));

            assignin('base',strcat(char(Atom_labels(i)),'_dist')',[num2cell(Tot_index) num2cell(Tot_neighindex) Tot_type num2cell(Tot_dist) num2cell(Tot_CN)]);
            assignin('base',strcat(char(Atom_labels(i)),'_coords')',[[atom(Tot_neighindex).x]' [atom(Tot_neighindex).y]' [atom(Tot_neighindex).z]']);
            assignin('base',strcat(char(Atom_labels(i)),'_bonds')',[Tot_bondindex Tot_bonds]);
            assignin('base',strcat(char(Atom_labels(i)),'_angles')',[Tot_angleindex Tot_angles]);
            assignin('base',strcat(char(Atom_labels(i)),'_atom')',atom(ismember([atom.type],Atom_labels(i))));
        catch
            assignin('base',strcat(char(Atom_labels(i)),'_dist')',[num2cell(Tot_index) num2cell(Tot_neighindex) Tot_type num2cell(Tot_dist) num2cell(Tot_CN)]);
            assignin('base',strcat(char(Atom_labels(i)),'_coords')',[[atom(Tot_neighindex).x]' [atom(Tot_neighindex).y]' [atom(Tot_neighindex).z]']);
            assignin('base',strcat(char(Atom_labels(i)),'_bonds')',[Tot_bondindex Tot_bonds]);
            assignin('base',strcat(char(Atom_labels(i)),'_angles')',[Tot_angleindex Tot_angles]);
            assignin('base',strcat(char(Atom_labels(i)),'_atom')',atom(ismember([atom.type],Atom_labels(i))));
        end
    end
end

atom=order_attributes(atom);

try
    assignin('caller','dist_matrix',dist_matrix);
    assignin('caller','overlap_index',overlap_index);
    assignin('caller','Bond_index',Bond_index);
    assignin('caller','Angle_index',Angle_index);
    assignin('caller','nBonds',nBonds);
    assignin('caller','nAngles',nAngles);
catch
    assignin('base','dist_matrix',dist_matrix);
    assignin('base','overlap_index',overlap_index);
    assignin('base','Bond_index',Bond_index);
    assignin('base','Angle_index',Angle_index);
    assignin('base','nBonds',nBonds);
    assignin('base','nAngles',nAngles);
end
% toc