function Kilosort2Neurosuite(rez) % Converts KiloSort output (.rez structure) to Neurosuite files: fet,res,clu,spk files. % Based on the GPU enable filter from Kilosort and fractions from Brendon % Watson's code for saving Neurosuite files. % % 1) Waveforms are extracted from the dat file via GPU enabled filters. % 2) Features are calculated in parfor loops. % % Inputs: % rez - rez structure from Kilosort % % By Peter Petersen 2018 % petersen.peter@gmail.com t1 = tic; spikeTimes = uint64(rez.st3(:,1)); % uint64 spikeTemplates = uint32(rez.st3(:,2)); % uint32 % template id for each spike kcoords = rez.ops.kcoords; basename = rez.ops.basename; sizeInBytes = 2; if exist([rez.ops.root filesep 'chanMap.mat']) v = load([rez.ops.root filesep 'chanMap.mat']); connected = v.connected; end Nchan = rez.ops.Nchan; samples = rez.ops.nt0; templates = zeros(Nchan, size(rez.W,1), rez.ops.Nfilt, 'single'); for iNN = 1:rez.ops.Nfilt templates(:,:,iNN) = squeeze(rez.U(:,iNN,:)) * squeeze(rez.W(:,iNN,:))'; end amplitude_max_channel = []; for i = 1:size(templates,3) [~,amplitude_max_channel(i)] = max(range(templates(:,:,i)')); end template_kcoords = kcoords(amplitude_max_channel); kcoords2 = unique(template_kcoords); ia = []; for i = 1:length(kcoords2) kcoords3 = kcoords2(i); disp(['-Loading data for spike group ', num2str(kcoords3)]) template_index = find(template_kcoords == kcoords3); ia{i} = find(ismember(spikeTemplates,template_index)); end rez.ia = ia; toc(t1) disp('Saving .clu files to disk (cluster indexes)') for i = 1:length(kcoords2) kcoords3 = kcoords2(i); disp(['-Saving .clu file for group ', num2str(kcoords3)]) tclu = spikeTemplates(ia{i}); tclu = cat(1,length(unique(tclu)),double(tclu)); cluname = fullfile([basename '.clu.' num2str(kcoords3)]); if ~exist(cluname) fid=fopen(cluname,'w'); fprintf(fid,'%.0f\n',tclu); fclose(fid); clear fid end end toc(t1) disp('Saving .res files to disk (spike times)') for i = 1:length(kcoords2) kcoords3 = kcoords2(i); tspktimes = spikeTimes(ia{i}); disp(['-Saving .res file for group ', num2str(kcoords3)]) resname = fullfile([basename '.res.' num2str(kcoords3)]); if ~exist(resname) fid=fopen(resname,'w'); fprintf(fid,'%.0f\n',tspktimes); fclose(fid); clear fid end end toc(t1) disp('Extracting waveforms') Kilosort_ExtractWaveforms(rez); toc(t1) disp('Computing PCAs') % Starting parpool if stated in the Kilosort settings Kilosort_MakeFet(rez) toc(t1) disp('Complete!') function Kilosort_ExtractWaveforms(rez) % Extracts waveforms from a dat file using GPU enable filters. % Based on the GPU enable filter from Kilosort. % All settings and content are extracted from the rez input structure % % Inputs: % rez - rez structure from Kilosort % % Outputs: % waveforms_all - structure with extracted waveforms % Extracting content from the .rez file ops = rez.ops; NT = ops.NT; fid = fopen(ops.fbinary, 'r'); if exist(ops.fbinary) d = dir(ops.fbinary); else [fname,dirName] = uigetfile('*.dat'); d = dir([dirName fname]); ops.root = dirName; ops.fbinary = [dirName fname]; end NchanTOT = ops.NchanTOT; chanMap = ops.chanMap; chanMapConn = chanMap(rez.connected>1e-6); kcoords = ops.kcoords; ia = rez.ia; spikeTimes = uint64(rez.st3(:,1)); if ispc dmem = memory; memfree = dmem.MemAvailableAllArrays/8; memallocated = min(ops.ForceMaxRAMforDat, dmem.MemAvailableAllArrays) - memfree; memallocated = max(0, memallocated); else memallocated = ops.ForceMaxRAMforDat; end ops.ForceMaxRAMforDat = 10000000000; memallocated = ops.ForceMaxRAMforDat; nint16s = memallocated/2; NTbuff = NT + 4*ops.ntbuff; Nbatch = ceil(d.bytes/2/NchanTOT /(NT-ops.ntbuff)); Nbatch_buff = floor(4/5 * nint16s/ops.Nchan /(NT-ops.ntbuff)); % factor of 4/5 for storing PCs of spikes Nbatch_buff = min(Nbatch_buff, Nbatch); if isfield(ops,'fslow')&&ops.fslow