From 54ba58f6572ef5c7d7626e4ec6af750439a29553 Mon Sep 17 00:00:00 2001 From: Thierry Zamofing Date: Wed, 27 Nov 2024 15:23:52 +0100 Subject: [PATCH] try to cleanup stuff(1) --- python/shapepath.py | 418 ++++++++++++++++++++++---------------------- 1 file changed, 213 insertions(+), 205 deletions(-) diff --git a/python/shapepath.py b/python/shapepath.py index 0afa0ce..c8524ad 100755 --- a/python/shapepath.py +++ b/python/shapepath.py @@ -192,7 +192,8 @@ class DebugPlot: def plot_points(pts): fig=plt.figure() ax = fig.add_subplot(1,1,1) - ax.invert_xaxis();ax.invert_yaxis() + #ax.invert_xaxis() + ax.invert_yaxis() #hl=ax[0].plot(x, y, color=col) hl=ax.plot(pts[:,0],pts[:,1],'r.') hl=ax.plot(pts[:,0],pts[:,1],'y--') @@ -707,187 +708,197 @@ class ShapePath(MotionBase): the type of generated program is defined by $ -> the list af all points that will be moved at, is in 'mot_pts' + (m)= mandatory + (o)= optional common kwargs: - scale : scaling velocity (default=1. value=0 would stop at each point - cnt : move path multiple times (default=1) - dwell : dwell time at end (default=100ms) + scale : (o) scaling velocity (default=1. value=0 would stop at each point + cnt : (o) move path multiple times (default=1) + dwell : (o) dwell time at end (default=100ms) mode:0 unused - mode:1 pvt motion + mode:1 pvt motion point list common kwargs plus: - points : point list - trf : optional transformation that will be done on 'points', mot_pts=trf*points + points : (m) point list + trf : (o) transformation that will be done on 'points', mot_pts=trf*points mode:2 unused - mode:3 pvt motion using inverse fft velocity + mode:3 pvt motion point list using inverse fft velocity common kwargs plus: - points : point list - trf : optional transformation that will be done on 'points', mot_pts=trf*points - numPad : number of padding points to reduce aliasing (default=16) + points : (m) point list + trf : (o) transformation that will be done on 'points', mot_pts=trf*points + numPad : (o) number of padding points to reduce aliasing (default=16) mode:4 pvt motion short code using grid parameters common kwargs plus: - trf : transformation that will be done on 'grid points' - grid: grid parameters: {orig:(0,0),pitch(10,10),cnt:(10,10),mode:0} + trf : (o) transformation that will be done on 'grid points' + grid: (m) grid parameters: {orig:(0,0),pitch(10,10),cnt:(10,10),mode:0} mode:5 pvt motion 'stop and go' short code using grid parameters. Instead of continous motion it moves and waits as given in the parameters common kwargs plus: - trf : transformation that will be done on 'grid points' - grid: grid parameters: {orig:(0,0),pitch(10,10),cnt:(10,10),mode:0} - tmove: time to move in ms (move start on FEL-trigger - twait: time to wait in ms + trf : (o) transformation that will be done on 'grid points' + grid: (m) grid parameters: {orig:(0,0),pitch(10,10),cnt:(10,10),mode:0} + tmove: (m) time to move in ms (move start on FEL-trigger + twait: (m) time to wait in ms (tmove+twait will be rounded to a multiple of fel_per) mode:6 pvt motion 'hit and return using grid parameters. continous motion on 2n ells to pump then same 2n wells to probe, then go 2 rows down common kwargs plus: - trf : transformation that will be done on 'grid points' - grid : grid parameters: {orig:(0,0),pitch(10,10),cnt:(10,10),mode:0} - ssz : section size (in wells) - smv : time(in num of shots) to move to next section (horiz/vert) + trf : (o) transformation that will be done on 'grid points' + grid : (m) grid parameters: {orig:(0,0),pitch(10,10),cnt:(10,10),mode:0} + ssz : (m) section size (in wells) + smv : (o) time(in num of shots) to move to next section (horiz/vert) default is (ssz[0]-1,ssz[1]) - sdelay: shots count of delay. Default is ssz[0]*ssz[1] + sdelay: (o) shots count of delay. Default is ssz[0]*ssz[1] ''' - #scan=0 # snake motion X fast, Y slow - scan=1 # snake motion Y fast, X slow (default) - - prg=f'close all buffers\nopen prog {prgId}\n Coord[1].DesTimeBase=Sys.ServoPeriod\n' - - verb=self.verbose - comm=self.comm - meta=self.meta + if mode not in (1,3,4,5,6): #### pvt motion + raise ValueError(f'unsupported mode:{mode}') try: self.sync_prg except AttributeError: _log.warning('missing motion sync code!') - # this uses Coord[1].Tm and limits with MaxSpeed - if mode in (1,3,4,5,6): #### pvt motion - if mode!=5: - pt2pt_time=meta['pt2pt_time']=meta['fel_per'] - scale=kwargs.get('scale', 1.) - cnt=kwargs.get('cnt', 1) # move path multiple times - dwell=kwargs.get('dwell', 100) # wait time at end of motion - CoordFeedTime=1000. #Defaut deltatau value - if mode in (1, 3): #### pvt motion, using points - pt=kwargs['points'] - try: - trf=kwargs['trf'] - except KeyError as e: - self.mot_pts=pt + + verb=self.verbose + comm=self.comm + meta=self.meta + #scan=0 # snake motion X fast, Y slow + scan=1 # snake motion Y fast, X slow (default) + + argsStr=[f'mode:{mode}'] + for k,v in kwargs.items(): + if type(v) in (np.ndarray,np.matrix): + argsStr.append(f'{k}:{type(v).__name__}({v.shape})') + else: + argsStr.append(f'{k}:{v}') + prg='// '+' '.join(argsStr) + prg+=f'\n\nclose all buffers\nopen prog {prgId}\n Coord[1].DesTimeBase=Sys.ServoPeriod\n' + + scale=kwargs.get('scale', 1.) + cnt=kwargs.get('cnt', 1) # move path multiple times + dwell=kwargs.get('dwell', 100) # wait time at end of motion + CoordFeedTime=1000. #Defaut deltatau value + if mode!=5: + pt2pt_time=meta['pt2pt_time']=meta['fel_per'] + if mode in (1, 3): #### pvt motion, using points + pt=kwargs['points'] + try: + trf=kwargs['trf'] + except KeyError as e: + self.mot_pts=pt + else: + self.mot_pts=(np.hstack((pt, np.ones((pt.shape[0], 1))))*np.asmatrix(trf)).A # pt*trf + #pv is an array of posx posy velx vely + pv=np.ndarray(shape=(pt.shape[0]+2,4),dtype=pt.dtype) + pv[:]=np.NaN + pv[ 0,(0,1)]=pt[0,:] + pv[ 1:-1,(0,1)]=pt + pv[ -1,(0,1)]=pt[-1,:] + pv[(0,0,-1,-1),(2,3,2,3)]=0 + if mode==1: # set velocity to average from prev to next point + dist=pv[2:,(0,1)] - pv[:-2,(0,1)] + pv[ 1:-1,(2,3)] = dist/(2.*pt2pt_time)*scale #um/ms + else: # mode==3: # set velocity to the reconstructed inverse fourier transformation + numPad=kwargs.get('numPad', 16) + p=np.hstack((pt.T,pt[-1,:].repeat(numPad).reshape(2,-1))) + k=p.shape[1] + stp=((p[:,-1]-p[:,0])/(k-1)) #calculate steepness point to point + #stp*=0 + p[0,:]-=stp[0]*np.arange(k) + p[1,:]-=stp[1]*np.arange(k) + f=np.fft.fftfreq(k, d=1.) + pf=np.fft.fft(p) + pfd=pf*f*1j # differentiate in fourier + pd=np.fft.ifft(pfd) + v=pd.real.T/pt2pt_time*np.pi*2+stp/pt2pt_time + if numPad==0: + n=None else: - self.mot_pts=(np.hstack((pt, np.ones((pt.shape[0], 1))))*np.asmatrix(trf)).A # pt*trf - #pv is an array of posx posy velx vely - pv=np.ndarray(shape=(pt.shape[0]+2,4),dtype=pt.dtype) - pv[:]=np.NaN - pv[ 0,(0,1)]=pt[0,:] - pv[ 1:-1,(0,1)]=pt - pv[ -1,(0,1)]=pt[-1,:] - pv[(0,0,-1,-1),(2,3,2,3)]=0 - if mode==1: # set velocity to average from prev to next point - dist=pv[2:,(0,1)] - pv[:-2,(0,1)] - pv[ 1:-1,(2,3)] = dist/(2.*pt2pt_time)*scale #um/ms - else: # mode==3: # set velocity to the reconstructed inverse fourier transformation - numPad=kwargs.get('numPad', 16) - p=np.hstack((pt.T,pt[-1,:].repeat(numPad).reshape(2,-1))) - k=p.shape[1] - stp=((p[:,-1]-p[:,0])/(k-1)) #calculate steepness point to point - #stp*=0 - p[0,:]-=stp[0]*np.arange(k) - p[1,:]-=stp[1]*np.arange(k) - f=np.fft.fftfreq(k, d=1.) - pf=np.fft.fft(p) - pfd=pf*f*1j # differentiate in fourier - pd=np.fft.ifft(pfd) - v=pd.real.T/pt2pt_time*np.pi*2+stp/pt2pt_time - if numPad==0: - n=None - else: - n=-numPad - pv[ 1:-1,(2,3)] = v[:n]*scale - if verb&0x20: - if 'trf' in kwargs: - _log.warning('correct ploting of pvt only works without transformation !') - else: - dp=DebugPlot(self);self.pvt=dp.plot_gen_pvt(pv) - plt.show(block=False) - pv[1:-1, (2, 3)]*=CoordFeedTime #scaling for Deltatau - prg+=' linear abs\n X%g Y%g\n' % tuple(pv[0, (0,1)]) - elif mode in (4,5): #### pvt motion, short code using grid parameters - g=kwargs['grid'] - nx, ny=g['count'] - xx, yy=np.meshgrid(range(nx), range(ny)) - if scan==0: # snake motion X fast, Y slow - for i in range(1,ny,2): - xx[i]=xx[i][::-1] - else: #scan==1 snake motion Y fast, X slow - xx=xx.T - yy=yy.T - for i in range(1, nx, 2): - yy[i]=yy[i][::-1] - pt=np.array([xx.reshape(-1), yy.reshape(-1)], dtype=np.float64).transpose() #*pitch - try: - trf=kwargs['trf'] - except KeyError as e: - ox, oy=g['pos'] - px, py=g['pitch'] - #self.mot_pts=pt - self.mot_pts=pt*np.array(g['pitch'], np.float)+np.array(g['pos'], np.float) + n=-numPad + pv[ 1:-1,(2,3)] = v[:n]*scale + if verb&0x20: + if 'trf' in kwargs: + _log.warning('correct plotting of pvt only works without transformation !') else: - ox, oy=(0,0) - px, py=(1,1) - self.mot_pts=(np.hstack((pt, np.ones((pt.shape[0], 1))))*np.asmatrix(trf)).A # pt*trf - #prg+=f' linear abs\n X{ox:g} Y{oy:g}\n' - prg+=f' linear abs\n X{ox-px:g} Y{oy-py:g}\n' # start one position out of grid - else: #mode==6: #### pvt motion, hit and return using grid parameters - g=kwargs['grid'] - nx,ny=g['count'] #total count of wells - #TODO: rework pt calculation - hrs=HitReturnSim() - pt=hrs.sim_motion(mode=0xff if verb&0x20 else 0x00 , **kwargs) - pt=np.array(pt)[:,:2] - try: - trf=kwargs['trf'] - except KeyError as e: - ox, oy=g['pos'] - px, py=g['pitch'] - self.mot_pts=pt*np.array(g['pitch'], np.float)+np.array(g['pos'], np.float) - else: - ox, oy=(0,0) - px, py=(1,1) - self.mot_pts=(np.hstack((pt, np.ones((pt.shape[0], 1))))*np.asmatrix(trf)).A # pt*trf - sx,sy=kwargs['ssz'] #section size (in wells) - try: - tsx,tsy=kwargs['smv'] #time(in num of shots) to move to next section (horiz/vert) - except KeyError as e: - tsx=sx-1 - tsy=sy - try: - tsd=kwargs['sdelay'] - except KeyError as e: - tsd=sx*sy - tsd+=1-sx*sy # sdl are shots to wait at position #(6) - prg+=f' linear abs\n X{ox-px:g} Y{oy-py:g}\n' # start one position out of grid - prg+=' dwell 10\n' - try: prg+=self.sync_prg - except AttributeError: - #print('no sync code available') - prg+=' Gather.Enable=2\n' - if cnt>1: - prg+=' P100=%d\n'%cnt - prg+='N100:\n' - if mode in (1,3): - prg+=f'''\ + dp=DebugPlot(self);self.pvt=dp.plot_gen_pvt(pv) + plt.show(block=False) + pv[1:-1, (2, 3)]*=CoordFeedTime #scaling for Deltatau + prg+=' linear abs\n X%g Y%g\n' % tuple(pv[0, (0,1)]) + elif mode in (4,5): #### pvt motion, short code using grid parameters + g=kwargs['grid'] + nx, ny=g['count'] + xx, yy=np.meshgrid(range(nx), range(ny)) + if scan==0: # snake motion X fast, Y slow + for i in range(1,ny,2): + xx[i]=xx[i][::-1] + else: #scan==1 snake motion Y fast, X slow + xx=xx.T + yy=yy.T + for i in range(1, nx, 2): + yy[i]=yy[i][::-1] + pt=np.array([xx.reshape(-1), yy.reshape(-1)], dtype=np.float64).transpose() #*pitch + try: + trf=kwargs['trf'] + except KeyError as e: + ox, oy=g['pos'] + px, py=g['pitch'] + #self.mot_pts=pt + self.mot_pts=pt*np.array(g['pitch'], np.float)+np.array(g['pos'], np.float) + else: + ox, oy=(0,0) + px, py=(1,1) + self.mot_pts=(np.hstack((pt, np.ones((pt.shape[0], 1))))*np.asmatrix(trf)).A # pt*trf + #prg+=f' linear abs\n X{ox:g} Y{oy:g}\n' + prg+=f' linear abs\n X{ox-px:g} Y{oy-py:g}\n' # start one position out of grid + else: #mode==6: #### pvt motion, hit and return using grid parameters + g=kwargs['grid'] + nx,ny=g['count'] #total count of wells + #TODO: rework pt calculation + hrs=HitReturnSim() + pt=hrs.sim_motion(mode=0xff if verb&0x20 else 0x00 , **kwargs) + pt=np.array(pt)[:,:2] + try: + trf=kwargs['trf'] + except KeyError as e: + ox, oy=g['pos'] + px, py=g['pitch'] + self.mot_pts=pt*np.array(g['pitch'], np.float)+np.array(g['pos'], np.float) + else: + ox, oy=(0,0) + px, py=(1,1) + self.mot_pts=(np.hstack((pt, np.ones((pt.shape[0], 1))))*np.asmatrix(trf)).A # pt*trf + sx,sy=kwargs['ssz'] #section size (in wells) + try: + tsx,tsy=kwargs['smv'] #time(in num of shots) to move to next section (horiz/vert) + except KeyError as e: + tsx=sx-1 + tsy=sy + try: + tsd=kwargs['sdelay'] + except KeyError as e: + tsd=sx*sy + tsd+=1-sx*sy # sdl are shots to wait at position #(6) + prg+=f' linear abs\n X{ox-px:g} Y{oy-py:g}\n' # start one position out of grid + prg+=' dwell 10\n' + try: prg+=self.sync_prg + except AttributeError: + #print('no sync code available') + prg+=' Gather.Enable=2\n' + if cnt>1: + prg+=' P100=%d\n'%cnt + prg+='N100:\n' + if mode in (1,3): + prg+=f'''\ //mode {mode}: pvt motion with each point in program code pvt{pt2pt_time} abs ''' - for idx in range(1,pv.shape[0]): - #prg+=f'N{idx} ' + 'X%g:%g Y%g:%g\n'%tuple(pv[idx,(0,2,1,3)]) - prg+=f' X%g:%g Y%g:%g\n'%tuple(pv[idx, (0, 2, 1, 3)]) - prg+=f' X{pv[-1, 0]:g} Y{pv[-1, 1]:g}\n' - elif mode==4: - if scan==0: - raise Exception('scan=0 not supported') - pass - else: # scan=1 - vx=px/(pt2pt_time)*scale*CoordFeedTime #scaling for Deltatau - vy=py/(pt2pt_time)*scale*CoordFeedTime #scaling for Deltatau - prg+=f'''\ + for idx in range(1,pv.shape[0]): + #prg+=f'N{idx} ' + 'X%g:%g Y%g:%g\n'%tuple(pv[idx,(0,2,1,3)]) + prg+=f' X%g:%g Y%g:%g\n'%tuple(pv[idx, (0, 2, 1, 3)]) + prg+=f' X{pv[-1, 0]:g} Y{pv[-1, 1]:g}\n' + elif mode==4: + if scan==0: + raise Exception('scan=0 not supported') + pass + else: # scan=1 + vx=px/(pt2pt_time)*scale*CoordFeedTime #scaling for Deltatau + vy=py/(pt2pt_time)*scale*CoordFeedTime #scaling for Deltatau + prg+=f'''\ //mode 4: grid pvt motion pvt{pt2pt_time} abs L1=0 //slow loop x @@ -934,22 +945,22 @@ class ShapePath(MotionBase): X({ox}+L1*{px}):{0:g} Y({oy}+L0*{py}):{0:g} ''' - elif mode==5: - if scan==0: - raise Exception('scan=0 not supported') - pass - else: # scan=1 - if meta['sync_mode']==2: - _log.error('sync_mode=2 not allowed for stop-and-go motion !') - tmove=kwargs['tmove'] - twait=kwargs['twait'] - fel_per=meta['fel_per'] - pt2tp_felpulse=round((tmove+twait)/fel_per) # number of fel-pulses for a whole cycle (tmove+twait) - meta['pt2pt_time']=fel_per*pt2tp_felpulse - twait_=round((tmove+twait)/fel_per)*fel_per-tmove - if twait!=twait_: - _log.warning(f'adjust twait({twait}) to {twait_} to match multiple of fel-cycles') - syncPlc=f'''\ + elif mode==5: + if scan==0: + raise Exception('scan=0 not supported') + pass + else: # scan=1 + if meta['sync_mode']==2: + _log.error('sync_mode=2 not allowed for stop-and-go motion !') + tmove=kwargs['tmove'] + twait=kwargs['twait'] + fel_per=meta['fel_per'] + pt2tp_felpulse=round((tmove+twait)/fel_per) # number of fel-pulses for a whole cycle (tmove+twait) + meta['pt2pt_time']=fel_per*pt2tp_felpulse + twait_=round((tmove+twait)/fel_per)*fel_per-tmove + if twait!=twait_: + _log.warning(f'adjust twait({twait}) to {twait_} to match multiple of fel-cycles') + syncPlc=f'''\ close all buffers disable plc 2 open plc 2 @@ -967,8 +978,8 @@ open plc 2 close enable plc 2 ''' - comm.gpascii.send_block(syncPlc, verb&0x08) - prg+=f'''\ + if comm: comm.gpascii.send_block(syncPlc, verb&0x08) + prg+=f'''\ //mode 5: grid pvt motion pvt{tmove} abs L1=0 //slow loop x @@ -1023,31 +1034,31 @@ enable plc 2 while(Sys.Udata[2]==Sys.Udata[1]){{}};Sys.Udata[2]=Sys.Udata[1] // wait motion trigger ''' - elif mode==6: - if scan==0: - raise Exception('scan=0 not supported') - pass - else: # scan=1 - vsx=px/(pt2pt_time)*scale*CoordFeedTime # scaling for Deltatau - vsy=py/(pt2pt_time)*scale*CoordFeedTime # scaling for Deltatau + elif mode==6: + if scan==0: + raise Exception('scan=0 not supported') + pass + else: # scan=1 + vsx=px/(pt2pt_time)*scale*CoordFeedTime # scaling for Deltatau + vsy=py/(pt2pt_time)*scale*CoordFeedTime # scaling for Deltatau - #g=kwargs['grid'] - #ox,oy=g['pos'] #origin position in um (or counts if scaled) - #px,py=g['pitch'] #pitch to next position in um (or 1 if scaled) - #nx,ny=g['count'] #total count of wells - #sx,sy=kwargs['ssz'] #section size (in wells) - #tsx, tsy, tsd #time scale to pvt move to (next horiz|next vert| after position #6) - tx,ty=nx//sx,ny//sy #total sections + #g=kwargs['grid'] + #ox,oy=g['pos'] #origin position in um (or counts if scaled) + #px,py=g['pitch'] #pitch to next position in um (or 1 if scaled) + #nx,ny=g['count'] #total count of wells + #sx,sy=kwargs['ssz'] #section size (in wells) + #tsx, tsy, tsd #time scale to pvt move to (next horiz|next vert| after position #6) + tx,ty=nx//sx,ny//sy #total sections - #variables - cx,cy,dx,dy,n,k,t,vx,vy,x,x0,y,y0=map(lambda x: f'L{x}',range(13)) - # replace in python code of hit_and_return.py setup_motion: - # (cx|cy|dx|dy|n|k|sx|sy|tsd|tsx|tsy|tx|ty|vsx|vsy|vx|vy|x|x0|y|y0) -> {\1} - # if ([^:]*): -> if \(\1\){{ - # else: -> }}else{{ - # elif ([^:]*): -> }}else if \(\1\){{ + #variables + cx,cy,dx,dy,n,k,t,vx,vy,x,x0,y,y0=map(lambda x: f'L{x}',range(13)) + # replace in python code of hit_and_return.py setup_motion: + # (cx|cy|dx|dy|n|k|sx|sy|tsd|tsx|tsy|tx|ty|vsx|vsy|vx|vy|x|x0|y|y0) -> {\1} + # if ([^:]*): -> if \(\1\){{ + # else: -> }}else{{ + # elif ([^:]*): -> }}else if \(\1\){{ - prg+=f'''\ + prg+=f'''\ //mode 6: hit-and-return pvt motion {t}=1 // motion pvt tome scaling @@ -1143,11 +1154,9 @@ enable plc 2 }} ''' - else: - raise ValueError('unsupported mode') - #common code to repeat the motion multiple times - if cnt>1: - prg+=f'''\ + #common code to repeat the motion multiple times + if cnt>1: + prg+=f'''\ dwell 10 P100=P100-1 f(P100>0) @@ -1157,9 +1166,8 @@ f(P100>0) dwell {dwell} goto 100 }}\n''' - else: - prg+=f' dwell {dwell}\n Gather.Enable=0\nclose\n' - #prg+='&1\nb%dr\n'%prgId) + else: + prg+=f' dwell {dwell}\n Gather.Enable=0\nclose\n' if verb&0x02: DebugPlot.plot_points(self.mot_pts)