|
| 1 | +''' |
| 2 | +This script is used to test Current Source Density Estimates, |
| 3 | +using the kCSD method Jan et.al (2012) |
| 4 | +
|
| 5 | +This script is in alpha phase. |
| 6 | +
|
| 7 | +This was written by : |
| 8 | +Chaitanya Chintaluri, |
| 9 | +Laboratory of Neuroinformatics, |
| 10 | +Nencki Institute of Exprimental Biology, Warsaw. |
| 11 | +''' |
| 12 | +import os |
| 13 | +import numpy as np |
| 14 | +from scipy.integrate import simps |
| 15 | +import matplotlib.pyplot as plt |
| 16 | +from kcsd import KCSD1D |
| 17 | +from figure_LC import make_plots |
| 18 | +from figure_LCandCVperformance import make_plot_perf |
| 19 | +from figure_LCandCV import plot_surface |
| 20 | + |
| 21 | +def do_kcsd(i, ele_pos, pots, **params): |
| 22 | + """ |
| 23 | + Function that calls the KCSD1D module |
| 24 | + """ |
| 25 | + num_ele = len(ele_pos) |
| 26 | + pots = pots.reshape(num_ele, 1) |
| 27 | + ele_pos = ele_pos.reshape(num_ele, 1) |
| 28 | + k = KCSD1D(ele_pos, pots, **params) |
| 29 | + noreg_csd = k.values('CSD') |
| 30 | + k.cross_validate(Rs=Rs, lambdas=lambdas) |
| 31 | + errsy = k.errs |
| 32 | + LandR[1,0,i] = k.lambd |
| 33 | + LandR[1,1,i] = k.R |
| 34 | + est_csd_cv = k.values('CSD') |
| 35 | + k.L_curve(lambdas=lambdas, Rs=Rs) |
| 36 | + LandR[0,0,i] = k.lambd |
| 37 | + LandR[0,1,i] = k.R |
| 38 | + est_csd = k.values('CSD') |
| 39 | + est_pot = k.values('POT') |
| 40 | + return k, est_csd, est_pot, noreg_csd, errsy, est_csd_cv |
| 41 | + |
| 42 | +def generate_csd_1D(src_width, name, srcs=np.array([0]), |
| 43 | + start_x=0., end_x=1., |
| 44 | + start_y=0., end_y=1., |
| 45 | + res_x=50, res_y=50): |
| 46 | + """ |
| 47 | + Gives CSD profile at the requested spatial location, at 'res' resolution |
| 48 | + """ |
| 49 | + csd_y = np.linspace(start_x, end_x, res_x) |
| 50 | + csd_x = np.linspace(start_x, end_x, res_x) |
| 51 | + src_peak = .7*np.exp(-((csd_x-0.25)**2)/(2.*src_width)) |
| 52 | + src_thr1 = .35*np.exp(-((csd_x-0.45)**2)/(2.*src_width)) |
| 53 | + src_thr2 = .35*np.exp(-((csd_x-0.65)**2)/(2.*src_width)) |
| 54 | + f = src_peak-src_thr1-src_thr2 |
| 55 | + csd_y = np.linspace(start_x, end_x, res_x) |
| 56 | + return csd_x, csd_y, f |
| 57 | + |
| 58 | +def integrate_1D(x0, csd_x, csd, h): |
| 59 | + m = np.sqrt((csd_x-x0)**2 + h**2) - abs(csd_x-x0) |
| 60 | + y = csd * m |
| 61 | + I = simps(y, csd_x) |
| 62 | + return I |
| 63 | + |
| 64 | +def calculate_potential_1D(csd, measure_locations, csd_space_x, h): |
| 65 | + sigma = 1 |
| 66 | + print(measure_locations.shape, csd_space_x.shape, csd.shape) |
| 67 | + pots = np.zeros(len(measure_locations)) |
| 68 | + for ii in range(len(measure_locations)): |
| 69 | + pots[ii] = integrate_1D(measure_locations[ii], csd_space_x, csd, h) |
| 70 | + pots *= 1/(2.*sigma) #eq.: 26 from Potworowski et al |
| 71 | + return pots |
| 72 | + |
| 73 | +def transformAndNormalizeLongGrid(D): |
| 74 | + #D is a dictionary |
| 75 | + locations = np.zeros((len(D), 2)) |
| 76 | + for i in range(len(D)): |
| 77 | + locations[i, 0] = D[i]['x'] |
| 78 | + locations[i, 1] = D[i]['y'] |
| 79 | + return locations |
| 80 | + |
| 81 | +def generate_electrodes(inpos, lpos, b): |
| 82 | + loc = {} |
| 83 | + cordx = -(inpos[0] - lpos[0])/b |
| 84 | + cordy = -(inpos[1] - lpos[1])/b |
| 85 | + def _addLocToDict(D, chnum, x, y): |
| 86 | + d = {} |
| 87 | + d['x'] = x |
| 88 | + d['y'] = y |
| 89 | + D[chnum] = d |
| 90 | + #first add locations just as they suppose to be |
| 91 | + for i in range(b): |
| 92 | + _addLocToDict(loc, i, inpos[0] + cordx*i, inpos[1] + cordy*i) |
| 93 | + loc_mtrx = transformAndNormalizeLongGrid(loc) |
| 94 | + loc_mtrx = loc_mtrx.T |
| 95 | + return loc_mtrx[0], loc_mtrx[1] |
| 96 | + |
| 97 | +def electrode_config(ele_res, true_csd, csd_x, csd_y, inpos, lpos): |
| 98 | + """ |
| 99 | + What is the configuration of electrode positions, between what and what positions |
| 100 | + """ |
| 101 | + ele_x, ele_y = generate_electrodes(inpos, lpos, ele_res) |
| 102 | + pots = calculate_potential_1D(true_csd, ele_y.T, csd_y, h=1) |
| 103 | + ele_pos = np.vstack((ele_x, ele_y)).T #Electrode configs |
| 104 | + return ele_pos, pots |
| 105 | + |
| 106 | +def main_loop(src_width, total_ele, inpos, lpos, nm, noise=0, srcs=1): |
| 107 | + """ |
| 108 | + Loop that decides the random number seed for the CSD profile, |
| 109 | + electrode configurations and etc. |
| 110 | + """ |
| 111 | + #TrueCSD |
| 112 | + t_csd_x, t_csd_y, true_csd = generate_csd_1D(src_width, nm, srcs=srcs, |
| 113 | + start_x=0, end_x=1., |
| 114 | + start_y=0, end_y=1, |
| 115 | + res_x=100, res_y=100) |
| 116 | + if type(noise) == float: n_spec = [noise] |
| 117 | + else: n_spec = noise |
| 118 | + for i, noise in enumerate(n_spec): |
| 119 | + plt.close('all') |
| 120 | + noise = np.round(noise, 5) |
| 121 | + print('numer rekonstrukcji: ', i, 'noise level: ', noise) |
| 122 | + #Electrodes |
| 123 | + ele_pos, pots = electrode_config(total_ele, true_csd, t_csd_x, t_csd_y, inpos, lpos) |
| 124 | + ele_y = ele_pos[:, 1] |
| 125 | + gdX = 0.01 |
| 126 | + x_lims = [0, 1] #CSD estimation place |
| 127 | + np.random.seed(srcs) |
| 128 | + pots_n = pots + (np.random.rand(total_ele)*np.max(abs(pots))-np.max(abs(pots))/2)*noise |
| 129 | + k, est_csd, est_pot, noreg_csd, errsy, est_csd_cv = do_kcsd(i, ele_y, pots_n, h=1., gdx=gdX, sigma = 1, |
| 130 | + xmin=x_lims[0], xmax=x_lims[1], n_src_init=1e3) |
| 131 | + save_as = nm + '_noise' + str(np.round(noise*100, 1)) |
| 132 | + m_norm = k.m_norm |
| 133 | + m_resi = k.m_resi |
| 134 | + curve_surf = k.curve_surf |
| 135 | + title = [str(k.lambd), str(k.R), str(noise), nm] |
| 136 | + if plot: |
| 137 | + make_plots(title, m_norm, m_resi, true_csd, curve_surf, ele_y, pots_n, |
| 138 | + pots, k.estm_x, est_pot, est_csd, noreg_csd, save_as) |
| 139 | + plot_surface(curve_surf, errsy, save_as+'surf') |
| 140 | + vals_to_save = {'m_norm':m_norm, 'm_resi':m_resi, 'true_csd':true_csd, |
| 141 | + 'curve_surf':curve_surf, 'ele_y':ele_y, 'pots_n':pots_n, |
| 142 | + 'pots':pots, 'estm_x':k.estm_x, 'est_pot':est_pot, |
| 143 | + 'est_csd':est_csd, 'noreg_csd':noreg_csd, 'errsy':errsy} |
| 144 | + np.savez('data_fig4_and_fig13_'+save_as, **vals_to_save) |
| 145 | + RMS_wek[0, i] = np.linalg.norm(true_csd/np.linalg.norm(true_csd) - est_csd[:,0]/np.linalg.norm(est_csd[:,0])) |
| 146 | + RMS_wek[1, i] = np.linalg.norm(true_csd/np.linalg.norm(true_csd) - est_csd_cv[:,0]/np.linalg.norm(est_csd_cv[:,0])) |
| 147 | + |
| 148 | +if __name__=='__main__': |
| 149 | + saveDir = "./LCurve/" |
| 150 | + try: |
| 151 | + os.chdir(saveDir) |
| 152 | + except FileNotFoundError: |
| 153 | + os.mkdir(saveDir) |
| 154 | + os.chdir(saveDir) |
| 155 | + plot = False |
| 156 | + total_ele = 32 |
| 157 | + src_width = 0.001 |
| 158 | + noises = 9 |
| 159 | + seeds = 9 |
| 160 | + inpos = [0.5, 0.1]#od dolu |
| 161 | + lpos = [0.5, 0.9] |
| 162 | + noise_lvl = np.linspace(0, 0.5, noises) |
| 163 | + Rs = np.linspace(0.025, 8*0.025, 8) |
| 164 | + lambdas = np.logspace(-7, -3, 50) |
| 165 | + sim_results = np.zeros((2, 4, seeds, noises)) |
| 166 | + sim_results[:, 3] = noise_lvl |
| 167 | + for src in range(seeds): |
| 168 | + print('noise seed:', src) |
| 169 | + RMS_wek = np.zeros((2,len(noise_lvl))) |
| 170 | + LandR = np.zeros((2,2, len(noise_lvl))) |
| 171 | + mypath = 'LC' + str(src) + '/' |
| 172 | + if not os.path.isdir(mypath): os.makedirs(mypath) |
| 173 | + os.chdir(mypath) |
| 174 | + main_loop(src_width, total_ele, inpos, |
| 175 | + lpos, 'LC', noise=noise_lvl, srcs=src) |
| 176 | + sim_results[:,:2, src] = LandR |
| 177 | + sim_results[:, 2, src] = RMS_wek |
| 178 | + os.chdir('..') |
| 179 | + np.save('sim_results', sim_results) |
| 180 | + sim_results = np.load('sim_results.npy') |
| 181 | + make_plot_perf(sim_results) |
| 182 | + |
0 commit comments