From e4c06940929f1e504aec0a70f54dce1bd4640ddb Mon Sep 17 00:00:00 2001
From: epnev <eap2111@columbia.edu>
Date: Thu, 28 Jan 2016 14:34:16 -0500
Subject: [PATCH] combine update_temporal_compoents & parallel

combine update_temporal_compoents & update_temporal_components_parallel
into a single function. The default option is to use the parallel
implementation if the parallel processing toolbox is present
---
 @Sources2D/Sources2D.m                |   8 +-
 CNMFSetParms.m                        | 118 ++++++-----
 demo_script.m                         |   4 +-
 update_temporal_components.m          | 295 ++++++++++++++++++--------
 update_temporal_components_parallel.m | 233 +-------------------
 5 files changed, 275 insertions(+), 383 deletions(-)

diff --git a/@Sources2D/Sources2D.m b/@Sources2D/Sources2D.m
index a0e54e8..ef48481 100644
--- a/@Sources2D/Sources2D.m
+++ b/@Sources2D/Sources2D.m
@@ -56,13 +56,7 @@ function updateTemporal(obj, Y)
             [obj.C, obj.f, obj.P, obj.S] = update_temporal_components(...
                 Y, obj.A, obj.b, obj.C, obj.f, obj.P, obj.options);
         end
-        
-        %% update temporal components in parallel
-        function updateTemporalParallel(obj, Y)
-            [obj.C, obj.f, obj.P, obj.S] = update_temporal_components_parallel(...
-                Y, obj.A, obj.b, obj.C, obj.f, obj.P, obj.options);
-        end
-                
+                       
         %% merge found components
         function [nr, merged_ROIs] = merge(obj, Y)
             [obj.A, obj.C, nr, merged_ROIs, obj.P, obj.S] = merge_components(...
diff --git a/CNMFSetParms.m b/CNMFSetParms.m
index 854c953..bd5d4c4 100644
--- a/CNMFSetParms.m
+++ b/CNMFSetParms.m
@@ -8,76 +8,77 @@
 
 Names = [
     % dataset info
-    'd1             ' % number of rows
-    'd2             ' % number of cols
+    'd1                 ' % number of rows
+    'd2                 ' % number of cols
     % INITIALIZATION  (initialize_components.m)
-    'ssub           ' % spatial downsampling factor (default: 1)
-    'tsub           ' % temporal downsampling factor (default: 1)
-    'init_method    ' % initialization method ('greedy','sparse_NMF') (default: 'greedy')
+    'ssub               ' % spatial downsampling factor (default: 1)
+    'tsub               ' % temporal downsampling factor (default: 1)
+    'init_method        ' % initialization method ('greedy','sparse_NMF') (default: 'greedy')
     % greedyROI parameters (greedyROI2d.m)
-    'gSig           ' % half size of neurons to be found (default: [5,5])
-    'gSiz           ' % half size of bounding box for each neuron (default: 2*gSig+1)
-    'nb             ' % number of background components (default: 1)
-    'nIter          ' % maximum number of rank-1 NMF iterations during refining
-    'med_app        ' % number of timesteps to be interleaved for fast (approximate) median calculation (default: 1)   
-    'save_memory    ' % process data sequentially to save memory (default: 0)
-    'chunkSiz       ' % filter this number of timesteps each time (default: 100)
-    'windowSiz      ' % size of window over which is computed sequentially (default: 32 x 32)
+    'gSig               ' % half size of neurons to be found (default: [5,5])
+    'gSiz               ' % half size of bounding box for each neuron (default: 2*gSig+1)
+    'nb                 ' % number of background components (default: 1)
+    'nIter              ' % maximum number of rank-1 NMF iterations during refining
+    'med_app            ' % number of timesteps to be interleaved for fast (approximate) median calculation (default: 1)   
+    'save_memory        ' % process data sequentially to save memory (default: 0)
+    'chunkSiz           ' % filter this number of timesteps each time (default: 100)
+    'windowSiz          ' % size of window over which is computed sequentially (default: 32 x 32)
     % sparse_NMF parameters (sparse_NMF_initialization.m)
-    'snmf_max_iter  ' % max # of sparse NMF iterations
-    'err_thr        ' % relative change threshold for stopping sparse_NMF
-    'eta            ' % frobenious norm factor *max(Y(:))^2
-    'beta           ' % sparsity factor
+    'snmf_max_iter      ' % max # of sparse NMF iterations
+    'err_thr            ' % relative change threshold for stopping sparse_NMF
+    'eta                ' % frobenious norm factor *max(Y(:))^2
+    'beta               ' % sparsity factor
     % HALS parameters (HALS_2d.m)
-    'bSiz           ' % expand kernel for HALS growing (default: 3)
-    'maxIter        ' % maximum number of HALS iterations (default: 5)
+    'bSiz               ' % expand kernel for HALS growing (default: 3)
+    'maxIter            ' % maximum number of HALS iterations (default: 5)
     % Noise and AR coefficients calculation (preprocess_data.m)
-    'noise_range    ' % frequency range over which to estimate the noise (default: [0.25,0.5]) 
-    'noise_method   ' % method for which to estimate the noise level (default: 'logmexp')            
-    'flag_g         ' % compute global AR coefficients (default: false)
-    'lags           ' % number of extra lags when computing the AR coefficients (default: 5)
-    'include_noise  ' % include early lags when computing AR coefs (default: 0)
-    'pixels         ' % pixels to include when computing the AR coefs (default: 1:numel(Y)/size(Y,ndims(Y)))
-    'split_data     ' % split data into patches for memory reasons (default: 0)
-    'block_size     ' % block size for estimating noise std in patches (default: [64,64])
+    'noise_range        ' % frequency range over which to estimate the noise (default: [0.25,0.5]) 
+    'noise_method       ' % method for which to estimate the noise level (default: 'logmexp')            
+    'flag_g             ' % compute global AR coefficients (default: false)
+    'lags               ' % number of extra lags when computing the AR coefficients (default: 5)
+    'include_noise      ' % include early lags when computing AR coefs (default: 0)
+    'pixels             ' % pixels to include when computing the AR coefs (default: 1:numel(Y)/size(Y,ndims(Y)))
+    'split_data         ' % split data into patches for memory reasons (default: 0)
+    'block_size         ' % block size for estimating noise std in patches (default: [64,64])
     % UPDATING SPATIAL COMPONENTS (unpdate_spatial_components.m)
-    'search_method  ' % method for determining footprint of spatial components 'ellipse' or 'dilate' (default: 'ellipse')
-    'use_parallel   ' % update pixels in parallel (default: 1 if present)
+    'search_method      ' % method for determining footprint of spatial components 'ellipse' or 'dilate' (default: 'ellipse')
+    'use_parallel       ' % update pixels in parallel (default: 1 if present)
     % determine_search_location.m
-    'min_size       ' % minimum size of ellipse axis (default: 3)
-    'max_size       ' % maximum size of ellipse axis (default: 8)
-    'dist           ' % expansion factor of ellipse (default: 3)
-    'se             ' % morphological element for dilation (default: strel('disk',4,0))
+    'min_size           ' % minimum size of ellipse axis (default: 3)
+    'max_size           ' % maximum size of ellipse axis (default: 8)
+    'dist               ' % expansion factor of ellipse (default: 3)
+    'se                 ' % morphological element for dilation (default: strel('disk',4,0))
     % threshold_components.m
-    'nrgthr         ' % energy threshold (default: 0.9999)
-    'clos_op        ' % morphological element for closing (default: strel('square',3))
-    'medw           ' % size of median filter (default: [3,3])
+    'nrgthr             ' % energy threshold (default: 0.9999)
+    'clos_op            ' % morphological element for closing (default: strel('square',3))
+    'medw               ' % size of median filter (default: [3,3])
     % UPDATING TEMPORAL COMPONENTS (update_temporal_components.m)
-    'deconv_method  ' % method for spike deconvolution (default: 'constrained_foopsi')
-    'restimate_g    ' % flag for updating the time constants for each component (default: 1)
-    'temporal_iter  ' % number of block-coordinate descent iterations (default 2)
+    'deconv_method      '    % method for spike deconvolution (default: 'constrained_foopsi')
+    'restimate_g        '    % flag for updating the time constants for each component (default: 1)
+    'temporal_iter      '    % number of block-coordinate descent iterations (default: 2)
+    'temporal_parallel  ' % flag for parallel updating of temporal components (default: true if present)
     % CONSTRAINED DECONVOLUTION (constrained_foopsi.m)
-    'method         ' % methods for performing spike inference ('dual','cvx','spgl1','lars') (default:'cvx')
-    'bas_nonneg     ' % flag for setting the baseline lower bound. if 1, then b >= 0 else b >= min(y) (default 0)
-    'fudge_factor   ' % scaling constant to reduce bias in the time constant estimation (default 1 - no scaling)
-    'resparse       ' % number of times that the solution is resparsened (default: 0)
+    'method             ' % methods for performing spike inference ('dual','cvx','spgl1','lars') (default:'cvx')
+    'bas_nonneg         ' % flag for setting the baseline lower bound. if 1, then b >= 0 else b >= min(y) (default 0)
+    'fudge_factor       ' % scaling constant to reduce bias in the time constant estimation (default 1 - no scaling)
+    'resparse           ' % number of times that the solution is resparsened (default: 0)
     % MERGING (merge_ROIs.m)
-    'merge_thr      ' % merging threshold (default: 0.85)
-    'fast_merge     ' % flag for using fast merging (default 1)
+    'merge_thr          ' % merging threshold (default: 0.85)
+    'fast_merge         ' % flag for using fast merging (default 1)
     % VIDEO (make_patch_video.m)
-    'ind            ' % indeces of components to be shown (deafult: 1:4)
-    'skip_frame     ' % skip frames when showing the video (default: 1 (no skipping))
-    'sx             ' % half size of representative patches (default: 16)
-    'make_avi       ' % flag for saving avi video (default: 0)
-    'show_background' % flag for displaying the background in the denoised panel (default: 1)
-    'show_contours  ' % flag for showing the contour plots of the patches in the FoV (default: 0)
-    'cmap           ' % colormap for plotting (default: 'default')
-    'name           ' % name of saved video file (default: based on current date)
+    'ind                ' % indeces of components to be shown (deafult: 1:4)
+    'skip_frame         ' % skip frames when showing the video (default: 1 (no skipping))
+    'sx                 ' % half size of representative patches (default: 16)
+    'make_avi           ' % flag for saving avi video (default: 0)
+    'show_background    ' % flag for displaying the background in the denoised panel (default: 1)
+    'show_contours      ' % flag for showing the contour plots of the patches in the FoV (default: 0)
+    'cmap               ' % colormap for plotting (default: 'default')
+    'name               ' % name of saved video file (default: based on current date)
     % PLOT COMPONENTS (view_patches.m)
-    'plot_df        ' % flag for displaying DF/F estimates (default: 1)
-    'make_gif       ' % save animation (default: 0)
-    'save_avi       ' % save video (default: 0)
-    'pause_time     ' % time to pause between each component (default: Inf, user has to click)
+    'plot_df            ' % flag for displaying DF/F estimates (default: 1)
+    'make_gif           ' % save animation (default: 0)
+    'save_avi           ' % save video (default: 0)
+    'pause_time         ' % time to pause between each component (default: Inf, user has to click)
     ];
 
 [m,n] = size(Names);
@@ -207,6 +208,7 @@
     {'constrained_foopsi'}
     {1}
     {2}
+    {~isempty(which('parpool'))}
     % CONSTRAINED DECONVOLUTION (constrained_foopsi.m)
     {'cvx'}
     {0}
@@ -216,7 +218,7 @@
     {0.85}
     {1}
     % VIDEO (make_patch_video.m)
-    {[1:4]}
+    {1:4}
     {1}
     {16}
     {0}
diff --git a/demo_script.m b/demo_script.m
index 3baf9f4..6b5f384 100644
--- a/demo_script.m
+++ b/demo_script.m
@@ -8,6 +8,7 @@
 num2read=2000;					% user input: how many frames to read   (optional, default until the end)
 
 Y = bigread2(nam,sframe,num2read);
+Y = Y - min(Y(:)); 
 if ~isa(Y,'double');    Y = double(Y);  end         % convert to double
 
 [d1,d2,T] = size(Y);                                % dimensions of dataset
@@ -25,7 +26,7 @@
     'search_method','ellipse','dist',3,...      % search locations when updating spatial components
     'deconv_method','constrained_foopsi',...    % activity deconvolution method
     'temporal_iter',2,...                       % number of block-coordinate descent steps 
-    'fudge_factor',0.98,...                      % bias correction for AR coefficients
+    'fudge_factor',0.98,...                     % bias correction for AR coefficients
     'merge_thr',merge_thr...                    % merging threshold
     );
 %% Data pre-processing
@@ -50,7 +51,6 @@
 [A,b] = update_spatial_components(Yr,Cin,fin,Ain,P,options);
 
 %% update temporal components
-% consider using update_temporal_components_parallel for increased speed
 [C,f,P,S] = update_temporal_components(Yr,A,b,Cin,fin,P,options);
 
 %% merge found components
diff --git a/update_temporal_components.m b/update_temporal_components.m
index f257e83..e686d9e 100644
--- a/update_temporal_components.m
+++ b/update_temporal_components.m
@@ -19,6 +19,9 @@
 %           subject to:   G*c_j >= 0
 %                         ||Y(i,:) - A*C - b*f|| <= sn(i)*sqrt(T)
 
+% The update can happen either in parallel (default) or serial by tuning options.temporal_parallel. 
+% In the case of parallel implementation the methods 'MCEM_foopsi' and 'noise_constrained' are not supported
+
 % INPUTS:
 % Y:        raw data ( d X T matrix)
 % A:        spatial footprints  (d x nr matrix)
@@ -53,6 +56,7 @@
 if ~isfield(options,'temporal_iter') || isempty(options.temporal_iter); ITER = defoptions.temporal_iter; else ITER = options.temporal_iter; end           % number of block-coordinate descent iterations
 if ~isfield(options,'bas_nonneg'); options.bas_nonneg = defoptions.bas_nonneg; end
 if ~isfield(options,'fudge_factor'); options.fudge_factor = defoptions.fudge_factor; end
+if ~isfield(options,'temporal_parallel'); options.temporal_parallel = defoptions.temporal_parallel; end
 
 if isfield(P,'interp'); Y_interp = P.interp; else Y_interp = sparse(d,T); end        % missing data
 if isfield(P,'unsaturatedPix'); unsaturatedPix = P.unsaturatedPix; else unsaturatedPix = 1:d; end   % saturated pixels
@@ -62,8 +66,14 @@
 
 if (strcmpi(method,'noise_constrained') || strcmpi(method,'project')) && ~isfield(P,'g')
     options.flag_g = 1;
-    if ~isfield(P,'p') || isempty(P.p); p = 2; end; 
-    [P,Y] = preprocess_data(Y,p,options);
+    if ~isfield(P,'p') || isempty(P.p); P.p = 2; end; 
+    p = P.p;
+    P = arpfit(Yr,p,options,P.sn);
+    if ~iscell(P.g)
+        G = make_G_matrix(T,P.g);
+    end
+else
+    G = speye(T);
 end
 
 ff = find(sum(A)==0);
@@ -117,99 +127,208 @@
         P.c1 = cell(K,1);           
         P.neuron_sn = cell(K,1);
     end
+    if strcmpi(method,'MCMC')        
+        params.B = 300;
+        params.Nsamples = 400;
+        params.p = P.p;
+    else
+        params = [];
+    end
 end
-for iter = 1:ITER
+p = P.p;
+if options.temporal_parallel
+    for iter = 1:ITER
+        [O,lo] = update_order(A(:,1:K));
+        for jo = 1:length(O)
+            Ytemp = YrA(:,O{jo}(:)) + (diag(nA(O{jo}))*Cin(O{jo},:))';
+            Ctemp = zeros(length(O{jo}),T);
+            Stemp = zeros(length(O{jo}),T);
+            btemp = zeros(length(O{jo}),1);
+            sntemp = btemp;
+            c1temp = btemp;
+            gtemp = cell(length(O{jo}),1);
+            nT = nA(O{jo});
+            % FN added the part below in order to save SAMPLES as a field of P
+            if strcmpi(method,'MCMC')
+                clear samples_mcmc
+                samples_mcmc(length(O{jo})) = struct();
+                [samples_mcmc.Cb] = deal(zeros(params.Nsamples,1));
+                [samples_mcmc.Cin] = deal(zeros(params.Nsamples,1));
+                [samples_mcmc.sn2] = deal(zeros(params.Nsamples,1));
+                [samples_mcmc.ns] = deal(zeros(params.Nsamples,1));
+                [samples_mcmc.ss] = deal(cell(params.Nsamples,1));
+                [samples_mcmc.ld] = deal(zeros(params.Nsamples,1));
+                [samples_mcmc.Am] = deal(zeros(params.Nsamples,1));
+                [samples_mcmc.g] = deal(zeros(params.Nsamples,1));
+                [samples_mcmc.params] = deal(struct('lam_', [], 'spiketimes_', [], 'A_', [], 'b_', [], 'C_in', [], 'sg', [], 'g', []));
+            end
+            parfor jj = 1:length(O{jo})
+                if p == 0   % p = 0 (no dynamics assumed)
+                    cc = max(Ytemp(:,jj)/nT(jj),0);
+                    Ctemp(jj,:) = full(cc');
+                    Stemp(jj,:) = C(jj,:);
+                else
+                    switch method
+                        case 'project'
+                            maxy = max(Ytemp(:,jj)/nT(jj));
+                            cc = plain_foopsi(Ytemp(:,jj)/nT(jj)/maxy,G);
+                            Ctemp(jj,:) = full(cc')*maxy;
+                            Stemp(jj,:) = Ctemp(jj,:)*G';
+                        case 'constrained_foopsi'
+                            %if restimate_g
+                            [cc,cb,c1,gn,sn,spk] = constrained_foopsi(Ytemp(:,jj)/nT(jj),[],[],[],[],options);
+                            %else
+                            %    [cc,cb,c1,gn,sn,spk] = constrained_foopsi(Ytemp(:,jj)/nA(jj),[],[],P.g,[],options);
+                            %end
+                            gd = max(roots([1,-gn']));  % decay time constant for initial concentration
+                            gd_vec = gd.^((0:T-1));
+                            Ctemp(jj,:) = full(cc(:)' + cb + c1*gd_vec);
+                            Stemp(jj,:) = spk(:)';
+                            Ytemp(:,jj) = Ytemp(:,jj) - nT(jj)*Ctemp(jj,:)';
+                            btemp(jj) = cb;
+                            c1temp(jj) = c1;
+                            sntemp(jj) = sn;
+                            gtemp{jj} = gn(:)';
+                        case 'MCMC'
+                            SAMPLES = cont_ca_sampler(Ytemp(:,jj)/nT(jj),params);
+                            Ctemp(jj,:) = make_mean_sample(SAMPLES,Ytemp(:,jj)/nT(jj));
+                            Stemp(jj,:) = mean(samples_cell2mat(SAMPLES.ss,T));
+                            btemp(jj) = mean(SAMPLES.Cb);
+                            c1temp(jj) = mean(SAMPLES.Cin);
+                            sntemp(jj) = sqrt(mean(SAMPLES.sn2));
+                            gtemp{jj} = mean(exp(-1./SAMPLES.g))';
+                            samples_mcmc(jj) = SAMPLES; % FN added.
+                    end
+                end
+            end
+            if p > 0
+                if strcmpi(method,'constrained_foopsi') || strcmpi(method,'MCMC');
+                    P.b(O{jo}) = num2cell(btemp);
+                    P.c1(O{jo}) = num2cell(c1temp);
+                    P.neuron_sn(O{jo}) = num2cell(sntemp);
+                    for jj = 1:length(O{jo})
+                        P.gn(O{jo}(jj)) = gtemp(jj);
+                    end
+                    YrA(:,O{jo}(:)) = Ytemp;
+                    C(O{jo}(:),:) = Ctemp;
+                    S(O{jo}(:),:) = Stemp;
+
+                    if strcmpi(method,'MCMC');
+                        P.samples_mcmc(O{jo}) = samples_mcmc; % FN added, a useful parameter to have.
+                    end                
+                end
+            end
+            fprintf('%i out of %i components updated \n',sum(lo(1:jo)),K);
+        end
+        ii = K + 1;
+        YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
+        cc = max(YrA(:,ii)/nA(ii),0);
+        C(ii,:) = full(cc');
+        YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
+    %     if mod(jj,10) == 0
+    %         fprintf('%i out of total %i temporal components updated \n',jj,K);
+    %     end
+        %disp(norm(Fin(1:nr,:) - F,'fro')/norm(F,'fro'));
+        if norm(Cin - C,'fro')/norm(C,'fro') <= 1e-3
+            % stop if the overall temporal component does not change by much
+            break;
+        else
+            Cin = C;
+        end
+    end
+else
+    for iter = 1:ITER
     perm = randperm(K+size(b,2));
-    for jj = 1:K
-        ii = perm(jj);
-        if ii<=K
-            if P.p == 0   % p = 0 (no dynamics assumed)
+        for jj = 1:K
+            ii = perm(jj);
+            if ii<=K
+                if P.p == 0   % p = 0 (no dynamics assumed)
+                    YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
+                    maxy = max(YrA(:,ii)/nA(ii));
+                    cc = max(YrA(:,ii)/nA(ii)/maxy,0);
+                    C(ii,:) = full(cc')*maxy;
+                    YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
+                    S(ii,:) = C(ii,:);
+                else
+                    switch method
+                        case 'project'
+                            YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
+                            maxy = max(YrA(:,ii)/nA(ii));
+                            cc = plain_foopsi(YrA(:,ii)/nA(ii)/maxy,G);
+                            C(ii,:) = full(cc')*maxy;
+                            YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
+                            S(ii,:) = C(ii,:)*G';
+                        case 'constrained_foopsi'
+                            YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
+                            if restimate_g
+                                [cc,cb,c1,gn,sn,spk] = constrained_foopsi(YrA(:,ii)/nA(ii),[],[],[],[],options);
+                                P.gn{ii} = gn;
+                            else
+                                [cc,cb,c1,gn,sn,spk] = constrained_foopsi(YrA(:,ii)/nA(ii),[],[],P.g,[],options);
+                            end
+                            gd = max(roots([1,-gn']));  % decay time constant for initial concentration
+                            gd_vec = gd.^((0:T-1));
+                            C(ii,:) = full(cc(:)' + cb + c1*gd_vec);
+                            S(ii,:) = spk(:)';
+                            YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
+                            P.b{ii} = cb;
+                            P.c1{ii} = c1;           
+                            P.neuron_sn{ii} = sn;
+                        case 'MCEM_foopsi'
+                            options.p = length(P.g);
+                            YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
+                            [cc,cb,c1,gn,sn,spk] = MCEM_foopsi(YrA(:,ii)/nA(ii),[],[],P.g,[],options);
+                            gd = max(roots([1,-gn.g(:)']));
+                            gd_vec = gd.^((0:T-1));
+                            C(ii,:) = full(cc(:)' + cb + c1*gd_vec);
+                            S(ii,:) = spk(:)';
+                            YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
+                            P.b{ii} = cb;
+                            P.c1{ii} = c1;           
+                            P.neuron_sn{ii} = sn;
+                            P.gn{ii} = gn.g;
+                        case 'MCMC'
+                            params.B = 300;
+                            params.Nsamples = 400;
+                            params.p = P.p; %length(P.g);
+                            YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
+                            SAMPLES = cont_ca_sampler(YrA(:,ii)/nA(ii),params);
+                            C(ii,:) = make_mean_sample(SAMPLES,YrA(:,ii)/nA(ii));
+                            S(ii,:) = mean(samples_cell2mat(SAMPLES.ss,T));
+                            YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
+                            P.b{ii} = mean(SAMPLES.Cb);
+                            P.c1{ii} = mean(SAMPLES.Cin);
+                            P.neuron_sn{ii} = sqrt(mean(SAMPLES.sn2));
+                            P.gn{ii} = mean(exp(-1./SAMPLES.g));
+                            P.samples_mcmc(ii) = SAMPLES; % FN added, a useful parameter to have.
+                        case 'noise_constrained'
+                            Y_res = Y_res + A(:,ii)*Cin(ii,:);
+                            [~,srt] = sort(A(:,ii),'descend');
+                            ff = srt(1:mc);
+                            [cc,LD(:,ii)] = lagrangian_foopsi_temporal(Y_res(ff,:),A(ff,ii),T*P.sn(unsaturatedPix(ff)).^2,G,LD(:,ii));        
+                            C(ii,:) = full(cc');
+                            Y_res = Y_res - A(:,ii)*cc';
+                            S(ii,:) = C(ii,:)*G';
+                    end
+                end
+            else
                 YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
-                maxy = max(YrA(:,ii)/nA(ii));
-                cc = max(YrA(:,ii)/nA(ii)/maxy,0);
-                C(ii,:) = full(cc')*maxy;
+                cc = max(YrA(:,ii)/nA(ii),0);
+                C(ii,:) = full(cc');
                 YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
-                S(ii,:) = C(ii,:);
-            else
-                switch method
-                    case 'project'
-                        YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
-                        maxy = max(YrA(:,ii)/nA(ii));
-                        cc = plain_foopsi(YrA(:,ii)/nA(ii)/maxy,G);
-                        C(ii,:) = full(cc')*maxy;
-                        YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
-                        S(ii,:) = C(ii,:)*G';
-                    case 'constrained_foopsi'
-                        YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
-                        if restimate_g
-                            [cc,cb,c1,gn,sn,spk] = constrained_foopsi(YrA(:,ii)/nA(ii),[],[],[],[],options);
-                            P.gn{ii} = gn;
-                        else
-                            [cc,cb,c1,gn,sn,spk] = constrained_foopsi(YrA(:,ii)/nA(ii),[],[],P.g,[],options);
-                        end
-                        gd = max(roots([1,-gn']));  % decay time constant for initial concentration
-                        gd_vec = gd.^((0:T-1));
-                        C(ii,:) = full(cc(:)' + cb + c1*gd_vec);
-                        S(ii,:) = spk(:)';
-                        YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
-                        P.b{ii} = cb;
-                        P.c1{ii} = c1;           
-                        P.neuron_sn{ii} = sn;
-                    case 'MCEM_foopsi'
-                        options.p = length(P.g);
-                        YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
-                        [cc,cb,c1,gn,sn,spk] = MCEM_foopsi(YrA(:,ii)/nA(ii),[],[],P.g,[],options);
-                        gd = max(roots([1,-gn.g(:)']));
-                        gd_vec = gd.^((0:T-1));
-                        C(ii,:) = full(cc(:)' + cb + c1*gd_vec);
-                        S(ii,:) = spk(:)';
-                        YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
-                        P.b{ii} = cb;
-                        P.c1{ii} = c1;           
-                        P.neuron_sn{ii} = sn;
-                        P.gn{ii} = gn.g;
-                    case 'MCMC'
-                        params.B = 300;
-                        params.Nsamples = 400;
-                        params.p = P.p; %length(P.g);
-                        YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
-                        SAMPLES = cont_ca_sampler(YrA(:,ii)/nA(ii),params);
-                        C(ii,:) = make_mean_sample(SAMPLES,YrA(:,ii)/nA(ii));
-                        S(ii,:) = mean(samples_cell2mat(SAMPLES.ss,T));
-                        YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
-                        P.b{ii} = mean(SAMPLES.Cb);
-                        P.c1{ii} = mean(SAMPLES.Cin);
-                        P.neuron_sn{ii} = sqrt(mean(SAMPLES.sn2));
-                        P.gn{ii} = mean(exp(-1./SAMPLES.g));
-                        P.samples_mcmc(ii) = SAMPLES; % FN added, a useful parameter to have.
-                    case 'noise_constrained'
-                        Y_res = Y_res + A(:,ii)*Cin(ii,:);
-                        [~,srt] = sort(A(:,ii),'descend');
-                        ff = srt(1:mc);
-                        [cc,LD(:,ii)] = lagrangian_foopsi_temporal(Y_res(ff,:),A(ff,ii),T*P.sn(unsaturatedPix(ff)).^2,G,LD(:,ii));        
-                        C(ii,:) = full(cc');
-                        Y_res = Y_res - A(:,ii)*cc';
-                        S(ii,:) = C(ii,:)*G';
-                end
             end
-        else
-            YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
-            cc = max(YrA(:,ii)/nA(ii),0);
-            C(ii,:) = full(cc');
-            YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
+            if mod(jj,10) == 0
+                fprintf('%i out of total %i temporal components updated \n',jj,K);
+            end
         end
-        if mod(jj,10) == 0
-            fprintf('%i out of total %i temporal components updated \n',jj,K);
+        %disp(norm(Fin(1:nr,:) - F,'fro')/norm(F,'fro'));
+        if norm(Cin - C,'fro')/norm(C,'fro') <= 1e-3
+            % stop if the overall temporal component does not change by much
+            break;
+        else
+            Cin = C;
         end
     end
-    %disp(norm(Fin(1:nr,:) - F,'fro')/norm(F,'fro'));
-    if norm(Cin - C,'fro')/norm(C,'fro') <= 1e-3
-        % stop if the overall temporal component does not change by much
-        break;
-    else
-        Cin = C;
-    end
 end
-
 f = C(K+1:end,:);
-C = C(1:K,:);
+C = C(1:K,:);
\ No newline at end of file
diff --git a/update_temporal_components_parallel.m b/update_temporal_components_parallel.m
index bcacf38..77d84a8 100644
--- a/update_temporal_components_parallel.m
+++ b/update_temporal_components_parallel.m
@@ -2,236 +2,13 @@
 
 % update temporal components and background given spatial components in
 % parallel, by forming of sequence of vertex covers. 
-% A variety of different methods can be used and are separated into 2 classes:
-
-% 1-d approaches, where for each component a 1-d trace is computed by removing
-% the effect of all the other components and then averaging with the corresponding 
-% spatial footprint. Then each trace is denoised. This corresponds to a block-coordinate approach
-% 4 different 1-d approaches are included, and any custom method
-% can be easily incorporated:
-% 'project':                The trace is projected to satisfy the constraints by the (known) calcium indicator dynamics
-% 'constrained_foopsi':     The noise constrained deconvolution approach is used. Time constants can be re-estimated (default)
-% 'MCEM_foopsi':            Alternating between constrained_foopsi and a MH approach for re-estimating the time constants
-% 'MCMC':                   A fully Bayesian method (slowest, but usually most accurate)
-
-% multi-dimensional approaches: (slowest)
-% 'noise_constrained': 
-% C(j,:) = argmin_{c_j} sum(G*c_j), 
-%           subject to:   G*c_j >= 0
-%                         ||Y(i,:) - A*C - b*f|| <= sn(i)*sqrt(T)
-
-% INPUTS:
-% Y:        raw data ( d X T matrix)
-% A:        spatial footprints  (d x nr matrix)
-% b:        spatial background  (d x 1 vector)
-% Cin:      current estimate of temporal components (nr X T matrix)
-% fin:      current estimate of temporal background (1 x T vector)
-% P:        struct for neuron parameters
-% options:  struct for algorithm parameters
-
-% LD:       Lagrange multipliers (needed only for 'noise_constrained' method).
-% 
-% OUTPUTS:
-% C:        temporal components (nr X T matrix)
-% f:        temporal background (1 x T vector)
-% P:        struct for neuron parameters
-% S:        deconvolved activity
+% Note that the parallel implementation is now implemented by default from
+% update_temporal_components. update_temporal_components_parallel will be
+% removed in the next release.
 
 % Written by: 
 % Eftychios A. Pnevmatikakis, Simons Foundation, 2015
 
-[d,T] = size(Y);
-if isempty(P) || nargin < 6
-    active_pixels = find(sum(A,2));                                 % pixels where the greedy method found activity
-    unsaturated_pixels = find_unsaturatedPixels(Y);                 % pixels that do not exhibit saturation
-    options.pixels = intersect(active_pixels,unsaturated_pixels);   % base estimates only on unsaturated, active pixels                
-end
-
-defoptions = CNMFSetParms;
-if nargin < 7 || isempty(options); options = []; end
-if ~isfield(options,'deconv_method') || isempty(options.deconv_method); method = defoptions.deconv_method; else method = options.deconv_method; end  % choose method
-if ~isfield(options,'restimate_g') || isempty(options.restimate_g); restimate_g = defoptions.restimate_g; else restimate_g = options.restimate_g; end % re-estimate time constant (only with constrained foopsi)
-if ~isfield(options,'temporal_iter') || isempty(options.temporal_iter); ITER = defoptions.temporal_iter; else ITER = options.temporal_iter; end           % number of block-coordinate descent iterations
-if ~isfield(options,'bas_nonneg'); options.bas_nonneg = defoptions.bas_nonneg; end
-if ~isfield(options,'fudge_factor'); options.fudge_factor = defoptions.fudge_factor; end
-
-if isfield(P,'interp'); Y_interp = P.interp; else Y_interp = sparse(d,T); end        % missing data
-if isfield(P,'unsaturatedPix'); unsaturatedPix = P.unsaturatedPix; else unsaturatedPix = 1:d; end   % saturated pixels
-
-mis_data = find(Y_interp);              % interpolate any missing data before deconvolution
-Y(mis_data) = Y_interp(mis_data);
-
-if (strcmpi(method,'noise_constrained') || strcmpi(method,'project')) && ~isfield(P,'g')
-    options.flag_g = 1;
-    if ~isfield(P,'p') || isempty(P.p); P.p = 2; end; 
-    p = P.p;
-    P = arpfit(Yr,p,options,P.sn);
-    if ~iscell(P.g)
-        G = make_G_matrix(T,P.g);
-    end
-else
-    G = speye(T);
-end
-
-ff = find(sum(A)==0);
-if ~isempty(ff)
-    A(:,ff) = [];
-    if exist('Cin','var')
-        if ~isempty(Cin)
-            Cin(ff,:) = [];
-        end
-    end
-end
-
-if isempty(Cin) || nargin < 4
-    Cin = max((A'*A)\(A'*Y),0);
-    ITER = max(ITER,3);
-end
-
-if  isempty(b) || isempty(fin) || nargin < 5
-    if isempty(b) || nargin < 3
-        [b,fin] = nnmf(max(Y - A*Cin,0),1);
-    else
-        fin = max(b'*Y/norm(b)^2,0);
-    end
-end
-
-saturatedPix = setdiff(1:d,unsaturatedPix);     % remove any saturated pixels
-Ysat = Y(saturatedPix,:);
-Asat = A(saturatedPix,:);
-bsat = b(saturatedPix,:);
-Y = Y(unsaturatedPix,:);
-A = A(unsaturatedPix,:);
-b = b(unsaturatedPix,:);
-d = length(unsaturatedPix);
-
-K = size(A,2);
-A = [A,b];
-S = zeros(size(Cin));
-Cin = [Cin;fin];
-C = Cin;
-
-if strcmpi(method,'noise_constrained')
-    Y_res = Y - A*Cin;
-    mc = min(d,15);  % number of constraints to be considered
-    LD = 10*ones(mc,K);
-else
-    nA = sum(A.^2);
-    YrA = Y'*A - Cin'*(A'*A);
-    if strcmpi(method,'constrained_foopsi') || strcmpi(method,'MCEM_foopsi')
-        P.gn = cell(K,1);
-        P.b = cell(K,1);
-        P.c1 = cell(K,1);           
-        P.neuron_sn = cell(K,1);
-    end
-    if strcmpi(method,'MCMC')        
-        params.B = 300;
-        params.Nsamples = 400;
-        params.p = P.p;
-    else
-        params = [];
-    end
-end
-p = P.p;
-for iter = 1:ITER
-    [O,lo] = update_order(A(:,1:K));
-    for jo = 1:length(O)
-        Ytemp = YrA(:,O{jo}(:)) + (diag(nA(O{jo}))*Cin(O{jo},:))';
-        Ctemp = zeros(length(O{jo}),T);
-        Stemp = zeros(length(O{jo}),T);
-        btemp = zeros(length(O{jo}),1);
-        sntemp = btemp;
-        c1temp = btemp;
-        gtemp = cell(length(O{jo}),1);
-        nT = nA(O{jo});
-        % FN added the part below in order to save SAMPLES as a field of P
-        if strcmpi(method,'MCMC')
-            clear samples_mcmc
-            samples_mcmc(length(O{jo})) = struct();
-            [samples_mcmc.Cb] = deal(zeros(params.Nsamples,1));
-            [samples_mcmc.Cin] = deal(zeros(params.Nsamples,1));
-            [samples_mcmc.sn2] = deal(zeros(params.Nsamples,1));
-            [samples_mcmc.ns] = deal(zeros(params.Nsamples,1));
-            [samples_mcmc.ss] = deal(cell(params.Nsamples,1));
-            [samples_mcmc.ld] = deal(zeros(params.Nsamples,1));
-            [samples_mcmc.Am] = deal(zeros(params.Nsamples,1));
-            [samples_mcmc.g] = deal(zeros(params.Nsamples,1));
-            [samples_mcmc.params] = deal(struct('lam_', [], 'spiketimes_', [], 'A_', [], 'b_', [], 'C_in', [], 'sg', [], 'g', []));
-        end
-        parfor jj = 1:length(O{jo})
-            if p == 0   % p = 0 (no dynamics assumed)
-                cc = max(Ytemp(:,jj)/nT(jj),0);
-                Ctemp(jj,:) = full(cc');
-                Stemp(jj,:) = C(jj,:);
-            else
-                switch method
-                    case 'project'
-                        maxy = max(Ytemp(:,jj)/nT(jj));
-                        cc = plain_foopsi(Ytemp(:,jj)/nT(jj)/maxy,G);
-                        Ctemp(jj,:) = full(cc')*maxy;
-                        Stemp(jj,:) = Ctemp(jj,:)*G';
-                    case 'constrained_foopsi'
-                        %if restimate_g
-                        [cc,cb,c1,gn,sn,spk] = constrained_foopsi(Ytemp(:,jj)/nT(jj),[],[],[],[],options);
-                        %else
-                        %    [cc,cb,c1,gn,sn,spk] = constrained_foopsi(Ytemp(:,jj)/nA(jj),[],[],P.g,[],options);
-                        %end
-                        gd = max(roots([1,-gn']));  % decay time constant for initial concentration
-                        gd_vec = gd.^((0:T-1));
-                        Ctemp(jj,:) = full(cc(:)' + cb + c1*gd_vec);
-                        Stemp(jj,:) = spk(:)';
-                        Ytemp(:,jj) = Ytemp(:,jj) - nT(jj)*Ctemp(jj,:)';
-                        btemp(jj) = cb;
-                        c1temp(jj) = c1;
-                        sntemp(jj) = sn;
-                        gtemp{jj} = gn(:)';
-                    case 'MCMC'
-                        SAMPLES = cont_ca_sampler(Ytemp(:,jj)/nT(jj),params);
-                        Ctemp(jj,:) = make_mean_sample(SAMPLES,Ytemp(:,jj)/nT(jj));
-                        Stemp(jj,:) = mean(samples_cell2mat(SAMPLES.ss,T));
-                        btemp(jj) = mean(SAMPLES.Cb);
-                        c1temp(jj) = mean(SAMPLES.Cin);
-                        sntemp(jj) = sqrt(mean(SAMPLES.sn2));
-                        gtemp{jj} = mean(exp(-1./SAMPLES.g))';
-                        samples_mcmc(jj) = SAMPLES; % FN added.
-                end
-            end
-        end
-        if p > 0
-            if strcmpi(method,'constrained_foopsi') || strcmpi(method,'MCMC');
-                P.b(O{jo}) = num2cell(btemp);
-                P.c1(O{jo}) = num2cell(c1temp);
-                P.neuron_sn(O{jo}) = num2cell(sntemp);
-                for jj = 1:length(O{jo})
-                    P.gn(O{jo}(jj)) = gtemp(jj);
-                end
-                YrA(:,O{jo}(:)) = Ytemp;
-                C(O{jo}(:),:) = Ctemp;
-                S(O{jo}(:),:) = Stemp;
-                
-                if strcmpi(method,'MCMC');
-                    P.samples_mcmc(O{jo}) = samples_mcmc; % FN added, a useful parameter to have.
-                end                
-            end
-        end
-        fprintf('%i out of %i components updated \n',sum(lo(1:jo)),K);
-    end
-    ii = K + 1;
-    YrA(:,ii) = YrA(:,ii) + nA(ii)*Cin(ii,:)';
-    cc = max(YrA(:,ii)/nA(ii),0);
-    C(ii,:) = full(cc');
-    YrA(:,ii) = YrA(:,ii) - nA(ii)*C(ii,:)';
-%     if mod(jj,10) == 0
-%         fprintf('%i out of total %i temporal components updated \n',jj,K);
-%     end
-    %disp(norm(Fin(1:nr,:) - F,'fro')/norm(F,'fro'));
-    if norm(Cin - C,'fro')/norm(C,'fro') <= 1e-3
-        % stop if the overall temporal component does not change by much
-        break;
-    else
-        Cin = C;
-    end
-end
+if ~isempty(options); options.temporal_parallel = 1; end
 
-f = C(K+1:end,:);
-C = C(1:K,:);
+[C,f,P,S] = update_temporal_components(Y,A,b,Cin,fin,P,options);
\ No newline at end of file