mecsolve.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. from math import *
  2. import array
  3. import sys
  4. import random
  5. import numarray as N
  6. import numarray.linear_algebra as la
  7. def eps_prologue(x0, y0, x1, y1, draw_box = False):
  8. print '%!PS-Adobe-3.0 EPSF'
  9. print '%%BoundingBox:', x0, y0, x1, y1
  10. print '%%EndComments'
  11. print '%%EndProlog'
  12. print '%%Page: 1 1'
  13. if draw_box:
  14. print x0, y0, 'moveto', x0, y1, 'lineto', x1, y1, 'lineto', x1, y0, 'lineto closepath stroke'
  15. def eps_trailer():
  16. print '%%EOF'
  17. # One step of 4th-order Runge-Kutta numerical integration - update y in place
  18. def rk4(y, dydx, x, h, derivs):
  19. hh = h * .5
  20. h6 = h * (1./6)
  21. xh = x + hh
  22. yt = []
  23. for i in range(len(y)):
  24. yt.append(y[i] + hh * dydx[i])
  25. dyt = derivs(xh, yt)
  26. for i in range(len(y)):
  27. yt[i] = y[i] + hh * dyt[i]
  28. dym = derivs(xh, yt)
  29. for i in range(len(y)):
  30. yt[i] = y[i] + h * dym[i]
  31. dym[i] += dyt[i]
  32. dyt = derivs(x + h, yt)
  33. for i in range(len(y)):
  34. y[i] += h6 * (dydx[i] + dyt[i] + 2 * dym[i])
  35. def run_elastica_half(sp, k0, lam1, lam2, n):
  36. def mec_derivs(x, ys):
  37. th, k = ys[2], ys[3]
  38. dx, dy = cos(th), sin(th)
  39. return [dx, dy, k, lam1 * dx + lam2 * dy, k * k]
  40. ys = [0, 0, 0, k0, 0]
  41. xyk = [(ys[0], ys[1], ys[3])]
  42. n = max(1, int(sp * n))
  43. h = float(sp) / n
  44. s = 0
  45. for i in range(n):
  46. dydx = mec_derivs(s, ys)
  47. rk4(ys, dydx, s, h, mec_derivs)
  48. xyk.append((ys[0], ys[1], ys[3]))
  49. return xyk, ys[2], ys[4]
  50. def run_elastica(sm, sp, k0, lam1, lam2, n = 100):
  51. xykm, thm, costm = run_elastica_half(-sm, k0, -lam1, lam2, n)
  52. xykp, thp, costp = run_elastica_half(sp, k0, lam1, lam2, n)
  53. xyk = []
  54. for i in range(1, len(xykm)):
  55. x, y, k = xykm[i]
  56. xyk.append((-x, y, k))
  57. xyk.reverse()
  58. xyk.extend(xykp)
  59. x = xyk[-1][0] - xyk[0][0]
  60. y = xyk[-1][1] - xyk[0][1]
  61. th = thm + thp
  62. sth, cth = sin(thm), cos(thm)
  63. x, y = x * cth - y * sth, x * sth + y * cth
  64. result = []
  65. maxk = 0
  66. for xt, yt, kt in xyk:
  67. maxk = max(maxk, kt)
  68. result.append((xt, yt, kt))
  69. cost = costm + costp
  70. return result, cost, x, y, th
  71. def run_mec_cos_pos(k, lam1, lam2, n = 1000):
  72. cost = 0
  73. th = 0
  74. x = 0
  75. y = 0
  76. dt = 1.0 / n
  77. result = [(0, 0)]
  78. for i in range(n):
  79. k1 = lam1 * cos(th) + lam2 * sin(th)
  80. cost += dt * k * k
  81. x += dt * cos(th)
  82. y += dt * sin(th)
  83. th += dt * k
  84. k += dt * k1
  85. result.append((x, y))
  86. return result, cost, x, y, th
  87. def run_mec_cos(k, lam1, lam2, n = 1000):
  88. resp, costp, xp, yp, thp = run_mec_cos_pos(k*.5, lam1*.25, lam2*.25, n)
  89. resm, costm, xm, ym, thm = run_mec_cos_pos(k*.5, lam1*-.25, lam2*.25, n)
  90. cost = (costp + costm) * .5
  91. x, y = xp + xm, yp - ym
  92. th = thp + thm
  93. sth, cth = .5 * sin(thm), .5 * cos(thm)
  94. x, y = x * cth - y * sth, x * sth + y * cth
  95. result = []
  96. for i in range(1, n):
  97. xt, yt = resm[n - i - 1]
  98. result.append((-xt * cth - yt * sth, -xt * sth + yt * cth))
  99. for i in range(n):
  100. xt, yt = resp[i]
  101. result.append((xt * cth - yt * sth, xt * sth + yt * cth))
  102. return result, cost, x, y, th
  103. def cross_prod(a, b):
  104. return [a[1] * b[2] - a[2] * b[1],
  105. a[2] * b[0] - a[0] * b[2],
  106. a[0] * b[1] - a[1] * b[0]]
  107. def solve_mec(constraint_fnl):
  108. delta = 1e-3
  109. params = [pi, 0, 0]
  110. for i in range(20):
  111. k, lam1, lam2 = params
  112. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2)
  113. #print i * .05, 'setgray'
  114. #plot(xys)
  115. c1c, c2c, costc = constraint_fnl(cost, x, y, th)
  116. print '% constraint_fnl =', c1c, c2c, 'cost =', costc
  117. dc1s = []
  118. dc2s = []
  119. for j in range(len(params)):
  120. params1 = N.array(params)
  121. params1[j] += delta
  122. k, lam1, lam2 = params1
  123. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2)
  124. c1p, c2p, costp = constraint_fnl(cost, x, y, th)
  125. params1 = N.array(params)
  126. params1[j] -= delta
  127. k, lam1, lam2 = params1
  128. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2)
  129. c1m, c2m, costm = constraint_fnl(cost, x, y, th)
  130. dc1s.append((c1p - c1m) / (2 * delta))
  131. dc2s.append((c2p - c2m) / (2 * delta))
  132. xp = cross_prod(dc1s, dc2s)
  133. xp = N.divide(xp, sqrt(N.dot(xp, xp))) # Normalize to unit length
  134. print '% dc1s =', dc1s
  135. print '% dc2s =', dc2s
  136. print '% xp =', xp
  137. # Compute second derivative wrt orthogonal vec
  138. params1 = N.array(params)
  139. for j in range(len(params)):
  140. params1[j] += delta * xp[j]
  141. k, lam1, lam2 = params1
  142. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2)
  143. c1p, c2p, costp = constraint_fnl(cost, x, y, th)
  144. print '% constraint_fnl+ =', c1p, c2p, 'cost =', costp
  145. params1 = N.array(params)
  146. for j in range(len(params)):
  147. params1[j] -= delta * xp[j]
  148. k, lam1, lam2 = params1
  149. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2)
  150. c1m, c2m, costm = constraint_fnl(cost, x, y, th)
  151. print '% constraint_fnl- =', c1m, c2m, 'cost =', costm
  152. d2cost = (costp + costm - 2 * costc) / (delta * delta)
  153. dcost = (costp - costm) / (2 * delta)
  154. print '% dcost =', dcost, 'd2cost =', d2cost
  155. if d2cost < 0: d2cost = .1
  156. # Make Jacobian matrix to invert
  157. jm = N.array([dc1s, dc2s, [x * d2cost for x in xp]])
  158. #print jm
  159. ji = la.inverse(jm)
  160. #print ji
  161. dp = N.dot(ji, [c1c, c2c, dcost])
  162. print '% dp =', dp
  163. print '% [right]=', [c1c, c2c, dcost]
  164. params -= dp * .1
  165. print '%', params
  166. sys.stdout.flush()
  167. return params
  168. def solve_mec_3constr(constraint_fnl, n = 30, initparams = None):
  169. delta = 1e-3
  170. if initparams:
  171. params = N.array(initparams)
  172. else:
  173. params = [3.14, 0, 0]
  174. for i in range(n):
  175. k, lam1, lam2 = params
  176. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2)
  177. c1c, c2c, c3c = constraint_fnl(cost, x, y, th)
  178. print '% constraint_fnl =', c1c, c2c, c3c
  179. dc1s = []
  180. dc2s = []
  181. dc3s = []
  182. for j in range(len(params)):
  183. params1 = N.array(params)
  184. params1[j] += delta
  185. k, lam1, lam2 = params1
  186. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2)
  187. c1p, c2p, c3p = constraint_fnl(cost, x, y, th)
  188. params1 = N.array(params)
  189. params1[j] -= delta
  190. k, lam1, lam2 = params1
  191. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2)
  192. c1m, c2m, c3m = constraint_fnl(cost, x, y, th)
  193. dc1s.append((c1p - c1m) / (2 * delta))
  194. dc2s.append((c2p - c2m) / (2 * delta))
  195. dc3s.append((c3p - c3m) / (2 * delta))
  196. # Make Jacobian matrix to invert
  197. jm = N.array([dc1s, dc2s, dc3s])
  198. #print jm
  199. ji = la.inverse(jm)
  200. dp = N.dot(ji, [c1c, c2c, c3c])
  201. if i < n/2: scale = .25
  202. else: scale = 1
  203. params -= scale * dp
  204. print '%', params
  205. return params
  206. def mk_ths_fnl(th0, th1):
  207. def fnl(cost, x, y, th):
  208. actual_th0 = atan2(y, x)
  209. actual_th1 = th - actual_th0
  210. print '% x =', x, 'y =', y, 'hypot =', hypot(x, y)
  211. return th0 - actual_th0, th1 - actual_th1, cost
  212. return fnl
  213. def mk_y_fnl(th0, th1, ytarg):
  214. def fnl(cost, x, y, th):
  215. actual_th0 = atan2(y, x)
  216. actual_th1 = th - actual_th0
  217. return th0 - actual_th0, th1 - actual_th1, ytarg - hypot(x, y)
  218. return fnl
  219. def solve_mec_nested_inner(th0, th1, y, fnl):
  220. innerfnl = mk_y_fnl(th0, th1, y)
  221. params = [th0 + th1, 1e-6, 1e-6]
  222. params = solve_mec_3constr(innerfnl, 10, params)
  223. k, lam1, lam2 = params
  224. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2, 100)
  225. c1, c2, c3 = fnl(cost, x, y, th)
  226. return c3, params
  227. # Solve (th0, th1) mec to minimize fnl; use solve_mec_3constr as inner loop
  228. # Use golden section search
  229. def solve_mec_nested(th0, th1, fnl):
  230. R = .61803399
  231. C = 1 - R
  232. ax, cx = .6, .85
  233. bx = .5 * (ax + cx)
  234. x0, x3 = ax, cx
  235. if abs(cx - bx) > abs(bx - ax):
  236. x1, x2 = bx, bx + C * (cx - bx)
  237. else:
  238. x1, x2 = bx - C * (bx - ax), bx
  239. f1, p = solve_mec_nested_inner(th0, th1, x1, fnl)
  240. f2, p = solve_mec_nested_inner(th0, th1, x2, fnl)
  241. for i in range(10):
  242. print '%', x0, x1, x2, x3, ':', f1, f2
  243. if f2 < f1:
  244. x0, x1, x2 = x1, x2, R * x2 + C * x3
  245. f1 = f2
  246. f2, p = solve_mec_nested_inner(th0, th1, x2, fnl)
  247. else:
  248. x1, x2, x3 = R * x1 + C * x0, x1, x2
  249. f2 = f1
  250. f1, p = solve_mec_nested_inner(th0, th1, x1, fnl)
  251. if f1 < f2:
  252. x = x1
  253. else:
  254. x = x2
  255. cc, p = solve_mec_nested_inner(th0, th1, x, fnl)
  256. return p
  257. def plot(xys):
  258. cmd = 'moveto'
  259. for xy in xys:
  260. print 306 + 200 * xy[0], 396 - 200 * xy[1], cmd
  261. cmd = 'lineto'
  262. print 'stroke'
  263. def mec_test():
  264. th0, th1 = 0, pi / 4
  265. fnl = mk_ths_fnl(th0, th1)
  266. params = solve_mec_nested(th0, th1, fnl)
  267. k, lam1, lam2 = params
  268. xys, cost, x, y, th = run_mec_cos(k, lam1, lam2, 1000)
  269. plot(xys)
  270. print '% run_mec_cos:', cost, x, y, th
  271. print '1 0 0 setrgbcolor'
  272. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2)
  273. print '%', xys
  274. plot(xys)
  275. print '% run_elastica:', cost, x, y, th
  276. print 'showpage'
  277. print '%', params
  278. def lenfig():
  279. print '306 720 translate'
  280. th0, th1 = pi / 2, pi / 2
  281. for i in range(1, 10):
  282. y = .1 * i + .003
  283. fnl = mk_y_fnl(th0, th1, y)
  284. params = solve_mec_3constr(fnl)
  285. k, lam1, lam2 = params
  286. print 'gsave 0.5 dup scale -306 -396 translate'
  287. xys, cost, x, y, th = run_elastica(-2, 2, k, lam1, lam2, 100)
  288. print 'gsave [2] 0 setdash'
  289. plot(xys)
  290. print 'grestore'
  291. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2, 100)
  292. plot(xys)
  293. print 'grestore'
  294. print '% y =', y, 'params =', params
  295. if lam2 < 0:
  296. mymaxk = k
  297. else:
  298. mymaxk = sqrt(k * k + 4 * lam2)
  299. lam = abs(lam2) / (mymaxk * mymaxk)
  300. print '-200 0 moveto /Symbol 12 selectfont (l) show'
  301. print '/Times-Roman 12 selectfont ( = %.4g) show' % lam
  302. print '0 -70 translate'
  303. print 'showpage'
  304. def lenplot(figno, th0, th1):
  305. result = []
  306. if figno in (1, 2):
  307. imax = 181
  308. elif figno == 3:
  309. imax = 191
  310. for i in range(1, imax):
  311. yy = .005 * i
  312. if figno in (1, 2) and i == 127:
  313. yy = 2 / pi
  314. if figno == 3 and i == 165:
  315. yy = .8270
  316. fnl = mk_y_fnl(th0, th1, yy)
  317. params = solve_mec_3constr(fnl)
  318. k, lam1, lam2 = params
  319. xys, cost, x0, y0, th = run_elastica(-.5, .5, k, lam1, lam2, 100)
  320. if lam2 < 0:
  321. mymaxk = k
  322. else:
  323. mymaxk = sqrt(k * k + 4 * lam2)
  324. lam = abs(lam2) / (mymaxk * mymaxk)
  325. result.append((yy, lam, cost))
  326. return result
  327. def lengraph(figno):
  328. if figno in (1, 2):
  329. eps_prologue(15, 47, 585, 543)
  330. th0, th1 = pi / 2, pi / 2
  331. yscale = 900
  332. ytic = .05
  333. ymax = 10
  334. elif figno == 3:
  335. eps_prologue(15, 47, 585, 592)
  336. th0, th1 = pi / 3, pi / 3
  337. yscale = 500
  338. ytic = .1
  339. ymax = 10
  340. x0 = 42
  341. xscale = 7.5 * 72
  342. y0 = 72
  343. print '/Times-Roman 12 selectfont'
  344. print '/ss 1.5 def'
  345. print '/circle { ss 0 moveto currentpoint exch ss sub exch ss 0 360 arc } bind def'
  346. print '.5 setlinewidth'
  347. print x0, y0, 'moveto', xscale, '0 rlineto 0', yscale * ytic * ymax, 'rlineto', -xscale, '0 rlineto closepath stroke'
  348. for i in range(0, 11):
  349. print x0 + .1 * i * xscale, y0, 'moveto 0 6 rlineto stroke'
  350. print x0 + .1 * i * xscale, y0 + ytic * ymax * yscale, 'moveto 0 -6 rlineto stroke'
  351. print x0 + .1 * i * xscale, y0 - 12, 'moveto'
  352. print '(%.1g) dup stringwidth exch -.5 mul exch rmoveto show' % (.1 * i)
  353. for i in range(0, 11):
  354. print x0, y0 + ytic * i * yscale, 'moveto 6 0 rlineto stroke'
  355. print x0 + xscale, y0 + ytic * i * yscale, 'moveto -6 0 rlineto stroke'
  356. print x0 - 3, y0 + ytic * i * yscale - 3.5, 'moveto'
  357. print '(%.2g) dup stringwidth exch neg exch rmoveto show' % (ytic * i)
  358. print x0 + .25 * xscale, y0 - 24, 'moveto (chordlen / arclen) show'
  359. print x0 - 14, y0 + ytic * ymax * yscale + 10, 'moveto /Symbol 12 selectfont (l) show'
  360. if figno in (1, 2):
  361. print x0 + 2 / pi * xscale, y0 - 18, 'moveto'
  362. print '(2/p) dup stringwidth exch -.5 mul exch rmoveto show'
  363. print 'gsave [3] 0 setdash'
  364. print x0, y0 + .25 * yscale, 'moveto', xscale, '0 rlineto stroke'
  365. if figno == 3:
  366. print x0, y0 + .5 * yscale, 'moveto', xscale, '0 rlineto stroke'
  367. xinterest = .81153
  368. print x0 + xinterest * xscale, y0, 'moveto 0', yscale * .5, 'rlineto stroke'
  369. print 'grestore'
  370. print '.75 setlinewidth'
  371. if 1:
  372. if figno in (1, 2):
  373. costscale = .01 * yscale
  374. elif figno == 3:
  375. costscale = .0187 * yscale
  376. lenresult = lenplot(figno, th0, th1)
  377. cmd = 'moveto'
  378. for x, y, cost in lenresult:
  379. print x0 + xscale * x, y0 + yscale * y, cmd
  380. cmd = 'lineto'
  381. print 'stroke'
  382. if figno in (2, 3):
  383. cmd = 'moveto'
  384. for x, y, cost in lenresult:
  385. print x0 + xscale * x, y0 + costscale * cost, cmd
  386. cmd = 'lineto'
  387. print 'stroke'
  388. cmd = 'moveto'
  389. for x, y, cost in lenresult:
  390. print x0 + xscale * x, y0 + costscale * x * cost, cmd
  391. cmd = 'lineto'
  392. print 'stroke'
  393. print '/Times-Roman 12 selectfont'
  394. if figno == 2:
  395. xlm, ylm = .75, 7
  396. xls, yls = .42, 15
  397. elif figno == 3:
  398. xlm, ylm = .6, 3
  399. xls, yls = .37, 15
  400. print x0 + xscale * xlm, y0 + costscale * ylm, 'moveto'
  401. print '(MEC cost) show'
  402. print x0 + xscale * xls, y0 + costscale * yls, 'moveto'
  403. print '(SIMEC cost) show'
  404. if figno == 1:
  405. minis = [(.05, 5, -5),
  406. (.26, -40, 10),
  407. (.4569466, -5, -10),
  408. (.55, 35, 12),
  409. (.6026, -60, 45),
  410. (.6046, -60, 15),
  411. (.6066, -60, -15),
  412. (.6213, -22, 10),
  413. (.6366198, 15, 22),
  414. (.66, 20, 10),
  415. (.9, 0, -10)]
  416. elif figno == 2:
  417. minis = [(.4569466, -5, -10),
  418. (.6366198, 15, 22)]
  419. elif figno == 3:
  420. minis = [(.741, 55, -10),
  421. (.81153, -30, 20),
  422. (.8270, 20, 30)]
  423. for yy, xo, yo in minis:
  424. fnl = mk_y_fnl(th0, th1, yy)
  425. params = solve_mec_3constr(fnl)
  426. k, lam1, lam2 = params
  427. if lam2 < 0:
  428. mymaxk = k
  429. else:
  430. mymaxk = sqrt(k * k + 4 * lam2)
  431. lam = abs(lam2) / (mymaxk * mymaxk)
  432. x = x0 + xscale * yy
  433. y = y0 + yscale * lam
  434. print 'gsave %g %g translate circle fill' % (x, y)
  435. print '%g %g translate 0.15 dup scale' % (xo, yo)
  436. print '-306 -396 translate'
  437. print '2 setlinewidth'
  438. if yy < .6 or yy > .61:
  439. s = 2
  440. elif yy == .6046:
  441. s = 2.8
  442. else:
  443. s = 5
  444. xys, cost, x, y, th = run_elastica(-s, s, k, lam1, lam2, 100)
  445. print 'gsave [10] 0 setdash'
  446. plot(xys)
  447. print 'grestore 6 setlinewidth'
  448. xys, cost, x, y, th = run_elastica(-.5, .5, k, lam1, lam2, 100)
  449. plot(xys)
  450. print 'grestore'
  451. print 'showpage'
  452. eps_trailer()
  453. def draw_axes(x0, y0, xscale, yscale, xmax, ymax, nx, ny):
  454. print '.5 setlinewidth'
  455. print '/Times-Roman 12 selectfont'
  456. print x0, y0, 'moveto', xscale * xmax, '0 rlineto 0', yscale * ymax, 'rlineto', -xscale * xmax, '0 rlineto closepath stroke'
  457. xinc = (xmax * xscale * 1.) / nx
  458. yinc = (ymax * yscale * 1.) / ny
  459. for i in range(0, nx + 1):
  460. if i > 0 and i < nx + 1:
  461. print x0 + xinc * i, y0, 'moveto 0 6 rlineto stroke'
  462. print x0 + xinc * i, y0 + ymax * yscale, 'moveto 0 -6 rlineto stroke'
  463. print x0 + xinc * i, y0 - 12, 'moveto'
  464. print '(%.2g) dup stringwidth exch -.5 mul exch rmoveto show' % ((i * xmax * 1.) / nx)
  465. for i in range(0, ny + 1):
  466. if i > 0 and i < ny + 1:
  467. print x0, y0 + yinc * i, 'moveto 6 0 rlineto stroke'
  468. print x0 + xmax * xscale, y0 + yinc * i, 'moveto -6 0 rlineto stroke'
  469. print x0 - 3, y0 + yinc * i - 3.5, 'moveto'
  470. print '(%.2g) dup stringwidth exch neg exch rmoveto show' % ((i * ymax * 1.) / ny)
  471. def mecchord():
  472. x0 = 72
  473. y0 = 72
  474. thscale = 150
  475. chscale = 400
  476. print '.5 setlinewidth'
  477. print '/ss 1.5 def'
  478. print '/circle { ss 0 moveto currentpoint exch ss sub exch ss 0 360 arc } bind def'
  479. draw_axes(x0, y0, thscale, chscale, 3.2, 1, 16, 10)
  480. print x0 + 1 * thscale, y0 - 28, 'moveto (angle) show'
  481. print 'gsave', x0 - 32, y0 + .25 * chscale, 'translate'
  482. print '90 rotate 0 0 moveto (chordlen / arclen) show'
  483. print 'grestore'
  484. cmd = 'moveto'
  485. for i in range(0, 67):
  486. s = i * .01
  487. xys, cost, x, y, th = run_elastica(-s, s, 4, 0, -8, 100)
  488. #plot(xys)
  489. if s > 0:
  490. ch = hypot(x, y) / (2 * s)
  491. else:
  492. ch = 1
  493. print '%', s, x, y, th, ch
  494. print x0 + thscale * th / 2, y0 + ch * chscale, cmd
  495. cmd = 'lineto'
  496. print 'stroke'
  497. print 'gsave %g %g translate circle fill' % (x0 + thscale * th / 2, y0 + ch * chscale)
  498. print '-30 15 translate 0.25 dup scale'
  499. print '-306 -396 translate'
  500. print '2 setlinewidth'
  501. plot(xys)
  502. print 'grestore'
  503. print 'gsave [2] 0 setdash'
  504. cmd = 'moveto'
  505. for i in range(0, 151):
  506. th = pi * i / 150.
  507. if th > 0:
  508. ch = sin(th) / th
  509. else:
  510. ch = 1
  511. print x0 + thscale * th, y0 + ch * chscale, cmd
  512. cmd = 'lineto'
  513. print 'stroke'
  514. print 'grestore'
  515. k0 = 4 * .4536 / (2 / pi)
  516. s = pi / (2 * k0)
  517. xys, cost, x, y, th = run_elastica(-s, s, k0, 0, 0, 100)
  518. th = pi
  519. ch = 2 / pi
  520. print 'gsave %g %g translate circle fill' % (x0 + thscale * th / 2, y0 + ch * chscale)
  521. print '30 15 translate 0.25 dup scale'
  522. print '-306 -396 translate'
  523. print '2 setlinewidth'
  524. plot(xys)
  525. print 'grestore'
  526. print x0 + 1.25 * thscale, y0 + .55 * chscale, 'moveto (MEC) show'
  527. print x0 + 2.3 * thscale, y0 + .35 * chscale, 'moveto (SIMEC) show'
  528. print 'showpage'
  529. def trymec(sm, sp):
  530. xys, thm, cost = run_elastica_half(abs(sm), 0, 1, 0, 10)
  531. xm, ym, km = xys[-1]
  532. if sm < 0:
  533. xm = -xm
  534. ym = -ym
  535. thm = -thm
  536. xys, thp, cost = run_elastica_half(abs(sp), 0, 1, 0, 10)
  537. xp, yp, kp = xys[-1]
  538. if sp < 0:
  539. xp = -xp
  540. yp = -yp
  541. thp = -thp
  542. chth = atan2(yp - ym, xp - xm)
  543. #print xm, ym, xp, yp, chth, thm, thp
  544. actual_th0 = chth - thm
  545. actual_th1 = thp - chth
  546. return actual_th0, actual_th1
  547. def findmec_old(th0, th1):
  548. guess_ds = sqrt(6 * (th1 - th0))
  549. guess_savg = 2 * (th1 + th0) / guess_ds
  550. sm = .5 * (guess_savg - guess_ds)
  551. sp = .5 * (guess_savg + guess_ds)
  552. #sm, sp = th0, th1
  553. for i in range(1):
  554. actual_th0, actual_th1 = trymec(sm, sp)
  555. guess_dth = 1./6 * (sp - sm) ** 2
  556. guess_avth = .5 * (sp + sm) * (sp - sm)
  557. guess_th0 = .5 * (guess_avth - guess_dth)
  558. guess_th1 = .5 * (guess_avth + guess_dth)
  559. print sm, sp, actual_th0, actual_th1, guess_th0, guess_th1
  560. def mecplots():
  561. print '2 dup scale'
  562. print '-153 -296 translate'
  563. scale = 45
  564. print '0.25 setlinewidth'
  565. print 306 - scale * pi/2, 396, 'moveto', 306 + scale * pi/2, 396, 'lineto stroke'
  566. print 306, 396 - scale * pi/2, 'moveto', 306, 396 + scale * pi/2, 'lineto stroke'
  567. print '/ss .5 def'
  568. print '/circle { ss 0 moveto currentpoint exch ss sub exch ss 0 360 arc } bind def'
  569. tic = .1
  570. maj = 5
  571. r0, r1 = 0, 81
  572. for i in range(r0, r1, maj):
  573. sm = i * tic
  574. cmd = 'moveto'
  575. for j in range(i, r1):
  576. sp = j * tic + 1e-3
  577. th0, th1 = trymec(sm, sp)
  578. print '%', sm, sp, th0, th1
  579. print 306 + scale * th0, 396 + scale * th1, cmd
  580. cmd = 'lineto'
  581. print 'stroke'
  582. for j in range(r0, r1, maj):
  583. sp = j * tic + 1e-3
  584. cmd = 'moveto'
  585. for i in range(0, j + 1):
  586. sm = i * tic
  587. th0, th1 = trymec(sm, sp)
  588. print '%', sm, sp, th0, th1
  589. print 306 + scale * th0, 396 + scale * th1, cmd
  590. cmd = 'lineto'
  591. print 'stroke'
  592. for i in range(r0, r1, maj):
  593. sm = i * tic
  594. for j in range(i, r1, maj):
  595. sp = j * tic + 1e-3
  596. th0, th1 = trymec(sm, sp)
  597. print 'gsave'
  598. print 306 + scale * th0, 596 + scale * th1, 'translate'
  599. print 'circle fill'
  600. uscale = 3
  601. xys, thm, cost = run_elastica_half(abs(sm), 0, 1, 0, 100)
  602. x0, y0 = xys[-1][0], xys[-1][1]
  603. if sm < 0:
  604. x0, y0 = -x0, -y0
  605. xys, thm, cost = run_elastica_half(abs(sp), 0, 1, 0, 100)
  606. x1, y1 = xys[-1][0], xys[-1][1]
  607. if sp < 0:
  608. x1, y1 = -x1, -y1
  609. cmd = 'moveto'
  610. for xy in xys:
  611. print xy[0] * uscale, xy[1] * uscale, cmd
  612. cmd = 'lineto'
  613. print 'stroke'
  614. print '1 0 0 setrgbcolor'
  615. print x0 * uscale, y0 * uscale, 'moveto'
  616. print x1 * uscale, y1 * uscale, 'lineto stroke'
  617. print 'grestore'
  618. print 'showpage'
  619. def findmec(th0, th1):
  620. delta = 1e-3
  621. if th0 < 0 and th0 - th1 < .1:
  622. sm = 5.
  623. sp = 6.
  624. else:
  625. sm = 3.
  626. sp = 5.
  627. params = [sm, sp]
  628. lasterr = 1e6
  629. for i in range(25):
  630. sm, sp = params
  631. ath0, ath1 = trymec(sm, sp)
  632. c1c, c2c = th0 - ath0, th1 - ath1
  633. err = c1c * c1c + c2c * c2c
  634. if 0:
  635. print '%findmec', sm, sp, ath0, ath1, err
  636. sys.stdout.flush()
  637. if err < 1e-9:
  638. return params
  639. if err > lasterr:
  640. return None
  641. lasterr = err
  642. dc1s = []
  643. dc2s = []
  644. for j in range(len(params)):
  645. params1 = N.array(params)
  646. params1[j] += delta
  647. sm, sp = params1
  648. ath0, ath1 = trymec(sm, sp)
  649. c1p, c2p = th0 - ath0, th1 - ath1
  650. params1 = N.array(params)
  651. params1[j] -= delta
  652. sm, sp = params1
  653. ath0, ath1 = trymec(sm, sp)
  654. c1m, c2m = th0 - ath0, th1 - ath1
  655. dc1s.append((c1p - c1m) / (2 * delta))
  656. dc2s.append((c2p - c2m) / (2 * delta))
  657. jm = N.array([dc1s, dc2s])
  658. ji = la.inverse(jm)
  659. dp = N.dot(ji, [c1c, c2c])
  660. if i < 4:
  661. scale = .5
  662. else:
  663. scale = 1
  664. params -= scale * dp
  665. if params[0] < 0: params[0] = 0.
  666. return params
  667. def mecrange(figtype):
  668. scale = 130
  669. eps_prologue(50, 110, 570, 630)
  670. print -50, 0, 'translate'
  671. print '0.5 setlinewidth'
  672. thlmin, thlmax = -pi/2, 2.4
  673. thrmin, thrmax = -2.2, pi / 2 + .2
  674. print 306 + scale * thlmin, 396, 'moveto', 306 + scale * thlmax, 396, 'lineto stroke'
  675. print 306, 396 + scale * thrmin, 'moveto', 306, 396 + scale * thrmax, 'lineto stroke'
  676. print 'gsave [2] 0 setdash'
  677. print 306, 396 + scale * pi / 2, 'moveto'
  678. print 306 + scale * thlmax, 396 + scale * pi / 2, 'lineto stroke'
  679. print 306 + scale * thlmin, 396 - scale * pi / 2, 'moveto'
  680. print 306 + scale * thlmax, 396 - scale * pi / 2, 'lineto stroke'
  681. print 306 + scale * pi / 2, 396 + scale * thrmin, 'moveto'
  682. print 306 + scale * pi / 2, 396 + scale * thrmax, 'lineto stroke'
  683. print 'grestore'
  684. print 306 + 3, 396 + scale * thrmax - 10, 'moveto'
  685. print '/Symbol 12 selectfont (q) show'
  686. print 0, -2, 'rmoveto'
  687. print '/Times-Italic 9 selectfont (right) show'
  688. print 306 - 18, 396 + scale * pi / 2 - 4, 'moveto'
  689. print '/Symbol 12 selectfont (p/2) show'
  690. print 306 + scale * 2.2, 396 - scale * pi / 2 + 2, 'moveto'
  691. print '/Symbol 12 selectfont (-p/2) show'
  692. print 306 + scale * pi/2 + 2, 396 + scale * thrmax - 10, 'moveto'
  693. print '/Symbol 12 selectfont (p/2) show'
  694. print 306 + scale * 2.2, 396 + 6, 'moveto'
  695. print '/Symbol 12 selectfont (q) show'
  696. print 0, -2, 'rmoveto'
  697. print '/Times-Italic 9 selectfont (left) show'
  698. print '/ss 0.8 def'
  699. print '/circle { ss 0 moveto currentpoint exch ss sub exch ss 0 360 arc } bind def'
  700. cmd = 'moveto'
  701. for i in range(0, 201):
  702. th = (i * .005 - .75 )* pi
  703. rmin = 1.5
  704. rmax = 2.5
  705. for j in range(20):
  706. r = (rmin + rmax) * .5
  707. th0 = r * cos(th)
  708. th1 = r * sin(th)
  709. if findmec(th0, th1) == None:
  710. rmax = r
  711. else:
  712. rmin = r
  713. r = (rmin + rmax) * .5
  714. th0 = r * cos(th)
  715. th1 = r * sin(th)
  716. print '%', r, th, th0, th1
  717. print 306 + scale * th0, 396 + scale * th1, cmd
  718. cmd = 'lineto'
  719. sys.stdout.flush()
  720. print 'stroke'
  721. sys.stdout.flush()
  722. for i in range(-11, 12):
  723. for j in range(-11, i + 1):
  724. th0, th1 = i * .196, j * .196
  725. print '%', th0, th1
  726. params = findmec(th0, th1)
  727. if params != None:
  728. sm, sp = params
  729. print 'gsave'
  730. print 306 + scale * th0, 396 + scale * th1, 'translate'
  731. uscale = 22
  732. k0, lam1, lam2 = justify_mec(sm, sp)
  733. xys, cost, x, y, th = run_elastica(-.5, .5, k0, lam1, lam2)
  734. cmdm = 'moveto'
  735. dx = xys[-1][0] - xys[0][0]
  736. dy = xys[-1][1] - xys[0][1]
  737. ch = hypot(dx, dy)
  738. chth = atan2(dy, dx)
  739. if figtype == 'mecrange':
  740. print 'circle fill'
  741. s = uscale * sin(chth) / ch
  742. c = uscale * cos(chth) / ch
  743. h = -xys[0][0] * s + xys[0][1] * c
  744. for xy in xys:
  745. print xy[0] * c + xy[1] * s, h + xy[0] * s - xy[1] * c, cmdm
  746. cmdm = 'lineto'
  747. elif figtype == 'mecrangek':
  748. ds = 1. / (len(xys) - 1)
  749. sscale = 13. / ch
  750. kscale = 3 * ch
  751. print 'gsave .25 setlinewidth'
  752. print sscale * -.5, 0, 'moveto', sscale, 0, 'rlineto stroke'
  753. print 'grestore'
  754. for l in range(len(xys)):
  755. print sscale * (ds * l - 0.5), kscale * xys[l][2], cmdm
  756. cmdm = 'lineto'
  757. print 'stroke'
  758. print 'grestore'
  759. sys.stdout.flush()
  760. print 'showpage'
  761. eps_trailer()
  762. # given sm, sp in [0, 1, 0] mec, return params for -0.5..0.5 segment
  763. def justify_mec(sm, sp):
  764. sc = (sm + sp) * 0.5
  765. xys, thc, cost = run_elastica_half(sc, 0, 1, 0, 100)
  766. print '% sc =', sc, 'thc =', thc
  767. k0, lam1, lam2 = xys[-1][2], cos(thc), -sin(thc)
  768. ds = sp - sm
  769. k0 *= ds
  770. lam1 *= ds * ds
  771. lam2 *= ds * ds
  772. return [k0, lam1, lam2]
  773. import sys
  774. figname = sys.argv[1]
  775. if len(figname) > 4 and figname[-4:] == '.pdf': figname = figname[:-4]
  776. if figname in ('lengraph1', 'lengraph2', 'lengraph3'):
  777. lengraph(int(figname[-1]))
  778. #mec_test()
  779. #lenfig()
  780. elif figname == 'mecchord':
  781. mecchord()
  782. elif figname in ('mecrange', 'mecrangek'):
  783. mecrange(figname)
  784. elif figname == 'mecplots':
  785. mecplots()
  786. elif figname == 'findmec':
  787. findmec(-.1, -.1)
  788. findmec(-.2, -.2)