From baef7cdb9ee10ae2344a8d46b8f3e6808c8c5f16 Mon Sep 17 00:00:00 2001 From: Thierry Zamofing Date: Fri, 12 Oct 2018 16:08:24 +0200 Subject: [PATCH] towards using gather and ppc in shapepath --- matlab/Readme.md | 1 + matlab/SCRATCH.m | 45 +++++--- python/MXMotion.py | 38 +++++++ python/shapepath.py | 246 +++++++++++++++++++++++++------------------- 4 files changed, 209 insertions(+), 121 deletions(-) create mode 100644 python/MXMotion.py diff --git a/matlab/Readme.md b/matlab/Readme.md index 0657688..5d2d6bd 100644 --- a/matlab/Readme.md +++ b/matlab/Readme.md @@ -29,6 +29,7 @@ close all; [pb]=simFxFyStage(mot1,1); [ssc]=StateSpaceControlDesign(mot1,1); +[mot1,mot2]=identifyFxFyStage(); [pb]=simFxFyStage(mot2,2); [ssc]=StateSpaceControlDesign(mot2,2); diff --git a/matlab/SCRATCH.m b/matlab/SCRATCH.m index 4d2ff3c..84c0d41 100644 --- a/matlab/SCRATCH.m +++ b/matlab/SCRATCH.m @@ -1,19 +1,38 @@ -raw=desPos_actPos.Data -raw(:,2)=raw(:,1)*100 -ft=fft(raw); -plot(log(abs(ft))); -plot(log(abs(ft(:,1)./ft(:,2)))); +https://de.wikipedia.org/wiki/Chirp - i=int(minFrq*tSec); j=int(maxFrq*tSec); #print(w[i],w[j]) +# amp, minFrq, maxFrq, tSec = (10, 10, 300, 30) +import numpy as np +import matplotlib as mpl +import matplotlib.pyplot as plt +x=np.arange(1,300000) +y=10*np.sin(31.415926535897931*( pow(1.058324104020218,(x*0.000199996614513)) -1) /np.log(1.058324104020218)) +plt.show() +plt.plot(x,y) +plt.show() +y=amp*sin( a* (b**(x*c))-1) / log(d) ) + =amp*sin( a/log(d)* (b**(x*c))-1) ) -x=2+3j -rho=abs(x) -theta=angle(x) -%------------------- -x=rho*exp(j*theta) +0.000199996614513=samplingrate in sec. (gatherPeriod==1?) +31.415926535897931 = pi*10 =? 2*pi*f0 +1.058324104020218 = k +x*0.000199996614513 =t +1.058324104020218**60 = 30 +sin( 2*pi*f0/ln(k)*(k**t-1) ) +f(t)=f0*k**t = f0*e**(t*ln(k)) + +k**t=30 (from 10 to 300 -> 300/10=30) + +log(k**t)=log(30) +log(k)*t=log(30) +log(k)=log(30)*(1/t) +log(k)=log(30**(1/t)) +k=30**(1/t) +30**(1/60.) = 1.0583241040202176 + +----------------------------------------------------------------- figure(); @@ -21,10 +40,6 @@ x=rho*exp(j*theta) setoptions(h,'FreqUnits','Hz','Grid','on');legend('location','sw'); - - - - %figure();bode(ssc.ss_o(3)); %figure();tf=tf(ssc.ss_o) pzplot(tf(3)); diff --git a/python/MXMotion.py b/python/MXMotion.py new file mode 100644 index 0000000..51d5d02 --- /dev/null +++ b/python/MXMotion.py @@ -0,0 +1,38 @@ +import os, sys +sys.path.insert(0,os.path.expanduser('~/Documents/prj/SwissFEL/PBTools/')) +#import pbtools.misc.pp_comm as pp_comm -> pp_comm.PPComm +from pbtools.misc.pp_comm import PPComm +from pbtools.misc.gather import Gather + + +class MotionBase: + def __init__(self, comm, gather, verbose): + self.comm=comm + self.gather=gather + self.verbose=verbose + + def wait_trigger(self): + ''' + //changes the Timebase of coord system 1 + + //modifies the timebase to start/stop a running program + //this can also be used to adjust the execution speed + + open plc 1 + Coord[1].DesTimeBase=0 // freezes timebase at boot + while(1) + { + if(PowerBrick[0].GpioData[0].0.1==1) + { + PowerBrick[0].GpioData[0].16.8=255 + Coord[1].DesTimeBase=Sys.ServoPeriod + } + else + { + PowerBrick[0].GpioData[0].16.8=7 + Coord[1].DesTimeBase=0 + } + } + close + ''' + pass \ No newline at end of file diff --git a/python/shapepath.py b/python/shapepath.py index 5c624bb..227e1ef 100755 --- a/python/shapepath.py +++ b/python/shapepath.py @@ -49,65 +49,33 @@ Sequencer functions are: Acquired time is:MaxSamples*Period*.2 ''' - -import os, sys, json +from __future__ import print_function +import os, sys, time import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt -import subprocess as sprc -import telnetlib -class ShapePath: - def __init__(self,args): - if args.cfg: - fh=open(args.cfg,'r') - s=fh.read() - cfg=json.loads(s, object_hook=ConvUtf8) - s=json.dumps(cfg, indent=2, separators=(',', ': '));print(s) - else: - fn='/tmp/shapepath4' - #fn='/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/data/'+time.strftime('%y-%m-%d-%H_%M_%S') - #cfg={"points": [[100,523],[635,632],[756,213]],"sequencer":['sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1")','plot_gather("'+fn+'.npz")']} - #cfg={"sequencer":['gen_rand_points(n=107, scale=1000)','sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1")','plot_gather("'+fn+'.npz")']} - #cfg={"sequencer":['gen_grid_points(w=10,h=10,pitch=100,rnd=.2)','sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1")','plot_gather("'+fn+'.npz")']} - #cfg={"sequencer":['gen_grid_points(w=10,h=10,pitch=100,rnd=0.2)','sort_points()','gen_prog(file="'+fn+'.prg")','plot_gather("'+fn+'.npz")']} - #cfg = {"sequencer": ['gen_rand_points(n=107, scale=1000)', 'sort_points()','plot_gather("'+fn+'.npz")']} - #cfg={"sequencer":['gen_grid_points(w=20,h=20,pitch=50,rnd=.2)','sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1")','plot_gather("'+fn+'.npz")']} - #cfg={"sequencer":['gen_grid_points(w=20,h=20,pitch=50,rnd=.2)','sort_points()','gen_prog(file="'+fn+'.prg")','plot_gather("'+fn+'.npz")']} - #cfg={"sequencer":['gen_rand_points(n=400, scale=1000)','sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1")','plot_gather("'+fn+'.npz")']} - #cfg = {"sequencer": ['gen_grid_points(w=20,h=20,pitch=50,rnd=.2)', 'sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=0)', 'plot_gather("'+fn+'.npz")']} - #cfg = {"sequencer": ['gen_grid_points(w=5,h=5,pitch=50,rnd=.2)', 'sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=1)', 'plot_gather("'+fn+'.npz")']} - #cfg = {"sequencer": ['gen_grid_points(w=2,h=2,pitch=100,rnd=0)', 'sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=0)', 'plot_gather("'+fn+'.npz")']} - #cfg = {"sequencer": ['gen_grid_points(w=5,h=5,pitch=100,rnd=0.2)', 'sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=0)', 'plot_gather("'+fn+'.npz")']} - #cfg = {"points": [[0, 0],[100, 0],[200, 0],[300, 0],[400, 0],[400, 100],[300, 100],[200, 100],[100, 100],[0, 100],[10, 200],[100, 200],[200, 200],[300, 200],[400, 200],[410, 300],[300, 300],[200, 300],[100, 300],[0, 300],[0, 400],[100, 400],[200, 400],[300, 400],[400, 400]],"sequencer": ['gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=0)', 'plot_gather("'+fn+'.npz")']} - #cfg = {"sequencer": ['gen_grid_points(w=2,h=2,pitch=10000,rnd=0)', 'sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=-1)', 'plot_gather("'+fn+'.npz")']} - #cfg = {"sequencer": ['gen_grid_points(w=2,h=2,pitch=10000,rnd=0)', 'sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=1,pt2pt_time=1000)', 'plot_gather("'+fn+'.npz")']} - #cfg = {"sequencer": ['gen_grid_points(w=20,h=20,pitch=50,rnd=0.2)', 'sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=1,pt2pt_time=10,acq_per=10)', 'plot_gather("'+fn+'.npz")']} - #cfg = {"sequencer": ['gen_rand_points(n=400, scale=1000)', 'sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=1,pt2pt_time=10)', 'plot_gather("'+fn+'.npz")']} - cfg = {"sequencer": ['gen_grid_points(w=40,h=40,pitch=100,rnd=0.4)', 'sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=1,pt2pt_time=10,cnt=1)', 'plot_gather("'+fn+'.npz")']} - cfg = {"sequencer":['gen_rand_points(n=900, scale=1000)','sort_points()','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=1,pt2pt_time=40,acq_per=10)','plot_gather("'+fn+'.npz")']} - #cfg = {"sequencer": ['gen_swissfel_points(scale=300)','gen_prog(file="'+fn+'.prg",host="SAR-CPPM-EXPMX1",mode=1,pt2pt_time=100,acq_per=10)', 'plot_gather("'+fn+'.npz")']} - #cfg = {"sequencer": ['opt_pts("'+fn+'.npz")','gen_prog(file="'+fn+'_corr.prg",host="SAR-CPPM-EXPMX1",mode=1,pt2pt_time=10,cnt=1)', 'plot_gather("'+fn+'_corr.npz")']} - #cfg = {"sequencer": ['opt_pts("'+fn+'.npz")','gen_prog(file="'+fn+'.prg",mode=1,pt2pt_time=10,cnt=1)']} +sys.path.insert(0,os.path.expanduser('~/Documents/prj/SwissFEL/PBTools/')) +from pbtools.misc.pp_comm import PPComm +from pbtools.misc.gather import Gather +from MXMotion import MotionBase - #cfg = {"sequencer": ['gen_grid_points(w=5,h=5,pitch=100,rnd=0.4)', 'sort_points()','gen_prog(file="'+fn+'.prg",mode=1,pt2pt_time=10,cnt=1)']} - self.cfg=dotdict(cfg) - self.args=args +class ShapePath(MotionBase): + def __init__(self,comm, gather, verbose): + MotionBase.__init__(self,comm, gather, verbose) - def run(self): - print('args='+str(self.args)) - print('cfg='+str(self.cfg)) + def run_test(self,cfg,dryrun=False): + print('cfg='+str(cfg)) try: - self.points=np.array(self.cfg.points) - except AttributeError: + self.points=np.array(cfg['points']) + except KeyError: pass try: - sequencer= self.cfg.pop('sequencer') + sequencer= cfg['sequencer'] except KeyError: print('no command sequence to execute') else: - dryrun=self.args.dryrun for cmd in sequencer: print('>'*5+' '+cmd+' '+'<'*5) if not dryrun: @@ -127,7 +95,7 @@ class ShapePath: pts*=scale self.points=pts - verb=self.args.verbose + verb=self.verbose if verb&2: self.plot_points(pts) plt.show() @@ -167,28 +135,27 @@ class ShapePath: self.ptsCorr=ptsCorr print(ptsCorr) - def gen_prog(self,prgId=2,file=None,host=None,mode=0,**kwargs): + def move_trajectory(self,prgId=2,fnPrg=None,mode=0,**kwargs): ''' + 1. generates program and saves to fnPrg + the type of generated program is defined by + 2. runs the program on the deltatau kwargs: acq_per : acquire period: acquire data all acq_per servo loops (default=1) pt2pt_time : time to move from one point to the next point ''' - prg=[] - acq_per=kwargs.get('acq_per',1) - gather={"MaxSamples":1000000, "Period":acq_per} - #Sys.ServoPeriod is dependent of !common() macro + gt=self.gather + comm=self.comm + acq_per=kwargs.get('acq_per', 1) ServoPeriod= .2 #0.2ms - #ServoPeriod = .05 - self.meta = {'timebase': ServoPeriod*gather['Period']} - #channels=["Motor[1].ActPos","Motor[2].ActPos","Motor[3].ActPos"] - channels=["Motor[3].ActPos","Motor[2].ActPos","Motor[1].ActPos","Motor[3].DesPos","Motor[2].DesPos","Motor[1].DesPos"] - prg.append('Gather.Enable=0') - prg.append('Gather.Items=%d'%len(channels)) - for k,v in gather.iteritems(): - prg.append('Gather.%s=%d'%(k,v)) - for i,c in enumerate(channels): - prg.append('Gather.Addr[%d]=%s.a'%(i,c)) + if gt: + gt.set_phasemode(False) + gt.set_address('Motor[3].ActPos','Motor[2].ActPos','Motor[1].ActPos','Motor[3].DesPos','Motor[2].DesPos','Motor[1].DesPos') + gt.set_property(MaxSamples=1000000,Period=acq_per) + #gt.set_property(Period=acq_per) + prg=[] + self.meta = {'timebase': ServoPeriod*acq_per} prg.append('open prog %d'%(prgId)) # this uses Coord[1].Tm and limits with MaxSpeed @@ -293,39 +260,56 @@ class ShapePath: prg.append('close') prg.append('&1\nb%dr\n'%prgId) - if self.args.verbose & 4: + if self.verbose & 4: for ln in prg: print(ln) - if file is not None: - fh=open(file,'w') + if fnPrg is not None: + fh=open(fnPrg,'w') fh.write('\n'.join(prg)) fh.close() - if host is not None: - cmd ='gpasciiCommander --host '+host+' '+ file - print(cmd) - p = sprc.Popen(cmd, shell=True)#, stdout=sprc.PIPE, stderr=sprc.STDOUT) - #res=p.stdout.readlines(); print res - retval = p.wait() - #gather -u /var/ftp/gather/out.txt - cmd ='PBGatherPlot -m24 -v7 --host '+host - print(cmd) - p = sprc.Popen(cmd, shell=True)#, stdout=sprc.PIPE, stderr=sprc.STDOUT) - retval = p.wait() - self.prg=prg + if comm is not None: + gpascii=comm.gpascii + for ln in prg: + gpascii.send_line(ln.strip()) + gpascii.sync() - - def sort_points(self): + def gather_upload(self,fnRec=None): + gt=self.gather + comm=self.comm + if comm is None: + return + gpascii=comm.gpascii + #while True: #wait unti acquisition started + # samples=gpascii.get_variable('Gather.Samples', type_=int) + # enable=gpascii.get_variable('Gather.Enable', type_=int) + # if enable>0 and samples>0: + # break; + # time.sleep(.1) + # sys.stdout.flush() + gt.wait_stopped(verbose=True) + self.rec =rec = self.gather.upload() pts=self.points - verb=self.args.verbose - #if verb&2: - # self.plot_points(pts) + + #rec=Motor[1].ActPos,Motor[2].ActPos,Motor[3].ActPos,Motor[1].DesPos,Motor[2].DesPos,Motor[3].DesPos + #res=rot.ActPos,x.ActPos,y.ActPos,rot.DesPos,x.DesPos,y.DesPos + #idx 0 1 2 3 4 5 + ofsy=-rec[0,4]+pts[0,0] + ofsx=-rec[0,5]+pts[0,1] + rec[:,(1,4)]+=ofsy + rec[:,(2,5)]+=ofsx + if fnRec: + np.savez_compressed(fnRec, rec=rec, pts=pts, meta=self.meta) + + def sort_points(self,xy=False): + pts=self.points + verb=self.verbose cnt=pts.shape[0] idx=np.ndarray(cnt,dtype=np.int32) grp_cnt=int(np.sqrt(cnt)) grp_sz=int(np.ceil(float(cnt)/grp_cnt)) - if self.args.xy==True: + if xy==True: idxA=1;idxB=0 else: idxA=0;idxB=1 @@ -366,24 +350,14 @@ class ShapePath: self.ax=ax self.hl=hl - def plot_gather(self,fnOut='/tmp/shapepath.npz',fnLoc='/tmp/gather.txt'): - meta=self.meta - pts=self.points # X,Y array - rec = np.genfromtxt(fnLoc, delimiter=' ') - #rec=Motor[1].ActPos,Motor[2].ActPos,Motor[3].ActPos,Motor[1].DesPos,Motor[2].DesPos,Motor[3].DesPos - #res=rot.ActPos,x.ActPos,y.ActPos,rot.DesPos,x.DesPos,y.DesPos - #idx 0 1 2 3 4 5 - ofsy=-rec[0,4]+pts[0,0] - ofsx=-rec[0,5]+pts[0,1] - rec[:,(1,4)]+=ofsy - rec[:,(2,5)]+=ofsx - if fnOut: - # time base: - # Gather.Period=10 - # Sys.ServoPeriod=0.2 -> 5kHz - # -> aquired data all 10*0.2ms= 2 ms -> 30000 points = 60 sec - - np.savez_compressed(fnOut, rec=rec, pts=pts, meta=meta) + def plot_gather(self): + try: + meta=self.meta + pts=self.points # X,Y array + rec = self.rec + except AttributeError as e: + print('plot_gather(): '+str(e)+': no data acquired yet') + return fig=plt.figure() ax = fig.add_subplot(1,1,1) #hl=ax[0].plot(x, y, color=col) @@ -415,6 +389,67 @@ class ShapePath: plt.show() if __name__=='__main__': + #import logging + #logger = logging.getLogger(__name__) + #logger = logging.getLogger('pbtools.misc.pp_comm') + #logger.setLevel(logging.DEBUG) + #logging.basicConfig(format=('%(asctime)s %(name)-12s ' + # '%(levelname)-8s %(message)s'), + # datefmt='%m-%d %H:%M', + # ) + + def run_test(args): + if args.host is None: + comm=gather=None + else: + comm = PPComm(host=args.host) + gather = Gather(comm) + sp=ShapePath(comm, gather, args.verbose) + + fn='/tmp/shapepath' + # fn='/home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/data/'+time.strftime('%y-%m-%d-%H_%M_%S') + sort_points='sort_points(xy='+str(args.xy)+')' + gt_upld='gather_upload(fnRec="'+fn+'.npz")' + move_trj='move_trajectory(fnPrg="'+fn+'.prg"' + + # cfg={"points": [[100,523],[635,632],[756,213]],"sequencer":[sort_points,move_trj+')']} + cfg={"sequencer":['gen_rand_points(n=107, scale=1000)',sort_points,move_trj+')']} + # cfg={"sequencer":['gen_grid_points(w=10,h=10,pitch=100,rnd=.2)',sort_points,move_trj+')']} + # cfg={"sequencer":['gen_grid_points(w=10,h=10,pitch=100,rnd=0.2)',sort_points,move_trj+')']} + # cfg = {"sequencer": ['gen_rand_points(n=107, scale=1000)', sort_points]} + # cfg={"sequencer":['gen_grid_points(w=20,h=20,pitch=50,rnd=.2)',sort_points,move_trj+')']} + # cfg={"sequencer":['gen_grid_points(w=20,h=20,pitch=50,rnd=.2)',sort_points,move_trj+')']} + # cfg={"sequencer":['gen_rand_points(n=400, scale=1000)',sort_points,move_trj+')']} + # cfg = {"sequencer": ['gen_grid_points(w=20,h=20,pitch=50,rnd=.2)', sort_points,move_trj+',mode=0)',]} + # cfg = {"sequencer": ['gen_grid_points(w=5,h=5,pitch=50,rnd=.2)', sort_points,move_trj+',mode=1)',]} + # cfg = {"sequencer": ['gen_grid_points(w=2,h=2,pitch=100,rnd=0)', sort_points,move_trj+',mode=0)',]} + # cfg = {"sequencer": ['gen_grid_points(w=5,h=5,pitch=100,rnd=0.2)', sort_points,move_trj+',mode=0)',]} + # cfg = {"points": [[0, 0],[100, 0],[200, 0],[300, 0],[400, 0],[400, 100],[300, 100],[200, 100],[100, 100],[0, 100],[10, 200],[100, 200],[200, 200],[300, 200],[400, 200],[410, 300],[300, 300],[200, 300],[100, 300],[0, 300],[0, 400],[100, 400],[200, 400],[300, 400],[400, 400]],"sequencer": [move_trj+',mode=0)',]} + # cfg = {"sequencer": ['gen_grid_points(w=2,h=2,pitch=10000,rnd=0)', sort_points,move_trj+',mode=-1)',]} + # cfg = {"sequencer": ['gen_grid_points(w=2,h=2,pitch=10000,rnd=0)', sort_points,move_trj+',mode=1,pt2pt_time=1000)',]} + # cfg = {"sequencer": ['gen_grid_points(w=20,h=20,pitch=50,rnd=0.2)', sort_points,move_trj+',mode=1,pt2pt_time=10,acq_per=10)',]} + # cfg = {"sequencer": ['gen_rand_points(n=400, scale=1000)', sort_points,move_trj+',mode=1,pt2pt_time=10)',]} + #cfg={"sequencer": ['gen_grid_points(w=40,h=40,pitch=100,rnd=0.4)', sort_points, + # move_trj+',mode=1,pt2pt_time=10,cnt=1)', + # ]} + + # 900npoints is a too big code block... and creates unfixable buffe locks + cfg={"sequencer": ['gen_rand_points(n=100, scale=1000)', sort_points, + move_trj+',mode=1,pt2pt_time=40,acq_per=10)', + ]} + # cfg = {"sequencer": ['gen_swissfel_points(scale=300)',move_trj+',mode=1,pt2pt_time=100,acq_per=10)',]} + # cfg = {"sequencer": ['opt_pts("'+fn+'.npz")','move_trajectory(file="'+fn+'_corr.prg",mode=1,pt2pt_time=10,cnt=1)', ("'+fn+'_corr.npz")']} + # cfg = {"sequencer": ['opt_pts("'+fn+'.npz")',move_trj+',mode=1,pt2pt_time=10,cnt=1)']} + + # cfg = {"sequencer": ['gen_grid_points(w=5,h=5,pitch=100,rnd=0.4)', sort_points,move_trj+',mode=1,pt2pt_time=10,cnt=1)']} + + cfg['sequencer'].append(gt_upld) + cfg['sequencer'].append('plot_gather()') + sp.run_test(cfg,args.dryrun) + #self.cfg=dotdict(cfg) + #self.args=args + + from optparse import OptionParser, IndentedHelpFormatter class MyFormatter(IndentedHelpFormatter): 'helper class for formating the OptionParser' @@ -443,14 +478,13 @@ Examples:'''+''.join(map(lambda s:cmd+s, exampleCmd))+'\n ' parser.add_option('-v', '--verbose', type="int", dest='verbose', help='verbosity bits (see below)', default=0) parser.add_option('-n', '--dryrun', action='store_true', help='dryrun to stdout') - parser.add_option('--xy', action='store_true', help='sort x,y instead y,x') - parser.add_option('--cfg', help='config file containing json configuration structure') + parser.add_option('--xy', action='store_true', help='sort x,y instead y,x',default=False) + parser.add_option('--host', help='hostname', default='SAR-CPPM-EXPMX1') + #parser.add_option('--host', help='hostname') (args, other)=parser.parse_args() args.other=other - - sp=ShapePath(args) - sp.run() + run_test(args) #------------------ Main Code ---------------------------------- #ssh_test() ret=parse_args()