class Shape(object): def __init__(self,profile,eqconf='unset',sep='unset',**kwargs): self.ny = kwargs.get('ny',3) # TF filament number (y-dir) self.alpha = kwargs.get('alpha',1-1e-4) self.color = cycle(sns.color_palette('Set2',10)) self.profile = profile self.loop = self.profile.loop self.bound = {} # initalise bounds self.bindex = {'internal':[0],'interior':[0],'external':[0]} # index for side in ['internal','interior','external']: self.bound[side] = {'r':[],'z':[]} if side in kwargs: self.add_bound(kwargs[side],side) if self.profile.nTF is not 'unset' and \ (eqconf is not 'unset' or sep is not 'unset'): if eqconf is not 'unset': plasma = {'config':eqconf} sf = SF(Setup(eqconf).filename) self.tf = TF(profile=self.profile,sf=sf) else: plasma = {'r':sep['r'],'z':sep['z']} self.tf = TF(profile=self.profile) self.cage = coil_cage(nTF=self.profile.nTF,rc=self.tf.rc, plasma=plasma,ny=self.ny,alpha=self.alpha) x = self.tf.get_loops(self.loop.draw()) self.cage.set_TFcoil(x['cl'],smooth=False) else: if self.profile.obj is 'E': errtxt = 'nTF and SFconfig keywords not set\n' errtxt += 'unable to calculate stored energy\n' errtxt += 'initalise with \'nTF\' keyword' raise ValueError(errtxt) def add_bound(self,x,side): for var in ['r','z']: self.bound[side][var] = np.append(self.bound[side][var],x[var]) self.bindex[side].append(len(self.bound[side]['r'])) def add_interior(self,r_gap=0.001): # offset minimum internal radius argmin = np.argmin(self.bound['internal']['r']) self.add_bound({'r':self.bound['internal']['r'][argmin]-r_gap, 'z':self.bound['internal']['z'][argmin]}, 'interior') def add_vessel(self,vessel,npoint=80,offset=[0.12,0.2]): rvv,zvv = geom.rzSLine(vessel['r'],vessel['z'],npoint) rvv,zvv = geom.offset(rvv,zvv,offset[1]) rmin = np.min(rvv) rvv[rvv<=rmin+offset[0]] = rmin+offset[0] self.add_bound({'r':rvv,'z':zvv},'internal') # vessel self.add_bound({'r':np.min(rvv)-5e-3,'z':0},'interior') # vessel def clear_bound(self): for side in self.bound: for var in ['r','z']: self.bound[side][var] = np.array([]) def plot_bounds(self): for side,marker in zip(['internal','interior','external'], ['.-','d','s']): index = self.bindex[side] for i in range(len(index)-1): pl.plot(self.bound[side]['r'][index[i]:index[i+1]], self.bound[side]['z'][index[i]:index[i+1]], marker,markersize=6,color=next(self.color)) def minimise(self,verbose=False,ripple_limit=0.6,ripple=False,acc=0.002): tic = time.time() xnorm,bnorm = set_oppvar(self.loop.xo,self.loop.oppvar) # normalize xnorm = fmin_slsqp(self.fit,xnorm,f_ieqcons=self.constraint_array, bounds=bnorm,acc=acc,iprint=-1, args=(False,ripple_limit)) if ripple: # re-solve with ripple constraint if self.profile.nTF == 'unset': raise ValueError('requre \'nTF\' to solve ripple constraint') print('with ripple') xnorm = fmin_slsqp(self.fit,xnorm,f_ieqcons=self.constraint_array, bounds=bnorm,acc=acc,iprint=-1, args=(True,ripple_limit)) xo = get_oppvar(self.loop.xo,self.loop.oppvar,xnorm) # de-normalize if hasattr(self,'tf'): x = self.tf.get_loops(self.loop.draw(x=xo)) # update tf self.cage.set_TFcoil(x['cl']) # update coil cage self.loop.set_input(x=xo) # inner loop self.profile.write() # store loop if verbose: self.toc(tic) def toc(self,tic): print('optimisation time {:1.1f}s'.format(time.time()-tic)) print('noppvar {:1.0f}'.format(len(self.loop.oppvar))) if self.profile.nTF is not 'unset': self.cage.output() def constraint_array(self,xnorm,*args): ripple,ripple_limit = args xo = get_oppvar(self.loop.xo,self.loop.oppvar,xnorm) # de-normalize if ripple: # constrain ripple contour x = self.tf.get_loops(self.loop.draw(x=xo)) #npoints dot = np.array([]) for side,key in zip(['internal','interior','external'], ['in','in','out']): dot = np.append(dot,self.dot_diffrence(x[key],side)) self.cage.set_TFcoil({'r':x['cl']['r'],'z':x['cl']['z']}) max_ripple = self.cage.get_ripple() edge_ripple = self.cage.edge_ripple(npoints=10) dot = np.append(dot,ripple_limit-edge_ripple) dot = np.append(dot,ripple_limit-max_ripple) else: # without tf object (no ripple or energy) x = self.loop.draw(x=xo) dot = self.dot_diffrence(x,'internal') dot = np.append(dot,self.dot_diffrence(x,'interior')) return dot def fit(self,xnorm,*args): xo = get_oppvar(self.loop.xo,self.loop.oppvar,xnorm) # de-normalize if hasattr(self,'xo'): self.xo = np.vstack([self.xo,xo]) else: self.xo = xo x = self.loop.draw(x=xo) if self.profile.obj is 'L': # coil length objF = geom.length(x['r'],x['z'],norm=False)[-1] elif self.obj is 'E': # stored energy x = self.tf.get_loops(x=x) self.cage.set_TFcoil(x['cl']) objF = 1e-9*self.cage.energy() else: # coil volume objF = geom.loop_vol(x['r'],x['z']) return objF def dot_diffrence(self,x,side): Rloop,Zloop = x['r'],x['z'] # inside coil loop switch = 1 if side is 'internal' else -1 nRloop,nZloop,Rloop,Zloop = geom.normal(Rloop,Zloop) R,Z = self.bound[side]['r'],self.bound[side]['z'] dot = np.zeros(len(R)) for j,(r,z) in enumerate(zip(R,Z)): i = np.argmin((r-Rloop)**2+(z-Zloop)**2) dr = [Rloop[i]-r,Zloop[i]-z] dn = [nRloop[i],nZloop[i]] dot[j] = switch*np.dot(dr,dn) return dot def movie(self,filename): fig,ax = pl.subplots(1,2,figsize=(12,8)) demo = DEMO() moviename = '../Movies/{}'.format(filename) moviename += '.mp4' FFMpegWriter = manimation.writers['ffmpeg'] writer = FFMpegWriter(fps=20, bitrate=5000,codec='libx264', extra_args=['-pix_fmt','yuv420p']) with writer.saving(fig,moviename,100): nS = len(self.xo) to = time.time() width = 35 for i,xo in enumerate(self.xo): self.frame(ax,demo,xo) writer.grab_frame() if i%1 == 0 and i > 0: elapsed = time.time()-to remain = int((nS-i)/i*elapsed) prog_str = '\r{:1.0e}'.format(i) prog_str += ' elapsed {:0>8}s'.format(str(\ datetime.timedelta(seconds=int(elapsed)))) prog_str += ' remain {:0>8}s'.format(str(\ datetime.timedelta(seconds=remain))) prog_str += ' complete {:1.1f}%'.format(1e2*i/nS) nh = int(i/nS*width) prog_str += ' |'+nh*'#'+(width-nh)*'-'+'|' sys.stdout.write(prog_str) sys.stdout.flush() def frames(self,filename): fig,ax = pl.subplots(1,2,figsize=(12,8)) demo = DEMO() figname = '../Figs/{}'.format(filename) self.frame(ax,demo,xo=self.xo[0]) pl.savefig(figname+'_s.png') self.frame(ax,demo,xo=self.xo[-1]) pl.savefig(figname+'_e.png') def frame(self,ax,demo,**kwargs): xo = kwargs.get('xo',self.xo[-1]) pl.sca(ax[0]) #pl.cla() pl.plot([3,18],[-10,10],'ko',alpha=0) demo.fill_part('Blanket') demo.fill_part('Vessel') self.loop.set_input(x=xo) #self.plot_bounds() self.update() #self.tf.fill() geom.polyfill(self.cage.plasma_loop[:,0], self.cage.plasma_loop[:,2], alpha=0.3,color=sns.color_palette('Set2',5)[3]) #self.cage.plot_loops(sticks=False) if len(ax) > 1: pl.sca(ax[1]) pl.cla() plot_oppvar(shp.loop.xo,shp.loop.oppvar)
palette='Set2', font_scale=7 / 8, rc=rc) color = sns.color_palette('Set2') demo = DEMO() demo.fill_loops() config = 'DEMO_SN' tf = TF(config, coil_type='S', npoints=80) #tf.coil.set_input(inputs={'upper':0.8,'top':0.5}) x = tf.coil.draw() tf.get_loops(x) tf.fill() cage = coil_cage(nTF=18, rc=tf.rc, plasma={'config': config}, coil={'cl': tf.x['cl']}) tic = time.time() print('ripple {:1.3f}%'.format(cage.get_ripple())) print('time {:1.3f}s'.format(time.time() - tic)) print(cage.edge_ripple()) #tf.coil.set_input() tic = time.time()