03-May-2017 16:55:50 classdef spikeTimes < handle % SPIKETIMES % % [obj] = spikeTimes(NeuralDir, exclusions, options) % % This routine compiles precise spike times for all units and is meant % as a companion to the spatialcorrelates object class % % This processing assumes that the Neural Data are formatted according % to the Buzsaki Lab Framework (.res and .clu files). These specifications are a little % fragile, and are detailed below. % % author: John D. Long II, PhD contact: jlong29@gmail.com % %%%%%%%%%%%%%% %%% INPUTS %%% %%%%%%%%%%%%%% % NeuralDir: a string designating the absolute path to the neural data % directory. No trailing filesep. % BehaviorDir: a string designating the absolute path to the behavioral % data directory. No trailing filesep. % Trigger: a vector at the lfp sampling rate containing camera % triggers used to align the neural data to the behavioral % data. These are steps pulses i.e. TTLs % exclusions: a structure with the fields: % -shanks: to exclude bad shanks % e.g. [1 3 7 8] i.e. lists of integer indices % options: an optional structure allowing the user to overwrite any % free parameters set in the routine. Just set a field of % "options" to the variables name with an appropriate value. %%%%%%%%%%%%%%% %%% OUTPUTS %%% %%%%%%%%%%%%%%% % obj: a hierarchical object with fields: % params: is a structure of input parameters % neuralpath : the directory in which the neural data resides % filebase : the base name of the neural files used % SRspikes : sampling rate of spike data % excludeshanks : shanks excluded from the analysis % % pershank: a structure detailing per shank variables % ShankID: formatted xx 2-digit [1-99] shankID % UnitIds: formatted xxyyy with xx being shankID and yyy being unit id % Ts: A cell array {unit} of time-stamps for each unit properties (SetAccess = public, GetAccess = public) params pershank end methods % Constructor % function obj = spikeTimes(NeuralDir, exclusions, options) %%%%%%%%%%%%%%%%%%%% %%% INPUT CHECKS %%% %%%%%%%%%%%%%%%%%%%% CurrentDir = pwd; if isdir(NeuralDir) % check for and access expected res and clu files resfiles = dir(fullfile(NeuralDir,'*.res.*')); if isempty(resfiles) error(['spikeTimes: FileNotFound: there are no res files in the NeuralDir:\n'... '\tCheck the ''NeuralDir'' directory']); else clufiles = dir(fullfile(NeuralDir,'*.clu.*')); %check to make sure the number of res and clue files are the same if length(resfiles) ~= length(clufiles) error(['spikeTimes: CountError: the number of res and clu files is not equal:\n'... '\tCheck the directories']); end end else error(['spikeTimes: PathError: the path ''NeuralDir'' input by the user does not exist:\n'... '\tConfirm path and then try again']); end [~,filebase,~] = fileparts(NeuralDir); % check for any exclusions if nargin < 2 || isempty(exclusions) excludeshanks = []; else if isfield(exclusions,'shanks') excludeshanks = exclusions.shanks; else warning(['spikeTimes: InputWarning: the structure ''exclusions'' does not have\n' ... '\tthe field ''shanks''. Using th Default; []']); excludeshanks = []; end end %%%%%%%%%%%%%%%%%%%%%%%%%%% %%% SET Free Parameters %%% %%%%%%%%%%%%%%%%%%%%%%%%%%% SRspikes = 20000; % spike sampling rate nSamples = 32; % samples per spike waveform MaxSpikeBytes = 5*1024^3;% maximum size used to determine processing branch % Check for options structure for overwriting free parameters if nargin > 5 && ~isempty(options) v2struct(options) end % store parameter settings for this run params.neuralpath = NeuralDir; params.filebase = filebase; params.SRspikes = SRspikes; params.nSamples = nSamples; params.excludeshanks = excludeshanks; %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Neural Data Pre-processing %%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % exclude bad shanks % load spike data and populate unit IDs Nshanks = length(resfiles); bad_shanks = false(length(Nshanks),1); for ii = 1:Nshanks shankID = strfind(resfiles(ii).name,'.'); shankID = str2double(resfiles(ii).name(shankID(end)+1:end)); if ismember(shankID,excludeshanks) bad_shanks(ii) = true; end end resfiles(bad_shanks) = []; clufiles(bad_shanks) = []; Nshanks = length(resfiles); % file size check for processing SpikeBytes = sum([cat(2,resfiles(:).bytes); cat(2,clufiles(:).bytes)]); %%% END: Neural Data Pre-processing %%% % DECLARE: pershank variables: % ShankID: formatted xx 2-digit [1-99] shankID % UnitIds: formatted xxyyy with xx being shankID and yyy being unit id % Ts: A cell array {unit} of time-stamps for each unit pershank = struct('ShankID', cell(Nshanks,1), ... 'UnitIds', cell(Nshanks,1), ... 'Ts', cell(Nshanks,1)); %%% END: Initialize Variables: shared and pershank %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Main Processing Loop %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%% % check processing branch based upon file size if all(SpikeBytes < MaxSpikeBytes) % access Neural Data cd(NeuralDir) %%%%%%%%%%%%%%%%%%%%%%%% %%% LOOP OVER Shanks %%% %%%%%%%%%%%%%%%%%%%%%%%% % load spike data and populate unit IDs for ii = 1:Nshanks % log shank ID shankID = strfind(resfiles(ii).name,'.'); shankID = str2double(resfiles(ii).name(shankID(end)+1:end)); % log shank id pershank(ii).ShankID = shankID; % load res and clu file clu = load(clufiles(ii).name); res = load(resfiles(ii).name); % convert spike times to seconds res = res/SRspikes; % The number of units and a vector of ids Nneurons = clu(1); % get rid of the artifact and multiunit clu and generate SpikeMat % Numbers units according to klusteraquik convention if sum(clu==0)>0 ids = 2:Nneurons-1; else ids = 2:Nneurons; end % Update output UnitIds: to find index: e.g. round(strfind(UnitIds,'02010')/6)+1 pershank(ii).UnitIds = ... sprintf('%02d%03d\n',[shankID*ones(1,length(ids));ids]); % Shift unit ids to 1:end Ids = ids - 1; Nneurons = length(Ids); % log spike data as ids 1:end SpikeMat = [res clu(2:end)-1]; SpikeMat((SpikeMat(:,2) == -1) | (SpikeMat(:,2) == 0),:) = []; % Write out time-stamps for units on this shank Ts = cell(Nneurons,1); for jj = 1:Nneurons idx = SpikeMat(:,2) == jj; Ts{jj} = SpikeMat(idx,1); end pershank(ii).Ts = Ts; end clear clu res SpikeMat else cd(CurrentDir) error(['spikeTimes: There is a maximum file size of %6.3 Gb accepted by this code.\n', ... '\tChange the internal variable "MaxSpikeByes" if this is too low'],MaxSpikeByes/1024^3); end %%%%%%%%%%%%%%%%%%%%%%% %%% GENERATE OUTPUT %%% %%%%%%%%%%%%%%%%%%%%%%% % put it all together obj.pershank = pershank; obj.params = params; % save output to CurrentDir % save(fullfile(CurrentDir,[filebase '_ts.mat']),'obj','-v7.3') [~,filename] = fileparts(NeuralDir); if contains(filename,'_reo') rind = regexp(filename,'_reo'); filename = filename(1:(rind(1)-1)); end save(fullfile('/home/kathryn/Dropbox/spCorrs/spCorrs04182017/TS/',[filename, '_TS']),'obj','-v7.3'); %return to caller directory cd(CurrentDir) % write out log file logAnalysisFile(mfilename('fullpath'),CurrentDir); end function [shankID, unitID] = accessUnit(obj, Unit) % accessUnit: This subroutine is associated with spatialcorrelates and allows the user % to input a 'xxyyy', xx -> shankID, yyy -> unitID, and returns the % corresponding shankID and unitID relative to the spatialcorrelates data % structure % % INPUT % obj: a spatialcorrelates data object % Unit: a 'xxyyy' shank and unit string if isempty(Unit) error('spikeTimes::accessUnit::InputError:No Unit identification provided by user'); else shank = str2double(Unit(1:2)); shankID = find(cat(1,obj.pershank(:).ShankID) == shank); if isempty(shankID) error('spikeTimes::accessUnit::IncorrectInput:No shank matching the user input was found'); end unitID = strfind(obj.pershank(shankID).UnitIds,Unit); if isempty(unitID) error('spikeTimes::accessUnit::IncorrectInput:No unit matching the user input was found'); end unitID = floor(unitID/6)+1; end end % Get list of unit ids by either shank or all % function UnitList = getUnitIdList(obj, Inp0) % Inputs: no inputs or a numeric shank id if nargin < 2 Nshanks = numel(obj.pershank); UnitList = cell(Nshanks,1); for ii = 1:Nshanks IdChars = obj.pershank(ii).UnitIds; Nunits = size(IdChars,2)/6; tmpList = cell(Nunits,1); for jj = 1:Nunits tmpList{jj} = IdChars(6*(jj-1)+1:6*jj-1); end UnitList{ii} = tmpList; end UnitList = cat(1,UnitList{:}); elseif nargin < 3 shankId = cat(1, obj.pershank(:).ShankID) == Inp0; if sum(shankId) == 0 error('spikeTimes::getUnitIdList::ShankNotFound'); end IdChars = obj.pershank(shankId).UnitIds; Nunits = size(IdChars,2)/6; UnitList = cell(Nunits,1); for ii = 1:Nunits UnitList{ii} = IdChars(6*(ii-1)+1:6*ii-1); end else error('spikeTimes::getUnitIdList::IncorrectInput: too many inputs'); end end end end % EOF