Borehole NMR processing
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

decay.py 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. import numpy, array #,rpy2
  2. from matplotlib import pyplot as plt
  3. import numpy as np
  4. from scipy.optimize import least_squares
  5. from rpy2.robjects.packages import importr
  6. import rpy2.robjects as robjects
  7. import rpy2.robjects.numpy2ri
  8. #import notch
  9. from numpy.fft import fft, fftfreq
  10. # We know/can calculate frequency peak, use this to guess where picks will be.
  11. # maybe have a sliding window that reports peak values.
  12. def peakPicker(data, omega, dt):
  13. # compute window based on omega and dt
  14. # make sure you are not aliased, grab every other peak
  15. window = (2*numpy.pi) / (omega*dt)
  16. data = numpy.array(data)
  17. peaks = []
  18. troughs = []
  19. times = []
  20. times2 = []
  21. indices = []
  22. ws = 0
  23. we = window
  24. ii = 0
  25. for i in range((int)(len(data)/window)):
  26. # initially was just returning this I think avg is better
  27. #times.append( (ws + numpy.abs(data[ws:we]).argmax()) * dt )
  28. peaks.append(numpy.max(data[ws:we]))
  29. times.append( (ws + data[ws:we].argmax()) * dt )
  30. indices.append( ii + data[ws:we].argmax() )
  31. troughs.append(numpy.min(data[ws:we]))
  32. times2.append( (ws + (data[ws:we]).argmin()) * dt )
  33. indices.append( ii + data[ws:we].argmin() )
  34. ws += window
  35. we += window
  36. ii += (int)(we-ws)
  37. #return numpy.array(peaks), numpy.array(times)
  38. # Averaging peaks does a good job of removing bias in noise
  39. return (numpy.array(peaks)-numpy.array(troughs))/2., \
  40. (numpy.array(times)+numpy.array(times2))/2., \
  41. indices
  42. #################################################
  43. # Regress for T2 using rpy2 interface
  44. def regressCurve(peaks,times,sigma2=1,intercept=True):
  45. # TODO, if regression fails, it might be because there is no exponential
  46. # term, maybe do a second regression then on a linear model.
  47. b1 = 0 # Bias
  48. b2 = 0 # Linear
  49. rT2 = 0.3 # T2 regressed
  50. r = robjects.r
  51. # Variable shared between R and Python
  52. robjects.globalenv['b1'] = b1
  53. robjects.globalenv['b2'] = b2
  54. robjects.globalenv['rT2'] = rT2
  55. robjects.globalenv['sigma2'] = sigma2
  56. value = robjects.FloatVector(peaks)
  57. times = robjects.FloatVector(numpy.array(times))
  58. # my_weights = robjects.RVector(value/sigma2)
  59. # robjects.globalenv['my_weigts'] = my_weights
  60. # if sigma2 != 0:
  61. # print "weighting"
  62. # tw = numpy.array(peaks)/sigma2
  63. # my_weights = robjects.RVector( tw/numpy.max(tw) )
  64. # else:
  65. # my_weights = robjects.RVector(numpy.ones(len(peaks)))
  66. # robjects.globalenv['my_weights'] = my_weights
  67. if (intercept):
  68. my_list = robjects.r('list(b1=50, b2=1e2, rT2=0.03)')
  69. my_lower = robjects.r('list(b1=0, b2=0, rT2=.005)')
  70. my_upper = robjects.r('list(b1=20000, b2=2000, rT2=.700)')
  71. else:
  72. my_list = robjects.r('list(b2=1e2, rT2=0.3)')
  73. my_lower = robjects.r('list(b2=0, rT2=.005)')
  74. my_upper = robjects.r('list(b2=2000, rT2=.700)')
  75. my_cont = robjects.r('nls.control(maxiter=1000, warnOnly=TRUE, printEval=FALSE)')
  76. if (intercept):
  77. #fmla = robjects.RFormula('value ~ b1 + exp(-times/rT2)')
  78. fmla = robjects.Formula('value ~ b1 + b2*exp(-times/rT2)')
  79. #fmla = robjects.RFormula('value ~ b1 + b2*times + exp(-times/rT2)')
  80. else:
  81. fmla = robjects.Formula('value ~ b2*exp(-times/rT2)')
  82. env = fmla.getenvironment()
  83. env['value'] = value
  84. env['times'] = times
  85. # ugly, but I get errors with everything else I've tried
  86. my_weights = robjects.r('rep(1,length(value))')
  87. for ii in range(len(my_weights)):
  88. my_weights[ii] *= peaks[ii]/sigma2
  89. Error = False
  90. #fit = robjects.r.nls(fmla,start=my_list,control=my_cont,weights=my_weights)
  91. if (sigma2 != 1):
  92. print("SIGMA 2")
  93. #fit = robjects.r.tryCatch(robjects.r.suppressWarnings(robjects.r.nls(fmla,start=my_list,control=my_cont,algorithm="port", \
  94. # weights=my_weights)), 'silent=TRUE')
  95. fit = robjects.r.tryCatch(robjects.r.nls(fmla,start=my_list,control=my_cont))#, \
  96. # weights=my_weights))
  97. else:
  98. try:
  99. fit = robjects.r.tryCatch(robjects.r.nls(fmla,start=my_list,control=my_cont,algorithm="port"))#,lower=my_lower,upper=my_upper))
  100. except:
  101. print("regression issue pass")
  102. Error = True
  103. # If failure fall back on zero regression values
  104. if not Error:
  105. #Error = fit[3][0]
  106. report = r.summary(fit)
  107. b1 = 0
  108. b2 = 0
  109. rT2 = 1
  110. if (intercept):
  111. if not Error:
  112. b1 = r['$'](report,'par')[0]
  113. b2 = r['$'](report,'par')[1]
  114. rT2 = r['$'](report,'par')[2]
  115. #print report
  116. #print r['$'](report,'convergence')
  117. #print r['convergence'] #(report,'convergence')
  118. #print r['$'](report,'par')[13]
  119. #print r['$'](report,'par')[14]
  120. else:
  121. print("ERROR DETECTED, regressed values set to default")
  122. b1 = 1e1
  123. b2 = 1e-2
  124. rT2 = 1e-2
  125. #print r['$'](report,'par')[0]
  126. #print r['$'](report,'par')[1]
  127. #print r['$'](report,'par')[2]
  128. return [b1,b2,rT2]
  129. else:
  130. if not Error:
  131. rT2 = r['$'](report,'par')[1]
  132. b2 = r['$'](report,'par')[0]
  133. else:
  134. print("ERROR DETECTED, regressed values set to default")
  135. return [b2, rT2]
  136. #################################################
  137. # Regress for T2 using rpy2 interface
  138. def regressCurve2(peaks,times,sigma2=[None],intercept=True):
  139. if sigma2[0] != None:
  140. my_weights = robjects.FloatVector( sigma2 )
  141. # TODO, if regression fails, it might be because there is no exponential
  142. # term, maybe do a second regression then on a linear model.
  143. b1 = 0 # Bias
  144. b2 = 0 # Linear
  145. bb2 = 0 # Linear
  146. rT2 = 0.3 # T2 regressed
  147. rrT2 = 1.3 # T2 regressed
  148. r = robjects.r
  149. # Variable shared between R and Python
  150. robjects.globalenv['b1'] = b1
  151. robjects.globalenv['b2'] = b2
  152. robjects.globalenv['rT2'] = rT2
  153. robjects.globalenv['bb2'] = b2
  154. robjects.globalenv['rrT2'] = rT2
  155. #robjects.globalenv['sigma2'] = sigma2
  156. value = robjects.FloatVector(peaks)
  157. times = robjects.FloatVector(numpy.array(times))
  158. if (intercept):
  159. my_list = robjects.r('list(b1=.50, b2=1e2, rT2=0.03, bb2=1e1, rrT2=1.3)')
  160. my_lower = robjects.r('list(b1=0, b2=0, rT2=.005, bb2=0, rrT2=.005 )')
  161. my_upper = robjects.r('list(b1=2000, b2=2000, rT2=.700, bb2=2000, rrT2=1.3 )')
  162. else:
  163. my_list = robjects.r('list(b2=.5, rT2=0.3, bb2=.5, rrT2=1.3)')
  164. my_lower = robjects.r('list(b2=0, rT2=.005, bb2=0, rrT2=.005)')
  165. my_upper = robjects.r('list(b2=1, rT2=2.6, bb2=1, rrT2=2.6)')
  166. my_cont = robjects.r('nls.control(maxiter=1000, warnOnly=TRUE, printEval=FALSE)')
  167. if (intercept):
  168. #fmla = robjects.RFormula('value ~ b1 + exp(-times/rT2)')
  169. fmla = robjects.Formula('value ~ b1 + b2*exp(-times/rT2) + bb2*exp(-times/rrT2)')
  170. #fmla = robjects.RFormula('value ~ b1 + b2*times + exp(-times/rT2)')
  171. else:
  172. fmla = robjects.Formula('value ~ b2*exp(-times/rT2) + bb2*exp(-times/rrT2)')
  173. env = fmla.getenvironment()
  174. env['value'] = value
  175. env['times'] = times
  176. # ugly, but I get errors with everything else I've tried
  177. Error = False
  178. #fit = robjects.r.nls(fmla,start=my_list,control=my_cont,weights=my_weights)
  179. if (sigma2[0] != None):
  180. #print("SIGMA 2")
  181. #fit = robjects.r.tryCatch(robjects.r.suppressWarnings(robjects.r.nls(fmla,start=my_list,control=my_cont,algorithm="port", \
  182. # weights=my_weights)), 'silent=TRUE')
  183. fit = robjects.r.tryCatch(robjects.r.nls(fmla,start=my_list,control=my_cont,algorithm='port',weights=my_weights,lower=my_lower,upper=my_upper))#, \
  184. # weights=my_weights))
  185. else:
  186. try:
  187. fit = robjects.r.tryCatch(robjects.r.nls(fmla,start=my_list,control=my_cont,algorithm="port"))#,lower=my_lower,upper=my_upper))
  188. except:
  189. print("regression issue pass")
  190. Error = True
  191. # If failure fall back on zero regression values
  192. if not Error:
  193. #Error = fit[3][0]
  194. report = r.summary(fit)
  195. b1 = 0
  196. b2 = 0
  197. rT2 = 1
  198. if (intercept):
  199. if not Error:
  200. b1 = r['$'](report,'par')[0]
  201. b2 = r['$'](report,'par')[1]
  202. rT2 = r['$'](report,'par')[2]
  203. #print report
  204. #print r['$'](report,'convergence')
  205. #print r['convergence'] #(report,'convergence')
  206. #print r['$'](report,'par')[13]
  207. #print r['$'](report,'par')[14]
  208. else:
  209. print("ERROR DETECTED, regressed values set to default")
  210. b1 = 1e1
  211. b2 = 1e-2
  212. rT2 = 1e-2
  213. #print r['$'](report,'par')[0]
  214. #print r['$'](report,'par')[1]
  215. #print r['$'](report,'par')[2]
  216. return [b1,b2,rT2, bb2, rrT2]
  217. else:
  218. if not Error:
  219. rT2 = r['$'](report,'par')[1]
  220. b2 = r['$'](report,'par')[0]
  221. rrT2 = r['$'](report,'par')[3]
  222. bb2 = r['$'](report,'par')[2]
  223. else:
  224. print("ERROR DETECTED, regressed values set to default")
  225. return [b2, rT2, bb2, rrT2]
  226. def fun(x, t, y):
  227. """ Cost function for regression, single exponential, no DC term
  228. x[0] = A0
  229. x[1] = zeta
  230. x[2] = df
  231. x[3] = T2
  232. """
  233. # concatenated real and imaginary parts
  234. pre = np.concatenate((x[0]*np.cos(2.*np.pi*x[2]*t + x[1])*np.exp(-t/x[3]), \
  235. -1.*x[0]*np.sin(2.*np.pi*x[2]*t + x[1])*np.exp(-t/x[3])))
  236. return y-pre
  237. def fun2(x, t, y):
  238. """ Cost function for regression, single exponential, no DC term
  239. x[0] = A0
  240. x[1] = zeta
  241. x[2] = T2
  242. """
  243. # concatenated real and imaginary parts
  244. pre = np.concatenate((x[0]*np.cos(x[1])*np.exp(-t/x[2]), \
  245. -1.*x[0]*np.sin(x[1])*np.exp(-t/x[2])))
  246. return y-pre
  247. def quadratureDetect2(X, Y, tt):
  248. """ Pure python quadrature detection using Scipy.
  249. X = real part of NMR signal
  250. Y = imaginary component of NMR signal
  251. tt = time
  252. """
  253. # df
  254. x = np.array( [1., 0., 0., .2] )
  255. res_lsq = least_squares(fun, x, args=(tt, np.concatenate((X, Y))), loss='soft_l1', f_scale=0.1,\
  256. bounds=( [0., -np.pi, -10, .0] , [1., np.pi, 10, .6] ))
  257. x = res_lsq.x
  258. return res_lsq.success, x[0], x[2], x[1], x[3]
  259. # no df
  260. #x = np.array( [1., 0., 0.2] )
  261. #res_lsq = least_squares(fun2, x, args=(tt, np.concatenate((X, Y))), loss='soft_l1', f_scale=0.1)
  262. #x = res_lsq.x
  263. #return conv, E0,df,phi,T2
  264. #return res_lsq.success, x[0], 0, x[1], x[2]
  265. def quadratureDetect(X, Y, tt, CorrectFreq=False, BiExp=False, CorrectDC=False):
  266. r = robjects.r
  267. if CorrectDC:
  268. robjects.r('''
  269. Xc1 <- function(E01, df, tt, phi, T2_1, DC) {
  270. DC + E01*cos(2*pi*df*tt + phi) * exp(-tt/T2_1)
  271. }
  272. Yc1 <- function(E01, df, tt, phi, T2_1, DC) {
  273. DC - E01*sin(2*pi*df*tt + phi) * exp(-tt/T2_1)
  274. }
  275. ''')
  276. else:
  277. robjects.r('''
  278. Xc1 <- function(E01, df, tt, phi, T2_1) {
  279. E01*cos(2*pi*df*tt + phi) * exp(-tt/T2_1)
  280. }
  281. Yc1 <- function(E01, df, tt, phi, T2_1) {
  282. -E01*sin(2*pi*df*tt + phi) * exp(-tt/T2_1)
  283. }
  284. ''')
  285. # bi-exponential
  286. if CorrectDC:
  287. robjects.r('''
  288. Xc2 <- function(E01, E02, df, tt, phi, T2_1, T2_2, DC) {
  289. DC + E01*cos(2*pi*df*tt + phi) * exp(-tt/T2_1) +
  290. DC + E02*cos(2*pi*df*tt + phi) * exp(-tt/T2_2)
  291. }
  292. Yc2 <- function(E01, E02, df, tt, phi, T2_1, T2_2, DC) {
  293. DC - E01*sin(2*pi*df*tt + phi) * exp(-tt/T2_1) +
  294. DC - E02*sin(2*pi*df*tt + phi) * exp(-tt/T2_2)
  295. }
  296. ''')
  297. else:
  298. robjects.r('''
  299. Xc2 <- function(E01, E02, df, tt, phi, T2_1, T2_2) {
  300. E01*cos(2*pi*df*tt + phi) * exp(-tt/T2_1) +
  301. E02*cos(2*pi*df*tt + phi) * exp(-tt/T2_2)
  302. }
  303. Yc2 <- function(E01, E02, df, tt, phi, T2_1, T2_2) {
  304. -E01*sin(2*pi*df*tt + phi) * exp(-tt/T2_1) +
  305. -E02*sin(2*pi*df*tt + phi) * exp(-tt/T2_2)
  306. }
  307. ''')
  308. # Make 0 vector
  309. Zero = robjects.FloatVector(numpy.zeros(len(X)))
  310. # Fitted Parameters
  311. E01 = 0.
  312. E02 = 0.
  313. df = 0.
  314. phi = 0.
  315. T2_1 = 0.
  316. T2_2 = 0.
  317. DC = 0.
  318. robjects.globalenv['DC'] = DC
  319. robjects.globalenv['E01'] = E01
  320. robjects.globalenv['E02'] = E02
  321. robjects.globalenv['df'] = df
  322. robjects.globalenv['phi'] = phi
  323. robjects.globalenv['T2_1'] = T2_1
  324. robjects.globalenv['T2_2'] = T2_2
  325. XY = robjects.FloatVector(numpy.concatenate((X,Y)))
  326. # Arrays
  327. tt = robjects.FloatVector(numpy.array(tt))
  328. X = robjects.FloatVector(numpy.array(X))
  329. Y = robjects.FloatVector(numpy.array(Y))
  330. Zero = robjects.FloatVector(numpy.array(Zero))
  331. if BiExp:
  332. if CorrectDC:
  333. fmla = robjects.Formula('XY ~ c(Xc2( E01, E02, df, tt, phi, T2_1, T2_2, DC ), Yc2( E01, E02, df, tt, phi, T2_1, T2_2, DC ))')
  334. if CorrectFreq:
  335. start = robjects.r('list(E01=.100, E02=.01, df=0, phi=0. , T2_1=.100, T2_2=.01, DC=0.0)')
  336. lower = robjects.r('list(E01=1e-6, E02=1e-6, df=-50, phi=-3.14 , T2_1=.001, T2_2=.001, DC=0.0)')
  337. upper = robjects.r('list(E01=1.00, E02=1.0, df=50, phi=3.14 , T2_1=.800, T2_2=.8, DC=0.5)')
  338. else:
  339. start = robjects.r('list(E01=.100, E02=.01, phi=0.9 , T2_1=.100, T2_2=.01, DC=0.0)')
  340. lower = robjects.r('list(E01=1e-6, E02=1e-6, phi=-3.14 , T2_1=.001, T2_2=.001, DC=0.0)')
  341. upper = robjects.r('list(E01=1.00, E02=1.0, phi=3.14 , T2_1=.800, T2_2=.8, DC=0.5)')
  342. else:
  343. fmla = robjects.Formula('XY ~ c(Xc2( E01, E02, df, tt, phi, T2_1, T2_2 ), Yc2( E01, E02, df, tt, phi, T2_1, T2_2))')
  344. if CorrectFreq:
  345. start = robjects.r('list(E01=.100, E02=.01, df=0, phi=0. , T2_1=.100, T2_2=.01)')
  346. lower = robjects.r('list(E01=1e-6, E02=1e-6, df=-50, phi=-3.14 , T2_1=.001, T2_2=.001)')
  347. upper = robjects.r('list(E01=1.00, E02=1.0, df=50, phi=3.14 , T2_1=.800, T2_2=.8)')
  348. else:
  349. start = robjects.r('list(E01=.100, E02=.01, phi=0.9 , T2_1=.100, T2_2=.01)')
  350. lower = robjects.r('list(E01=1e-6, E02=1e-6, phi=-3.14 , T2_1=.001, T2_2=.001)')
  351. upper = robjects.r('list(E01=1.00, E02=1.0, phi=3.14 , T2_1=.800, T2_2=.8)')
  352. else:
  353. if CorrectDC:
  354. fmla = robjects.Formula('XY ~ c(Xc1( E01, df, tt, phi, T2_1, DC), Yc1( E01, df, tt, phi, T2_1,DC))')
  355. if CorrectFreq:
  356. start = robjects.r('list(E01=.100, df=0 , phi=0. , T2_1=.100, DC=0.0)')
  357. lower = robjects.r('list(E01=1e-6, df=-50., phi=-3.14, T2_1=.001, DC=0.0)')
  358. upper = robjects.r('list(E01=1.00, df=50. , phi=3.14 , T2_1=.800, DC=0.5)')
  359. else:
  360. start = robjects.r('list(E01=.100, phi= 0. , T2_1=.100, DC=0.0)')
  361. lower = robjects.r('list(E01=1e-6, phi=-3.13, T2_1=.001, DC=0.0)')
  362. upper = robjects.r('list(E01=1.00, phi= 3.13, T2_1=.800, DC=0.5)')
  363. else:
  364. fmla = robjects.Formula('XY ~ c(Xc1( E01, df, tt, phi, T2_1), Yc1( E01, df, tt, phi, T2_1))')
  365. if CorrectFreq:
  366. start = robjects.r('list(E01=.100, df=0 , phi=0. , T2_1=.100)')
  367. lower = robjects.r('list(E01=1e-6, df=-50. , phi=-3.14 , T2_1=.001)')
  368. upper = robjects.r('list(E01=1.00, df=50. , phi=3.14 , T2_1=.800)')
  369. else:
  370. start = robjects.r('list(E01=.100, phi= 0. , T2_1=.100)')
  371. lower = robjects.r('list(E01=1e-6, phi=-3.13, T2_1=.001)')
  372. upper = robjects.r('list(E01=1.00, phi= 3.13, T2_1=.800)')
  373. env = fmla.getenvironment()
  374. env['Zero'] = Zero
  375. env['X'] = X
  376. env['Y'] = Y
  377. env['XY'] = XY
  378. env['tt'] = tt
  379. cont = robjects.r('nls.control(maxiter=10000, warnOnly=TRUE, printEval=FALSE)')
  380. fit = robjects.r.tryCatch(robjects.r.nls(fmla, start=start, control=cont, lower=lower, upper=upper, algorithm='port')) #, \
  381. #fit = robjects.r.tryCatch(robjects.r.nls(fmla, start=start, control=cont)) #, \
  382. report = r.summary(fit)
  383. conv = r['$'](fit,'convergence')[0]
  384. #if conv:
  385. # print (report)
  386. # print ("conv", conv)
  387. print ("Conv", r['$'](fit,'convergence')) # T2
  388. print (report)
  389. if BiExp:
  390. if CorrectFreq:
  391. E0 = r['$'](report,'par')[0] # E01
  392. E0 += r['$'](report,'par')[1] # E02
  393. df = r['$'](report,'par')[2] # offset
  394. phi = r['$'](report,'par')[3] # phase
  395. T2 = r['$'](report,'par')[4] # T2
  396. else:
  397. E0 = r['$'](report,'par')[0] # E01
  398. E0 += r['$'](report,'par')[1] # E02
  399. phi = r['$'](report,'par')[2] # phase
  400. T2 = r['$'](report,'par')[3] # T2
  401. else:
  402. if CorrectFreq:
  403. E0 = r['$'](report,'par')[0] # E01
  404. df = r['$'](report,'par')[1] # offset
  405. phi = r['$'](report,'par')[2] # phase
  406. T2 = r['$'](report,'par')[3] # T2
  407. else:
  408. E0 = r['$'](report,'par')[0] # E01
  409. phi = r['$'](report,'par')[1] # phase
  410. T2 = r['$'](report,'par')[2] # T2
  411. #phi = 0.907655876627
  412. #df = 0.
  413. #phi = 0
  414. print ("df", df)# = 0
  415. return conv, E0,df,phi,T2
  416. #################################################
  417. # Regress for T2 using rpy2 interface
  418. def regressSpec(w, wL, X): #,sigma2=1,intercept=True):
  419. # compute s
  420. s = -1j*w
  421. # TODO, if regression fails, it might be because there is no exponential
  422. # term, maybe do a second regression then on a linear model.
  423. a = 0 # Linear
  424. rT2 = 0.1 # T2 regressed
  425. r = robjects.r
  426. # Variable shared between R and Python
  427. robjects.globalenv['a'] = a
  428. robjects.globalenv['rT2'] = rT2
  429. robjects.globalenv['wL'] = wL
  430. robjects.globalenv['nb'] = 0
  431. s = robjects.ComplexVector(numpy.array(s))
  432. XX = robjects.ComplexVector(X)
  433. Xr = robjects.FloatVector(numpy.real(X))
  434. Xi = robjects.FloatVector(numpy.imag(X))
  435. Xa = robjects.FloatVector(numpy.abs(X))
  436. Xri = robjects.FloatVector(numpy.concatenate((Xr,Xi)))
  437. #my_lower = robjects.r('list(a=.001, rT2=.001, nb=.0001)')
  438. my_lower = robjects.r('list(a=.001, rT2=.001)')
  439. #my_upper = robjects.r('list(a=1.5, rT2=.300, nb =100.)')
  440. my_upper = robjects.r('list(a=1.5, rT2=.300)')
  441. #my_list = robjects.r('list(a=.2, rT2=0.03, nb=.1)')
  442. my_list = robjects.r('list(a=.2, rT2=0.03)')
  443. my_cont = robjects.r('nls.control(maxiter=5000, warnOnly=TRUE, printEval=FALSE)')
  444. #fmla = robjects.Formula('Xri ~ c(a*Re((wL) / (wL^2+(s+1/rT2)^2 )), a*Im((wL)/(wL^2 + (s+1/rT2)^2 )))') # envelope
  445. ##fmla = robjects.Formula('Xri ~ c(a*Re((wL) / (wL^2+(s+1/rT2)^2 )), a*Im((wL)/(wL^2 + (s+1/rT2)^2 )))') # envelope
  446. #fmla = robjects.Formula('XX ~ a*(wL) / (wL^2 + (s+1/rT2)^2 )') # complex
  447. #fmla = robjects.Formula('Xa ~ abs(a*(wL) / (wL^2 + (s+1/rT2)^2 )) + nb') # complex
  448. fmla = robjects.Formula('Xa ~ abs(a*(wL) / (wL^2 + (s+1/rT2)^2 ))') # complex
  449. env = fmla.getenvironment()
  450. env['s'] = s
  451. env['Xr'] = Xr
  452. env['Xa'] = Xa
  453. env['Xi'] = Xi
  454. env['Xri'] = Xri
  455. env['XX'] = XX
  456. #fit = robjects.r.tryCatch(robjects.r.nls(fmla,start=my_list, control=my_cont)) #, lower=my_lower, algorithm='port')) #, \
  457. fit = robjects.r.tryCatch(robjects.r.nls(fmla, start=my_list, control=my_cont, lower=my_lower, upper=my_upper, algorithm='port')) #, \
  458. report = r.summary(fit)
  459. #print report
  460. #print r.warnings()
  461. a = r['$'](report,'par')[0]
  462. rT2 = r['$'](report,'par')[1]
  463. nb = r['$'](report,'par')[2]
  464. return a, rT2, nb
  465. #################################################
  466. # Regress for T2 using rpy2 interface
  467. def regressSpecComplex(w, wL, X): #,sigma2=1,intercept=True):
  468. # compute s
  469. s = -1j*w
  470. # TODO, if regression fails, it might be because there is no exponential
  471. # term, maybe do a second regression then on a linear model.
  472. a = 1 # Linear
  473. rT2 = 0.1 # T2 regressed
  474. r = robjects.r
  475. phi2 = 0 # phase
  476. wL2 = wL
  477. # Variable shared between R and Python
  478. robjects.globalenv['a'] = a
  479. robjects.globalenv['rT2'] = rT2
  480. robjects.globalenv['wL'] = wL
  481. robjects.globalenv['wL2'] = 0
  482. robjects.globalenv['nb'] = 0
  483. robjects.globalenv['phi2'] = phi2
  484. s = robjects.ComplexVector(numpy.array(s))
  485. XX = robjects.ComplexVector(X)
  486. Xr = robjects.FloatVector(numpy.real(X))
  487. Xi = robjects.FloatVector(numpy.imag(X))
  488. Xa = robjects.FloatVector(numpy.abs(X))
  489. Xri = robjects.FloatVector(numpy.concatenate((X.real,X.imag)))
  490. robjects.r('''
  491. source('kernel.r')
  492. ''')
  493. #Kw = robjects.globalenv['Kwri']
  494. #print (numpy.shape(X))
  495. #my_lower = robjects.r('list(a=.001, rT2=.001, nb=.0001)')
  496. #my_lower = robjects.r('list(a=.001, rT2=.001)') # Working
  497. my_lower = robjects.r('list(a=.001, rT2=.001, phi2=-3.14, wL2=wL-5)')
  498. #my_upper = robjects.r('list(a=1.5, rT2=.300, nb =100.)')
  499. my_upper = robjects.r('list(a=3.5, rT2=.300, phi2=3.14, wL2=wL+5)')
  500. #my_list = robjects.r('list(a=.2, rT2=0.03, nb=.1)')
  501. my_list = robjects.r('list(a=.2, rT2=0.03, phi2=0, wL2=wL)')
  502. my_cont = robjects.r('nls.control(maxiter=5000, warnOnly=TRUE, printEval=FALSE)')
  503. #fmla = robjects.Formula('Xri ~ c(a*Re((wL) / (wL^2+(s+1/rT2)^2 )), a*Im((wL)/(wL^2 + (s+1/rT2)^2 )))') # envelope
  504. #fmla = robjects.Formula('Xi ~ Im(a*(sin(phi2)*s + ((1/rT2)*sin(phi2)) + wL*cos(phi2)) / (wL^2+(s+1/rT2)^2 ))') # envelope
  505. #fmla = robjects.Formula('Xri ~ c(Re(a*(sin(phi2)*s + ((1/rT2)*sin(phi2)) + wL*cos(phi2)) / (wL^2+(s+1/rT2)^2 )), Im(a*(sin(phi2)*s + ((1/rT2)*sin(phi2)) + wL*cos(phi2)) / (wL^2+(s+1/rT2)^2 )))') # envelope
  506. #fmlar = robjects.Formula('Xr ~ (Kwr(a, phi2, s, rT2, wL)) ') # envelope
  507. #fmlai = robjects.Formula('Xi ~ (Kwi(a, phi2, s, rT2, wL)) ') # envelope
  508. fmla = robjects.Formula('Xri ~ c(Kwr(a, phi2, s, rT2, wL2), Kwi(a, phi2, s, rT2, wL2) ) ') # envelope
  509. #fmla = robjects.Formula('Xri ~ (Kwri(a, phi2, s, rT2, wL)) ') # envelope
  510. #fmla = robjects.Formula('Xa ~ (abs(a*(sin(phi2)*s + ((1/rT2)*sin(phi2)) + wL*cos(phi2)) / (wL^2+(s+1/rT2)^2 )))') # envelope
  511. #fmla = robjects.Formula('XX ~ a*(wL) / (wL^2 + (s+1/rT2)^2 )') # complex
  512. #fmla = robjects.Formula('Xa ~ abs(a*(wL) / (wL^2 + (s+1/rT2)^2 )) + nb') # complex
  513. #fmla = robjects.Formula('Xri ~ c(a*Re((wL) / (wL^2+(s+1/rT2)^2 )), a*Im((wL)/(wL^2 + (s+1/rT2)^2 )))') # envelope
  514. # self.Gw[iw, iT2] = ((np.sin(phi2) * (alpha + 1j*self.w[iw]) + self.wL*np.cos(phi2)) / \
  515. # (self.wL**2 + (alpha+1.j*self.w[iw])**2 ))
  516. # self.Gw[iw, iT2] = ds * self.sc*((np.sin(phi2)*( alpha + 1j*self.w[iw]) + self.wL*np.cos(phi2)) / \
  517. # (self.wL**2 + (alpha+1.j*self.w[iw])**2 ))
  518. # Works Amplitude Only!
  519. #fmla = robjects.Formula('Xa ~ abs(a*(wL) / (wL^2 + (s+1/rT2)^2 ))') # complex
  520. env = fmla.getenvironment()
  521. env['s'] = s
  522. env['Xr'] = Xr
  523. env['Xa'] = Xa
  524. env['Xi'] = Xi
  525. env['Xri'] = Xri
  526. env['XX'] = XX
  527. fit = robjects.r.tryCatch(robjects.r.nls(fmla,start=my_list, control=my_cont)) #, lower=my_lower, algorithm='port')) #, \
  528. #fitr = robjects.r.tryCatch(robjects.r.nls(fmlar, start=my_list, control=my_cont, lower=my_lower, upper=my_upper, algorithm='port')) #, \
  529. #env = fmlai.getenvironment()
  530. #fiti = robjects.r.tryCatch(robjects.r.nls(fmlai, start=my_list, control=my_cont, lower=my_lower, upper=my_upper, algorithm='port')) #, \
  531. #reportr = r.summary(fitr)
  532. #reporti = r.summary(fiti)
  533. report = r.summary(fit)
  534. #print( report )
  535. #exit()
  536. #print( reportr )
  537. #print( reporti )
  538. #exit()
  539. #print r.warnings()
  540. #a = (r['$'](reportr,'par')[0] + r['$'](reporti,'par')[0]) / 2.
  541. #rT2 = (r['$'](reportr,'par')[1] + r['$'](reporti,'par')[1]) / 2.
  542. #nb = (r['$'](reportr,'par')[2] + r['$'](reporti,'par')[2]) / 2.
  543. a = r['$'](report,'par')[0]
  544. rT2 = r['$'](report,'par')[1]
  545. nb = r['$'](report,'par')[2] #phi2
  546. print ("Python wL2", r['$'](report,'par')[3] )
  547. print ("Python zeta", r['$'](report,'par')[2] )
  548. return a, rT2, nb
  549. ###################################################################
  550. ###################################################################
  551. ###################################################################
  552. if __name__ == "__main__":
  553. dt = .0001
  554. T2 = .1
  555. omega = 2000.*2*numpy.pi
  556. phi = .0
  557. T = 8.*T2
  558. t = numpy.arange(0, T, dt)
  559. # Synthetic data, simple single decaying sinusoid
  560. # with a single decay parameter and gaussian noise added
  561. data = numpy.exp(-t/T2) * numpy.sin(omega * t + phi) + numpy.random.normal(0,.05,len(t)) \
  562. + numpy.random.randint(-1,2,len(t))*numpy.random.exponential(.2,len(t))
  563. cdata = numpy.exp(-t/T2) * numpy.sin(omega * t + phi) #+ numpy.random.normal(0,.25,len(t))
  564. #data = numpy.random.normal(0,.25,len(t))
  565. sigma2 = numpy.std(data[::-len(data)/4])
  566. #sigma2 = numpy.var(data[::-len(data)/4])
  567. print("sigma2", sigma2)
  568. [peaks,times,indices] = peakPicker(data, omega, dt)
  569. [b1,b2,rT2] = regressCurve(peaks,times)
  570. print("rT2 nonweighted", rT2)
  571. [b1,b2,rT2] = regressCurve(peaks,times,sigma2)
  572. print("rT2 weighted", rT2)
  573. envelope = numpy.exp(-t/T2)
  574. renvelope = numpy.exp(-t/rT2)
  575. #outf = file('regress.txt','w')
  576. #for i in range(len(times)):
  577. # outf.write(str(times[i]) + " " + str(peaks[i]) + "\n")
  578. #outf.close()
  579. plt.plot(t,data, 'b')
  580. plt.plot(t,cdata, 'g', linewidth=1)
  581. plt.plot(t,envelope, color='violet', linewidth=4)
  582. plt.plot(t,renvelope, 'r', linewidth=4)
  583. plt.plot(times, numpy.array(peaks), 'bo', markersize=8, alpha=.25)
  584. plt.legend(['noisy data','clean data','real envelope','regressed env','picks'])
  585. plt.savefig("regression.pdf")
  586. # FFT check
  587. fourier = fft(data)
  588. plt.figure()
  589. freq = fftfreq(len(data), d=dt)
  590. plt.plot(freq, (fourier.real))
  591. plt.show()
  592. # TODO do a bunch in batch mode to see if T2 estimate is better with or without
  593. # weighting and which model is best.
  594. # TODO try with real data
  595. # TODO test filters (median, FFT, notch)
  596. # It looks like weighting is good for relatively low sigma, but for noisy data
  597. # it hurts us. Check