diff --git a/hit_return.svg b/hit_return.svg
new file mode 100644
index 0000000..38c0131
--- /dev/null
+++ b/hit_return.svg
@@ -0,0 +1,3600 @@
+
+
+
+
diff --git a/python/hit_return_evaluation.py b/python/hit_return_evaluation.py
new file mode 100755
index 0000000..3501a9f
--- /dev/null
+++ b/python/hit_return_evaluation.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python
+# *-----------------------------------------------------------------------*
+# | |
+# | Copyright (c) 2024 by Paul Scherrer Institute (http://www.psi.ch) |
+# | |
+# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
+# *-----------------------------------------------------------------------*
+'''
+hit and return motion simulation
+'''
+
+import logging
+_log=logging.getLogger(__name__)
+
+import os, sys, time, re
+import numpy as np
+import matplotlib.pyplot as plt
+
+
+class HitReturnEval:
+
+ def initPlt(self,grid):
+ cx,cy=grid['count']
+ fig=plt.figure()
+ ax = fig.add_subplot(1,1,1)
+ #ax.invert_xaxis()
+ ax.invert_yaxis()
+ #hl=ax[0].plot(x, y, color=col)
+ pts=np.array(((0,0),(cx-1,0),(cx-1,cy-1),(0,cy-1),(0,0)))
+ h3=ax.plot(pts[:,0],pts[:,1],'g-')
+ h2=ax.plot(pts[:,0],pts[:,1],'y-')
+ h1=ax.plot(pts[:,0],pts[:,1],'r.')
+ #cid = fig.canvas.mpl_connect('button_press_event', self.onclick)
+ #fig.obj=self
+ plt.axis('equal')
+ plt.ion()
+ fig.show()
+ self._plt=(fig,ax,h1[0],h2[0])
+
+ def updatePlt(self,pts):
+ fig, ax, h1, h2=self._plt
+ pts=np.array(pts)
+ h1.set_xdata((pts[:,0]))
+ h1.set_ydata((pts[:,1]))
+ h2.set_xdata((pts[:,0]))
+ h2.set_ydata((pts[:,1]))
+ plt.draw()
+ plt.pause(.01)
+ #fig.show()
+ #fig.update()
+
+ def setup_motion(self,prgId=2,fnPrg=None,mode=0,**kwargs):
+ #vgrid: grid parameters: {orig:(0,0),pitch(10,10),cnt:(10,10),mode:0}
+ #vp0: x/y koordinates of well to start (default 0,0)
+ #vsz: size of wells to cycle (must be 2n x m)
+ grid=kwargs['grid']
+ ox, oy=grid['pos'] #origin position in um (or counts if scaled)
+ px, py=grid['pitch'] #pitch to next position in um (or 1 if scaled)
+ cx,cy=grid['count'] #total count of wells
+ rx,ry=kwargs['sz'] #region size of wells (sign shows direction)
+ #fast y (up/down) slow x(left/right)
+ # 8
+ # 7 8 8
+ # 6 7 7
+ # 0-5 0-6---5 0-6-------5
+ # | | | 3-4 | | 3-4 3-4 |
+ # | | | | | | | | | | | |
+ # | | | | | | | | | | | |
+ # | | | | | | | | | | | |
+ # 1-2 1-2 1-2 1-2 1-2 1-2
+
+ m=0
+ x0,y0,n=0,-1,0 # counter well in region
+ dx,dy=0,1 # motion pitch
+ x1,y1=0,0 #counter region start
+ mv=list()
+ while(True):
+ x0+=dx;y0+=dy
+ print(f'{x0+x1} {y0+y1} ({dx}|{dy}|{n})')
+ mv.append((x0+x1+.1*n,y0+y1+.1*n,n))
+ self.updatePlt(mv)
+ if y0==ry-1:
+ if dy==1: #(1)
+ dx,dy=1,0
+ else:
+ dx,dy=0,-1#(2)
+ elif y0==1 and x0 0:
+ hl += ax.plot(rec[idxTrigger, 1], rec[idxTrigger, 0], 'xr', label='trig') # actual path
+ hl2 += ax2.plot(rec[:, 4]*10, 'b-', label='trigger')
+
+ ax.xaxis.set_label_text('x-pos um')
+ ax.yaxis.set_label_text('y-pos um')
+ ax.axis('equal')
+ ax.legend(loc='best')
+ # cid = fig.canvas.mpl_connect('button_press_event', self.onclick)
+ # fig.obj=self
+ ax2.legend(loc='best')
+ plt.show(block=False)
+
+from optparse import OptionParser, IndentedHelpFormatter
+if __name__=='__main__':
+ logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ')
+ import argparse
+
+ def parse_args():
+ 'main command line interpreter function'
+ (h, t)=os.path.split(sys.argv[0]);cmd='\n '+(t if len(h)>3 else sys.argv[0])+' '
+ exampleCmd=('-v0xff',
+ '--host=SAR-CPPM-EXPMX1 -v0x5d',
+ '--host=localhost:10001:10002 -v0x59',
+ '--host=SAR-CPPM-EXPMX1 -v0x5d -m5',
+ )
+ epilog=__doc__+'\nExamples:'+''.join(map(lambda s:cmd+s, exampleCmd))+'\n '
+ parser=argparse.ArgumentParser(epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter)
+ parser.add_argument("-m", "--mode", type=lambda x:int(x, 0), help="mode default=0x%(default)x", default=4)
+ parser.add_argument("-s", "--sync", type=lambda x:int(x, 0), help="sync default=0x%(default)x", default=2)
+ parser.add_argument('-v', '--verbose', type=lambda x:int(x, 0), dest='verbose', help='verbosity bits (see below) default=0x%(default)x', default=0x00)
+ parser.add_argument('--host', help='hostname', default=None)
+
+ args=parser.parse_args()
+ _log.info('Arguments:{}'.format(args.__dict__))
+
+ obj=HitReturnEval()
+ grid={'pos':(-1000, -1200), 'pitch':(120, 120), 'count':(20, 25)}
+ grid={'pos':(0, 0), 'pitch':(1, 1), 'count':(16, 20)}
+ obj.initPlt(grid)
+ obj.setup_motion(grid=grid,p0=(0,0),sz=(4,5))
+ obj.initPlt(grid)
+ obj.setup_motion(grid=grid,p0=(0,0),sz=(6,10))
+ obj.initPlt(grid)
+ obj.setup_motion(grid=grid,p0=(0,0),sz=(2,5))
+ print('done')
+
+#------------------ Main Code ----------------------------------
+
+ #dp=DebugPlot('/tmp/shapepath.npz');dp.plot_gather(mode=11);plt.show()
+ #exit(0)
+ #ssh_test()
+ ret=parse_args()
\ No newline at end of file
diff --git a/python/shapepath.py b/python/shapepath.py
index 9718cf7..c664352 100755
--- a/python/shapepath.py
+++ b/python/shapepath.py
@@ -730,6 +730,13 @@ class ShapePath(MotionBase):
tmove: time to move in ms (move start on FEL-trigger
twait: 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}
+ p0: x/y koordinates of well to start (must be 2n x 2m)
+ sz: size of wells to cycle
+
'''
#scan=0 # snake motion X fast, Y slow
scan=1 # snake motion Y fast, X slow (default)