
% fea_transmissibility_core.m  ver 1.1 by Tom Irvine

function[f,acc,rd]=fea_transmissibility_core(f,nff,nem,ModeShapes,MST,...
                             Mwd,damp,omegan,TT,ngw,TZ_tracking_array,node,num_modes)

ij   = TZ_tracking_array(node);

np   = numel(f);
omega = 2*pi*f(:);                 % column
om2   = omega.^2;

% modal data (columns)
damp   = damp(:);
omegan = omegan(:);
omn2   = omegan.^2;

% excitation vector for A
y  = ones(nem,1);
A  = -MST*Mwd*y;                   % nff×1

acc = zeros(np,1,'like',omega);
rd  = zeros(np,1,'like',omega);

% how many modes to use this pass
nffx = min([nff, numel(damp), numel(omegan), numel(om2), num_modes]);
idx  = 1:nffx;

% precompute column-shaped pieces
Ai    = A(idx);
omn2i = omn2(idx);
itdi  = (2*1i) * (damp(idx).*omegan(idx));    % nffx×1

% reduce ModeShapes to active columns
Md = ModeShapes(:, idx);

% map desired full-DOF index once
pos = find(ngw == ij, 1);
assert(~isempty(pos), 'Index ij not found in ngw.');

oneNem = ones(nem,1,'like',A);

progressbar;
for k = 1:np
    progressbar(k/np);

    den  = omn2i - om2(k) + omega(k).*itdi;   % nffx×1
    Xk   = Md * (Ai ./ den);                  % equals ModeShapes*N with N(idx)=Ai./den

    Ud_k = (-1/om2(k)) * oneNem;

    U    = TT * [Ud_k; Xk];

    uij  = U(pos);
    acc(k) = om2(k) * abs(uij);
    rd(k)  = abs(uij - Ud_k(1));
end
progressbar(1);
pause(0.2);
