diff --git a/matlab/@espic2dhdf5/displayLarmorRad2Dwell.m b/matlab/@espic2dhdf5/displayLarmorRad2Dwell.m new file mode 100644 index 0000000..355fa6b --- /dev/null +++ b/matlab/@espic2dhdf5/displayLarmorRad2Dwell.m @@ -0,0 +1,125 @@ +function displayLarmorRad2Dwell(obj,time2d) +% Plot the larmor radius for created particles with low energy +% the larmor radius is calculated by considering that the +% initial perpendicular velocity \approx the ExB velocity +% potential well is shown with isolines on top +if iscell(time2d) + time2d=cell2mat(time2d); +end +if nargin<3 + clims=[-inf inf]; +end +f=figure('Name',sprintf('%s Potential well + Larmor radius',obj.name)); +ax1=gca; +model=obj.potentialwellmodel(time2d); +z=model.z; +r=model.r; +Pot=model.pot; +rathet=model.rathet; +if (time2d==0) + title(sprintf('\\rho_l and Potential well Vacuum')) +else + title(sprintf('\\rho_l and Potential well t=%1.2f [ns]',obj.t2d(time2d)*1e9)) +end + + +geomw=obj.geomweight(:,:,1); + + +if time2d>0 + Er=obj.Er(:,:,time2d); + Ez=obj.Ez(:,:,time2d); +else + Er=obj.Erxt(:,:,1); + Ez=obj.Ezxt(:,:,1); +end + +rl=abs(obj.me/obj.qe*(-Er.*obj.Bz'+Ez.*obj.Br')./(obj.B.^3)'); +rl(obj.geomweight(:,:,1)<0)=0; +contourf(obj.zgrid*1e3,obj.rgrid*1e3,rl*1e3) +hold on +%contour(obj.zgrid*1e3,obj.rgrid*1e3,obj.geomweight(:,:,1),[0 0],'r-','linewidth',3) +c=colorbar; +c.Label.String='r_L [mm]'; + +id=find(time2d==0); +time2d(id)=[]; + +[Zmesh,Rmesh]=meshgrid(obj.zgrid,obj.rgrid); +Pot=griddata(z,r,Pot,Zmesh,Rmesh,'natural'); +%Pot(obj.geomweight(:,:,1)<=0)=NaN; +Pot=Pot/max(max(Pot(~isnan(Pot))))*max(rl(:))*1e3; +contour(obj.zgrid(1:end)*1e3,obj.rgrid(1:end)*1e3,Pot(1:end,1:end),10,'r--','Displayname','Well') +xlabel('z [mm]') +ylabel('r [mm]') +xlim([obj.zgrid(1) obj.zgrid(end)]*1e3) +ylim([obj.rgrid(1) obj.rgrid(end)]*1e3) +hold(gca, 'on') + +rdisp=obj.rgrid; + +%% Magnetic field lines +Blines=obj.rAthet; +levels=linspace(min(Blines(obj.geomweight(:,:,1)>0)),max(Blines(obj.geomweight(:,:,1)>0)),20); +Blines(obj.geomweight(:,:,1)<0)=NaN; +[~,h1]=contour(obj.zgrid*1000,obj.rgrid*1000,Blines,real(levels),'k-.','linewidth',0.8,'Displayname','Magnetic field lines'); + +c=colorbar; +colormap('jet'); + +% Grey outline showing the metalic walls +geomw(obj.geomweight(:,:,1)>0)=-1; +geomw(obj.geomweight(:,:,1)<=0)=1; +[c1,hContour]=contourf(ax1,obj.zgrid*1000,obj.rgrid*1000,geomw, [0 0]); + +drawnow; +xlim(ax1,[obj.zgrid(1)*1000 obj.zgrid(end)*1000]) +if(obj.conformgeom) + ylim([ax1 ],[obj.rgrid(1)*1000 obj.rgrid(rgridend)*1000]) +else + ylim([ax1],[obj.rgrid(1)*1000 obj.rgrid(end)*1000]) +end +%ylim(ax1,[0.05*1000 obj.rgrid(end)*1000]) +%xlim([obj.zgrid(1) 0.185]*1e3) +xlabel(ax1,'z [mm]') +ylabel(ax1,'r [mm]') +view(ax1,2) +c.Label.String='\rho_L [mm]'; +f.PaperUnits='centimeters'; +caxis(clims) +grid on; +hFills=hContour.FacePrims; +[hFills.ColorType] = deal('truecoloralpha'); % default = 'truecolor' +try + drawnow + hFills(1).ColorData = uint8([150;150;150;255]); + for idx = 2 : numel(hFills) + hFills(idx).ColorData(4) = 0; % default=255 + end +catch +end + +% add central and external metallic walls if we have a coaxial +% configuration +if( obj.walltype >=2 && obj.walltype<=4) + rectangle('Position',[obj.zgrid(1) obj.r_b obj.zgrid(end)-obj.zgrid(1) 0.001]*1e3,'FaceColor',[150 150 150]/255,'Edgecolor','none') + ylimits=ylim; + ylim([ylimits(1),ylimits(2)+1]) +end +if sum(obj.geomweight(:,1,1))==0 + rectangle('Position',[obj.zgrid(1) obj.r_a-0.001 obj.zgrid(end)-obj.zgrid(1) 0.001]*1e3,'FaceColor',[150 150 150]/255,'Edgecolor','none') + ylimits=ylim; + ylim([ylimits(1)-1,ylimits(2)]) +end + +%axis equal +%xlim([-100 200]) +[max_depth,id]=max(abs(Pot(:))); +[idr,idz]=ind2sub(size(Pot),id); +fprintf('Maximum potential wel depth: %f eV\n',max_depth) +fprintf('at location r=%f z=%f [mm]\n',obj.rgrid(idr)*1e3, obj.zgrid(idz)*1e3) +papsize=[14 8]; +obj.savegraph(f,sprintf('%s/%s_wellr_rl_%i',obj.folder,obj.name,floor(mean(time2d))),papsize); + + +end diff --git a/matlab/@espic2dhdf5/displaySurfFluxes.m b/matlab/@espic2dhdf5/displaySurfFluxes.m new file mode 100644 index 0000000..9391ff5 --- /dev/null +++ b/matlab/@espic2dhdf5/displaySurfFluxes.m @@ -0,0 +1,76 @@ +function displaySurfFluxes(obj,timesteps, ids) + %displaySurfFluxes plot the time evolution of the current + %densities on the domain boundaries for times t2d(timesteps) + %also plot the different boundaries to see which flux belong to + %which boundary + + mflux= obj.Metallicflux(timesteps); + lflux= -squeeze(obj.Axialflux(timesteps,1))'; + rflux= squeeze(obj.Axialflux(timesteps,length(obj.zgrid)))'; + + time=obj.t2d(timesteps); + + if nargin<3 + ids=1:(size(mflux.p,2)+2); + end + + %% + P=obj.neutcol.neutdens*obj.kb*300/100;% pressure at room temperature in mbar + f=figure('name','fluxevol'); + tiledlayout('flow') + j=1; + for i=1:length(mflux.p) + if(find(i+2==ids)) + ax(j)=nexttile; + j=j+1; + if issorted(mflux.p{i}(1,:),'strictascend') + contourf(mflux.p{i}(1,:)*100,time*1e9,mflux.gamma{i}'*obj.qe/(100^2)/P,'linestyle','none') + xlabel('z [cm]') + else + contourf(linspace(0,1,length(mflux.p{i}(1,:))),time*1e9,mflux.gamma{i}'*obj.qe/(100^2)/P,'linestyle','none') + xlabel('s [-]') + end + title(sprintf('Wall %i',i)) + + c=colorbar; + c.Label.String= 'j\cdotn [A/(cm^2 mbar)]'; + end + end + + if(find(1==ids)) + ax(j)=nexttile; + contourf(obj.rgrid*100,time*1e9,lflux*obj.qe/(100^2)/P,'linestyle','none') + title('left') + xlabel('r [cm]') + c=colorbar; + c.Label.String= 'j\cdotn [A/(cm^2 mbar)]'; + end + + if(find(2==ids)) + ax(j+1)=nexttile; + contourf(obj.rgrid*100,time*1e9,rflux*obj.qe/(100^2)/P,'linestyle','none') + title('right') + xlabel('r [cm]') + c=colorbar; + c.Label.String= 'j\cdotn [A/(cm^2 mbar)]'; + end + + + ylabel(ax,'t [ns]') + + nexttile; + for i=1:length(mflux.p) + plot(mflux.p{i}(1,:)*100,mflux.p{i}(2,:)*100,'displayname',sprintf('Wall %i',i),'linewidth',2) + hold on + end + legend('location','eastoutside') + title('Domain') + plot(ones(size(obj.rgrid))*obj.zgrid(1)*100,obj.rgrid*100,'displayname','left','linewidth',2) + plot(ones(size(obj.rgrid))*obj.zgrid(end)*100,obj.rgrid*100,'displayname','right','linewidth',2) + xlabel('z [cm]') + ylabel('r [cm]') + %xlim([obj.zgrid(1) obj.zgrid(end)]*100) + %ylim([obj.rgrid(1) obj.rgrid(end)]*100) + + obj.savegraph(f,sprintf('%s/%s_surfFluxEvol',obj.folder,obj.name),[16 14]); + end \ No newline at end of file diff --git a/matlab/@espic2dhdf5/displayVacuumTrap.m b/matlab/@espic2dhdf5/displayVacuumTrap.m new file mode 100644 index 0000000..a452c30 --- /dev/null +++ b/matlab/@espic2dhdf5/displayVacuumTrap.m @@ -0,0 +1,71 @@ +function displayVacuumTrap(obj,time2d) +% Plot the larmor radius for created particles with low energy +% the larmor radius is calculated by considering that the +% initial perpendicular velocity \approx the ExB velocity +% potential well is shown with isolines on top +if iscell(time2d) + time2d=cell2mat(time2d); +end + + +[zgrid,rgrid]=ndgrid(obj.zgrid,obj.rgrid); +geomw=obj.geomweight(:,:,1); +inside=griddedInterpolant(zgrid,rgrid,obj.geomweight(:,:,1)'); + +% Compute the Larmor radius assuming v_perp=v_exb +if time2d>0 + Er=obj.Er(:,:,time2d); + Ez=obj.Ez(:,:,time2d); +else + Er=obj.Erxt(:,:,1); + Ez=obj.Ezxt(:,:,1); +end +rl=abs(obj.me/obj.qe*(-Er.*obj.Bz'+Ez.*obj.Br')./(obj.B.^3)'); +% Remove the points outside the geometry +rl(obj.geomweight(:,:,1)<0)=0; + +% calculate the normal vector to the magnetic field lines at each position +perpB=zeros(size(obj.sinthet,1),size(obj.sinthet,2),2); +perpB(:,:,1)=sign(-Er).*obj.sinthet; +perpB(:,:,2)=-sign(-Er).*obj.costhet; + +pos=zeros(size(obj.sinthet,1),size(obj.sinthet,2),2); +pos(:,:,1)=rgrid'; +pos(:,:,2)=zgrid'; + +posu=pos+2*rl.*perpB; + +isinside=inside(posu(:,:,2),posu(:,:,1))>0; + + +model=obj.potentialwellmodel(time2d,true); +z=model.z; +r=model.r; +Pot=model.pot; + +Potdepth=scatteredInterpolant(z',r',Pot); + +effectdepth=0.5*(Potdepth(posu(:,:,2),posu(:,:,1))+Potdepth(pos(:,:,2),pos(:,:,1))); +effectdepth(geomw<0)=NaN; +effectdepth(~isinside)=NaN; +effectdepth(effectdepth<0)=NaN; + +f=figure; +contourf(obj.zgrid,obj.rgrid,effectdepth,40,'edgecolor','none') +hold on +contour(obj.zgrid,obj.rgrid,geomw,[0 0],'r-') +N=obj.N(:,:,end); +N=N/max(N(:)); +contour(obj.zgrid,obj.rgrid,N,'k--') +colormap(jet) + +xlabel('z [m]') +ylabel('r [m]') +c=colorbar; +c.Label.String='Effective well [eV]'; + +papsize=[14 8]; +obj.savegraph(f,sprintf('%s/%s_effwellr_rl_%i',obj.folder,obj.name,floor(mean(time2d))),papsize); + + +end diff --git a/matlab/@espic2dhdf5/espic2dhdf5.m b/matlab/@espic2dhdf5/espic2dhdf5.m index fff8f9a..0bf49e5 100644 --- a/matlab/@espic2dhdf5/espic2dhdf5.m +++ b/matlab/@espic2dhdf5/espic2dhdf5.m @@ -1,3542 +1,3434 @@ classdef espic2dhdf5 %espic2dhdf5 General class used to treat hdf5 result files of espic2d code % A result file is loaded with a call to M=espic2dhdf5(filename) where filename is the relative or absolute file path % after loading, several quantities and composite diagnostics such as moments of the distribution function or individual particles % quantities can be accessed. properties filename name folder fullpath timestamp info t0d t1d t2d tpart it0 it1 it2 + restartsteps + restarttimes %% Physical constants vlight=299792458; qe=1.60217662E-19; me=9.109383E-31; eps_0=8.85418781762E-12; kb=1.38064852E-23; %% Run parameters dt % simulation time step nrun % number of time steps simulated nlres nlsave nlclassical % Was the equation of motion solved in the classical framework nlPhis % Was the self-consistent electric field computed nz % number of intervals in the z direction for the grid nnr % number of intervals in the r direction for the grid for each of the 3 mesh regions lz % physical axial dimension of the simulation space nplasma % Number of initial macro particles potinn % Normalized electric potential at the coaxial insert potout % Normalized electric potential at the cylinder surface B0 % Normalization for the magnetic field Rcurv % Magnetic mirror ratio width % Magnetic mirror length n0 % Initial particle density in case of old particle loading temp % Initial particle temperature in case of old particle loading femorder % finite element method order in z and r direction ngauss % Order of the Gauss integration method for the FEM plasmadim % initial dimensions of the plasma for the old particle loading system radii % Radial limits of the three mesh regions coarse,fine,coarse H0 % Initial particle Energy for Davidsons distribution function P0 % Initial particle Angular momentum for Davidsons distribution function normalized % Are the parts quantities normalized in the h5 file nbspecies % Number of species simulated %% Frequencies omepe % Reference plasma frequency used for normalization omece % Reference cyclotronic frequency for normalization %% Normalizations tnorm % Time normalization rnorm % Dimension normalization bnorm % Magnetic field normalization enorm % Electric field normalization phinorm % Electric potential normalization vnorm % Velocity normalization %% Grid data rgrid % Radial grid position points zgrid % Axial grid position points dz % Axial grid step dr % Radial grid step for the three mesh regions CellVol % Volume of the cell used for density calculation celltype % type of cell -1 outside 1 inside 0 border linked_s % location of linked spline bsplinetype %% Magnetic field Br % Radial magnetic field Bz % Axial magnetic field Athet % Azimuthal component of the Magnetic potential vector rAthet % r*Athet used for the representation of magnetic field lines B % Magnetic field amplitude sinthet % ratio to project quantities along the magnetic field lines costhet % ratio to project quantities along the magnetic field lines %% Energies epot % Time evolution of the particles potential energy ekin % Time evolution of the particles kinetic energy etot % Time evolution of the particles total energy etot0 % Time evolution of the reference particle total energy eerr % Time evolution of the error on the energy conservation npart % Time evolution of the number of simulated %% 2D time data evaluated on grid points N % main specie Density fluidUR % main specie radial fluid velocity fluidUZ % main specie axial fluid velocity fluidUTHET % main specie azimuthal fluid velocity pot % Electric potential evaluated at grid points potxt % External Electric potential evaluated at grid points phi % Electric potential in spline form Er % Radial electric field Ez % Axial electric field Erxt % External Radial electric field Ezxt % External Axial electric field Presstens % Pressure tensor fluidEkin % average kinetic energy in each direction %% Splines knotsr % Spline radial knots knotsz % Spline axial knots %% Particle parameters weight % Macro particle numerical weight of the main specie qsim % Macro particle charge msim % Macro particle mass nbparts % Time evolution of the number of simulated particles partepot % Electric potential at the particles positions R % Particles radial position Z % Particles axial position Rindex % Particles radial grid index Zindex % Particles axial grid index partindex % Particles unique id for tracing trajectories VR % Particles radial velocity VZ % Particles axial velocity VTHET % Particles azimuthal velocity THET % Particles azimuthal position species % Array containing the other simulated species %% Celldiag celldiag % Array containing the cell diagnostic data nbcelldiag % Total number of cell diagnostics %% Curvilinear geometry conformgeom % stores if we use the conforming or nonconforming boundary conditions r_a r_b z_r z_0 r_0 r_r L_r L_z Interior above1 above2 interior walltype geomweight dirichletweight gtilde spl_bound %% Maxwell source parameters maxwellsrce %% Collision with neutral parameters neutcol nudcol % effective momentum collision frequency %% Non ideal power supply psupply end methods function file=file(obj) % returns the h5 file name file=obj.filename; end function obj = espic2dhdf5(filename,readparts,old) % Reads the new result file filename and read the parts data if readparts==true % adds the helper_classes folder to the path matlabfuncpath = dir([mfilename('fullpath'),'.m']); addpath(sprintf('%s/../helper_classes',matlabfuncpath.folder)); + addpath(sprintf('%s/../extrema',matlabfuncpath.folder)); addpath(sprintf('%s/../export_fig',matlabfuncpath.folder)); % Try catch are there for compatibility with older simulation files filedata=dir(filename); if (isempty(filedata)) error("File: ""%s"" doesn't exist",filename) end obj.folder=filedata.folder; obj.filename=filename; [~, obj.name, ext] = fileparts(obj.filename); obj.filename=[obj.name,ext]; obj.fullpath=[obj.folder,'/',obj.filename]; obj.timestamp=filedata.date; if nargin==1 readparts=true; end if nargin<3 old=false; end %obj.info=h5info(filename); %% Read the run parameters obj.dt = h5readatt(obj.fullpath,'/data/input.00/','dt'); obj.nrun = h5readatt(obj.fullpath,'/data/input.00/','nrun'); obj.nlres = strcmp(h5readatt(obj.fullpath,'/data/input.00/','nlres'),'y'); obj.nlsave = strcmp(h5readatt(obj.fullpath,'/data/input.00/','nlsave'),'y'); obj.nlclassical =strcmp(h5readatt(obj.fullpath,'/data/input.00/','nlclassical'),'y'); obj.nlPhis =strcmp(h5readatt(obj.fullpath,'/data/input.00/','nlPhis'),'y'); obj.nz = h5readatt(obj.fullpath,'/data/input.00/','nz'); obj.nnr = h5read(obj.fullpath,'/data/input.00/nnr'); obj.lz = h5read(obj.fullpath,'/data/input.00/lz'); obj.qsim = h5readatt(obj.fullpath,'/data/input.00/','qsim'); obj.msim = h5readatt(obj.fullpath,'/data/input.00/','msim'); try obj.r_a=h5readatt(obj.fullpath,'/data/input.00/geometry','r_a'); obj.r_b=h5readatt(obj.fullpath,'/data/input.00/geometry','r_b'); obj.z_r=h5readatt(obj.fullpath,'/data/input.00/geometry','z_r'); obj.r_r=h5readatt(obj.fullpath,'/data/input.00/geometry','r_r'); obj.r_0=h5readatt(obj.fullpath,'/data/input.00/geometry','r_0'); obj.z_0=h5readatt(obj.fullpath,'/data/input.00/geometry','z_0'); obj.above1=h5readatt(obj.fullpath,'/data/input.00/geometry','above1'); obj.above2=h5readatt(obj.fullpath,'/data/input.00/geometry','above2'); obj.interior=h5readatt(obj.fullpath,'/data/input.00/geometry','interior'); obj.walltype=h5readatt(obj.fullpath,'/data/input.00/geometry','walltype'); try obj.L_r=h5readatt(obj.fullpath,'/data/input.00/geometry','L_r'); obj.L_z=h5readatt(obj.fullpath,'/data/input.00/geometry','L_z'); catch end obj.conformgeom=false; catch obj.conformgeom=true; obj.walltype=0; obj.r_a=obj.rgrid(1); obj.r_b=obj.rgrid(end); obj.above1=1; obj.above2=-1; obj.L_r=0; obj.L_z=0; end try obj.weight=h5readatt(obj.fullpath,'/data/part/','weight'); catch obj.weight=obj.msim/obj.me; end + filesgrpinfo=h5info(obj.fullpath,'/files'); + nbrst=h5readatt(obj.fullpath,'/files','jobnum'); + obj.restartsteps(1)=0; + obj.restarttimes(1)=0; + for i=1:nbrst + grp=sprintf('/data/input.%02i/',i); + obj.restartsteps(i+1)= h5readatt(obj.fullpath,grp,'startstep'); + obj.restarttimes(i+1)= obj.restarttimes(i) + (obj.restartsteps(i+1)-obj.restartsteps(i))*h5readatt(obj.fullpath,grp,'dt'); + end obj.nplasma = h5readatt(obj.fullpath,'/data/input.00/','nplasma'); obj.potinn = h5readatt(obj.fullpath,'/data/input.00/','potinn'); obj.potout = h5readatt(obj.fullpath,'/data/input.00/','potout'); obj.B0 = h5readatt(obj.fullpath,'/data/input.00/','B0'); obj.Rcurv = h5readatt(obj.fullpath,'/data/input.00/','Rcurv'); obj.width = h5readatt(obj.fullpath,'/data/input.00/','width'); obj.n0 = h5readatt(obj.fullpath,'/data/input.00/','n0'); obj.temp = h5readatt(obj.fullpath,'/data/input.00/','temp'); try obj.it0 = h5readatt(obj.fullpath,'/data/input.00/','it0d'); obj.it1 = h5readatt(obj.fullpath,'/data/input.00/','it2d'); obj.it2 = h5readatt(obj.fullpath,'/data/input.00/','itparts'); catch obj.it0 = h5readatt(obj.fullpath,'/data/input.00/','it0'); obj.it1 = h5readatt(obj.fullpath,'/data/input.00/','it1'); obj.it1 = h5readatt(obj.fullpath,'/data/input.00/','it2'); end try try obj.nbspecies=h5readatt(obj.fullpath,'/data/part/','nbspecies'); catch obj.nbspecies=h5readatt(obj.fullpath,'/data/input.00/','nbspecies'); end obj.normalized=strcmp(h5readatt(obj.fullpath,'/data/input.00/','rawparts'),'y'); catch obj.nbspecies=1; obj.normalized=false; end try obj.nbcelldiag=h5readatt(obj.fullpath,'/data/celldiag/','nbcelldiag'); catch obj.nbcelldiag=0; end obj.omepe=sqrt(abs(obj.n0)*obj.qe^2/(obj.me*obj.eps_0)); obj.omece=obj.qe*obj.B0/obj.me; obj.npart= h5read(obj.fullpath, '/data/var0d/nbparts'); try obj.nudcol= h5read(obj.fullpath, '/data/var0d/nudcol'); catch end try obj.H0 = h5read(obj.fullpath,'/data/input.00/H0'); obj.P0 = h5read(obj.fullpath,'/data/input.00/P0'); catch obj.H0=3.2e-14; obj.P0=8.66e-25; end % Normalizations if old obj.tnorm=abs(1/obj.omepe); else obj.tnorm=min(abs(1/obj.omepe),abs(1/obj.omece)); end obj.rnorm=obj.vlight*obj.tnorm; obj.bnorm=obj.B0; obj.enorm=obj.vlight*obj.bnorm; obj.phinorm=obj.enorm*obj.rnorm; obj.vnorm=obj.vlight; % Grid data obj.rgrid= h5read(obj.fullpath, '/data/var1d/rgrid')*obj.rnorm; obj.zgrid= h5read(obj.fullpath, '/data/var1d/zgrid')*obj.rnorm; obj.dz=(obj.zgrid(end)-obj.zgrid(1))/double(obj.nz); rid=1; for i=1:length(obj.nnr) obj.dr(i)=(obj.rgrid(sum(obj.nnr(1:i))+1)-obj.rgrid(rid))/double(obj.nnr(i)); rid=rid+obj.nnr(i); end Br = h5read(obj.fullpath,'/data/fields/Br')*obj.bnorm; obj.Br= reshape(Br,length(obj.zgrid),length(obj.rgrid)); Bz = h5read(obj.fullpath,'/data/fields/Bz')*obj.bnorm; obj.Bz= reshape(Bz,length(obj.zgrid),length(obj.rgrid)); try Atheta = h5read(obj.fullpath,'/data/fields/Athet')*obj.bnorm; obj.Athet= reshape(Atheta,length(obj.zgrid),length(obj.rgrid)); [rmeshgrid,~]=meshgrid(obj.rgrid,obj.zgrid); obj.rAthet=(rmeshgrid.*obj.Athet)'; catch end obj.B=sqrt(obj.Bz.^2+obj.Br.^2); obj.costhet=(obj.Br./obj.B)'; obj.sinthet=(obj.Bz./obj.B)'; clear Br Bz try obj.t0d=h5read(obj.fullpath,'/data/var0d/time'); catch obj.t0d=obj.dt.*double(0:length(obj.epot)-1); end try - for i=0:5 + for i=0:nbrst grp=sprintf('/data/input.%02i/',i); obj.Erxt(:,:,i+1)=reshape(h5read(obj.fullpath,[grp,'Erxt']),length(obj.zgrid),length(obj.rgrid))'*obj.enorm; obj.Ezxt(:,:,i+1)=reshape(h5read(obj.fullpath,[grp,'Ezxt']),length(obj.zgrid),length(obj.rgrid))'*obj.enorm; obj.potxt(:,:,i+1)=reshape(h5read(obj.fullpath,[grp,'potxt']),length(obj.zgrid),length(obj.rgrid))'*obj.phinorm; end catch end obj.femorder = h5read(obj.fullpath,'/data/input.00/femorder'); obj.ngauss = h5read(obj.fullpath,'/data/input.00/ngauss'); obj.plasmadim = h5read(obj.fullpath,'/data/input.00/plasmadim'); obj.radii = h5read(obj.fullpath,'/data/input.00/radii'); obj.epot = h5read(obj.fullpath,'/data/var0d/epot'); obj.ekin = h5read(obj.fullpath,'/data/var0d/ekin'); obj.etot = h5read(obj.fullpath,'/data/var0d/etot'); try obj.etot0 = h5read(obj.fullpath,'/data/var0d/etot0'); obj.eerr = obj.etot-obj.etot0; catch obj.eerr = obj.etot-obj.etot(2); end if(obj.normalized) obj.pot=gridquantity(obj.fullpath,'/data/fields/pot',sum(obj.nnr)+1, obj.nz+1,1); obj.Er=gridquantity(obj.fullpath,'/data/fields/Er',sum(obj.nnr)+1, obj.nz+1,1); obj.Ez=gridquantity(obj.fullpath,'/data/fields/Ez',sum(obj.nnr)+1, obj.nz+1,1); else obj.pot=gridquantity(obj.fullpath,'/data/fields/pot',sum(obj.nnr)+1, obj.nz+1,obj.phinorm); obj.Er=gridquantity(obj.fullpath,'/data/fields/Er',sum(obj.nnr)+1, obj.nz+1,obj.enorm); obj.Ez=gridquantity(obj.fullpath,'/data/fields/Ez',sum(obj.nnr)+1, obj.nz+1,obj.enorm); end try obj.t2d = h5read(obj.fullpath,'/data/fields/time'); catch info=h5info(obj.fullpath,'/data/fields/partdensity'); obj.t2d=obj.dt*(0:info.objspace.Size(2)-1)*double(obj.it1); end try info=h5info(obj.fullpath,'/data/fields/moments'); obj.femorder = h5read(obj.fullpath,'/data/input.00/femorder'); kr=obj.femorder(2)+1; obj.knotsr=augknt(obj.rgrid,kr); kz=obj.femorder(1)+1; obj.knotsz=augknt(obj.zgrid,kz); try obj.CellVol= reshape(h5read(obj.fullpath,'/data/fields/volume'),length(obj.knotsz)-kz,length(obj.knotsr)-kr); obj.CellVol=permute(obj.CellVol,[2,1,3])*obj.rnorm^3; catch zvol=fnder(spmak(obj.knotsz,ones(1,length(obj.knotsz)-kz)), -1 ); rvol=fnder(spmak(obj.knotsr,2*pi*[obj.rgrid' 2*obj.rgrid(end)-obj.rgrid(end-1)]), -1 ); ZVol=diff(fnval(zvol,obj.knotsz)); RVol=diff(fnval(rvol,obj.knotsr)); obj.CellVol=RVol(3:end-1)*ZVol(3:end-1)'; obj.CellVol=padarray(obj.CellVol,[1,1],'replicate','post'); end try obj.geomweight = h5read(obj.fullpath,'/data/input.00/geometry/geomweight'); obj.geomweight= reshape(obj.geomweight,length(obj.zgrid),length(obj.rgrid),[]); obj.geomweight = permute(obj.geomweight,[2,1,3]); catch obj.geomweight=ones(length(obj.rgrid),length(obj.zgrid),3); end try obj.dirichletweight = h5read(obj.fullpath,'/data/input.00/geometry/dirichletweight'); obj.dirichletweight= reshape(obj.dirichletweight,length(obj.zgrid),length(obj.rgrid),[]); obj.dirichletweight = permute(obj.dirichletweight,[2,1,3]); catch obj.dirichletweight=obj.geomweight; end try obj.gtilde = h5read(obj.fullpath,'/data/input.00/geometry/gtilde'); obj.gtilde= reshape(obj.gtilde,length(obj.zgrid),length(obj.rgrid),[]); obj.gtilde = permute(obj.gtilde,[2,1,3]); catch obj.gtilde=zeros(length(obj.rgrid),length(obj.zgrid),3); end geomweight=ones(length(obj.rgrid),length(obj.zgrid)); if(obj.normalized) obj.N=splinedensity(obj.fullpath, '/data/fields/moments', obj.knotsr, obj.knotsz, obj.femorder, obj.CellVol, 1, geomweight, 1); obj.phi=splinequantity(obj.fullpath,'/data/fields/phi', obj.knotsr, obj.knotsz, obj.femorder, 1, obj.geomweight(:,:,1), -1); else obj.N=splinedensity(obj.fullpath, '/data/fields/moments', obj.knotsr, obj.knotsz, obj.femorder, obj.CellVol, abs(obj.qsim/obj.qe), geomweight, 1); end obj.fluidUR=splinevelocity(obj.fullpath, '/data/fields/moments', obj.knotsr, obj.knotsz, obj.femorder, obj.vnorm, geomweight, 2); obj.fluidUTHET=splinevelocity(obj.fullpath, '/data/fields/moments', obj.knotsr, obj.knotsz, obj.femorder, obj.vnorm, geomweight, 3); obj.fluidUZ=splinevelocity(obj.fullpath, '/data/fields/moments', obj.knotsr, obj.knotsz, obj.femorder, obj.vnorm, geomweight, 4); if(obj.normalized) obj.Presstens=splinepressure(obj.fullpath, '/data/fields/moments', obj.knotsr, obj.knotsz, obj.femorder, obj.CellVol, obj.vnorm^2*obj.me, geomweight); obj.fluidEkin=splineenergy(obj.fullpath, '/data/fields/moments', obj.knotsr, obj.knotsz, obj.femorder, obj.CellVol, obj.vnorm^2*obj.me*0.5, geomweight); else obj.Presstens=splinepressure(obj.fullpath, '/data/fields/moments', obj.knotsr, obj.knotsz, obj.femorder, obj.CellVol, obj.vnorm^2*obj.msim, geomweight); obj.fluidEkin=splineenergy(obj.fullpath, '/data/fields/moments', obj.knotsr, obj.knotsz, obj.femorder, obj.CellVol, obj.vnorm^2*obj.msim*0.5, geomweight); end try obj.celltype=h5read(obj.fullpath,'/data/input.00/geometry/ctype')'; obj.linked_s=h5read(obj.fullpath,'/data/input.00/geometry/linked_s'); obj.bsplinetype=h5read(obj.fullpath,'/data/input.00/geometry/bsplinetype'); obj.bsplinetype=reshape(obj.bsplinetype,length(obj.knotsz)-kz,length(obj.knotsr)-kr); catch obj.celltype=[]; obj.linked_s=[]; end catch obj.CellVol=(obj.zgrid(2:end)-obj.zgrid(1:end-1))*((obj.rgrid(2:end).^2-obj.rgrid(1:end-1).^2)*pi)'; obj.CellVol=obj.CellVol'; obj.N=griddensity(obj.fullpath, '/data/fields/partdensity', sum(obj.nnr)+1, obj.nz+1, obj.CellVol, abs(obj.qsim/obj.qe), true); obj.fluidUR=gridquantity(obj.fullpath, '/data/fields/fluidur', sum(obj.nnr)+1, obj.nz+1, obj.vnorm, true); obj.fluidUTHET=gridquantity(obj.fullpath, '/data/fields/fluiduthet', sum(obj.nnr)+1, obj.nz+1, obj.vnorm, true); obj.fluidUZ=gridquantity(obj.fullpath, '/data/fields/fluiduz', sum(obj.nnr)+1, obj.nz+1, obj.vnorm, true); end % If we have a maxwellian source, read its parameters try obj.maxwellsrce.rlim=h5read(obj.fullpath, '/data/input.00/maxwellsource/rlimits'); obj.maxwellsrce.zlim=h5read(obj.fullpath, '/data/input.00/maxwellsource/zlimits'); obj.maxwellsrce.frequency=h5readatt(obj.fullpath, '/data/input.00/maxwellsource','frequency'); obj.maxwellsrce.radialtype=h5readatt(obj.fullpath, '/data/input.00/maxwellsource','radialtype'); obj.maxwellsrce.temperature=h5readatt(obj.fullpath, '/data/input.00/maxwellsource','temperature'); obj.maxwellsrce.time_end=h5readatt(obj.fullpath, '/data/input.00/maxwellsource','time_end'); obj.maxwellsrce.time_start=h5readatt(obj.fullpath, '/data/input.00/maxwellsource','time_start'); obj.maxwellsrce.vth=h5readatt(obj.fullpath, '/data/input.00/maxwellsource','vth'); obj.maxwellsrce.rate=obj.maxwellsrce.frequency*obj.weight/(pi*(diff(obj.maxwellsrce.rlim.^2))*diff(obj.maxwellsrce.zlim)); + obj.maxwellsrce.current=obj.maxwellsrce.frequency*obj.weight*obj.qe; obj.maxwellsrce.present=true; catch obj.maxwellsrce.present=false; end %% load neutcol parameters try obj.neutcol.neutdens=double(h5readatt(obj.fullpath, '/data/input.00/neutcol','neutdens')); obj.neutcol.neutpressure=double(h5readatt(obj.fullpath, '/data/input.00/neutcol','neutpressure')); obj.neutcol.scatter_fac=double(h5readatt(obj.fullpath, '/data/input.00/neutcol','scatter_fac')); obj.neutcol.Eion=double(h5readatt(obj.fullpath, '/data/input.00/neutcol','Eion')); obj.neutcol.E0=double(h5readatt(obj.fullpath, '/data/input.00/neutcol','E0')); obj.neutcol.Escale=double(h5readatt(obj.fullpath, '/data/input.00/neutcol','Escale')); try obj.neutcol.io_cross_sec=double(h5read(obj.fullpath, '/data/input.00/neutcol/io_cross_sec')); obj.neutcol.io_cross_sec(:,2)=obj.neutcol.io_cross_sec(:,2)*obj.rnorm^2; obj.neutcol.io_cross_sec(:,3)=[log(obj.neutcol.io_cross_sec(2:end,2)./obj.neutcol.io_cross_sec(1:end-1,2))... ./log(obj.neutcol.io_cross_sec(2:end,1)./obj.neutcol.io_cross_sec(1:end-1,1)); 0]; obj.neutcol.iom_cross_sec=zeros(500,3); obj.neutcol.iom_cross_sec(:,1)=logspace(log10(obj.neutcol.Eion+0.001),log10(5e4),size(obj.neutcol.iom_cross_sec,1)); obj.neutcol.iom_cross_sec(:,2)=obj.sigmiopre(obj.neutcol.iom_cross_sec(:,1),true); obj.neutcol.iom_cross_sec(:,3)=abs([log(obj.neutcol.iom_cross_sec(2:end,2)./obj.neutcol.iom_cross_sec(1:end-1,2))... ./log(obj.neutcol.iom_cross_sec(2:end,1)./obj.neutcol.iom_cross_sec(1:end-1,1)); 0]); catch obj.neutcol.io_cross_sec=[]; obj.neutcol.iom_cross_sec=[]; end try obj.neutcol.ela_cross_sec=double(h5read(obj.fullpath, '/data/input.00/neutcol/ela_cross_sec')); obj.neutcol.ela_cross_sec(:,2)=obj.neutcol.ela_cross_sec(:,2)*obj.rnorm^2; obj.neutcol.ela_cross_sec(:,3)=[log(obj.neutcol.ela_cross_sec(2:end,2)./obj.neutcol.ela_cross_sec(1:end-1,2))... ./log(obj.neutcol.ela_cross_sec(2:end,1)./obj.neutcol.ela_cross_sec(1:end-1,1)); 0]; catch obj.neutcol.ela_cross_sec=[]; end obj.neutcol.present=true; catch obj.neutcol.present=false; end %% load spline boundaries try obj.spl_bound.nbsplines=h5readatt(obj.fullpath, '/data/input.00/geometry_spl','nbsplines'); for i=1:obj.spl_bound.nbsplines splgroup=sprintf('/data/input.00/geometry_spl/%02d',i); obj.spl_bound.boundary(i).knots=h5read(obj.fullpath,sprintf('%s/knots',splgroup)); obj.spl_bound.boundary(i).coefs=reshape(h5read(obj.fullpath,sprintf('%s/pos',splgroup)),2,[])'; obj.spl_bound.boundary(i).order=h5readatt(obj.fullpath,splgroup,'order'); obj.spl_bound.boundary(i).kind=h5readatt(obj.fullpath,splgroup,'kind'); obj.spl_bound.boundary(i).fun=spmak(obj.spl_bound.boundary(i).knots,obj.spl_bound.boundary(i).coefs'); end catch obj.spl_bound.nbsplines=0; end %% load non ideal power supply parameters try obj.psupply.targetbias=h5readatt(obj.fullpath, '/data/input.00/psupply','targetbias'); obj.psupply.expdens=h5readatt(obj.fullpath, '/data/input.00/psupply','expdens'); obj.psupply.PSresistor=h5readatt(obj.fullpath, '/data/input.00/psupply','PSresistor'); obj.psupply.geomcapacitor=h5readatt(obj.fullpath, '/data/input.00/psupply','geomcapacitor'); obj.psupply.nbhdt=h5readatt(obj.fullpath, '/data/input.00/psupply','nbhdt'); obj.psupply.biases=h5read(obj.fullpath, '/data/var0d/biases'); obj.psupply.current=h5read(obj.fullpath, '/data/var0d/current'); obj.psupply.tau=obj.psupply.PSresistor*obj.psupply.geomcapacitor*obj.psupply.expdens/obj.neutcol.neutdens; obj.psupply.active=true; obj.psupply.bdpos=h5read(obj.fullpath, '/data/input.00/psupply/bdpos'); catch obj.psupply.active=false; end % Read the main particles parameters if(readparts) if(obj.normalized) obj.R = h5partsquantity(obj.fullpath,'/data/part','R'); obj.Z = h5partsquantity(obj.fullpath,'/data/part','Z'); else obj.R = h5partsquantity(obj.fullpath,'/data/part','R',obj.rnorm); obj.Z = h5partsquantity(obj.fullpath,'/data/part','Z',obj.rnorm); end try obj.THET = h5partsquantity(obj.fullpath,'/data/part','THET'); catch clear obj.THET end try obj.Rindex=h5partsquantity(obj.fullpath,'/data/part','Rindex'); obj.Zindex=h5partsquantity(obj.fullpath,'/data/part','Zindex'); catch clear obj.Rindex obj.Zindex end vscale=obj.vnorm; obj.VR = h5partsquantity(obj.fullpath,'/data/part','UR',vscale); obj.VZ = h5partsquantity(obj.fullpath,'/data/part','UZ',vscale); obj.VTHET= h5partsquantity(obj.fullpath,'/data/part','UTHET',vscale); if(obj.normalized) obj.partepot = h5partsquantity(obj.fullpath,'/data/part','pot',sign(obj.qsim)*obj.qe); else obj.partepot = h5partsquantity(obj.fullpath,'/data/part','pot',sign(obj.qsim)*obj.qe*obj.phinorm); end try obj.partindex = h5partsquantity(obj.fullpath,'/data/part/','partindex'); catch end if(obj.nbspecies >1) obj.species=h5parts.empty(obj.nbspecies,0); for i=2:obj.nbspecies obj.species(i-1)=h5parts(obj.fullpath,sprintf('/data/part/%2d',i),obj); end end end try obj.tpart = h5read(obj.fullpath,'/data/part/time'); obj.nbparts = h5read(obj.fullpath,'/data/part/Nparts'); catch obj.nbparts=obj.npart; obj.tpart=obj.dt*(0:size(obj.R,2)-1)*double(obj.it2); end if(obj.nbcelldiag > 0) obj.celldiag=h5parts.empty; j=0; for i=1:obj.nbcelldiag nbparts=h5read(obj.fullpath,sprintf('%s/Nparts',sprintf('/data/celldiag/%02d',i))); if (sum(nbparts)>0) j=j+1; obj.celldiag(j)=h5parts(obj.fullpath,sprintf('/data/celldiag/%02d',i),obj); obj.celldiag(j).rindex=double(h5readatt(obj.fullpath, sprintf('/data/celldiag/%02d',i),'rindex'))+(1:2); obj.celldiag(j).zindex=double(h5readatt(obj.fullpath, sprintf('/data/celldiag/%02d',i),'zindex'))+(1:2); end end end end %------------------------------------------ % Functions for accesing secondary simulation quantities function Atheta=Atheta(obj,R,Z) %% returns the magnetic vector potential at position R,Z interpolated from stored Athet in h5 file % halflz=(obj.zgrid(end)+obj.zgrid(1))/2; % Atheta=0.5*obj.B0*(R-obj.width/pi*(obj.Rcurv-1)/(obj.Rcurv+1)... % .*besseli(1,2*pi*R/obj.width).*cos(2*pi*(Z-halflz)/obj.width)); Atheta=interp2(obj.rgrid,obj.zgrid,obj.Athet,R,Z); end function quantity=H(obj,indices) %% computes the total energy for the main specie % for the particle with index indices{1} at timepart step indices{2} % which is time obj.timepart(indices{2}) if strcmp(indices{1},':') p=1:obj.VR.nparts;% if nothing is defined we load all particles else p=indices{1}; end if strcmp(indices{2},':') t=1:length(obj.tpart); %if nothing is defined all time steps are considered else t=indices{2}; end % if track is true we look at specific particles with their % index and follow them in time % if it is false we just care about the distribution function % and specific particles can have different positions in the % resulting array for each timestep if size(indices,1)>2 track=indices{3}; else track=false; end quantity=0.5*obj.me*(obj.VR(p,t,track).^2+obj.VTHET(p,t,track).^2+obj.VZ(p,t,track).^2)+obj.partepot(p,t,track); end function quantity=P(obj,indices) %P computes the canonical angular momentum for the main specie % for the particle with index indices{1} at timepart step indices{2} % which is time obj.timepart(indices{2}) if strcmp(indices{1},':') p=1:obj.R.nparts; else p=indices{1}; end if strcmp(indices{2},':') t=1:length(obj.tpart); else t=indices{2}; end % if track is true we look at specific particles with their % index and follow them in time % if it is false we just care about the distribution function % and specific particles can have different positions in the % resulting array for each timestep if size(indices,1)>2 track=indices{3}; else track=false; end quantity=obj.R(p,t,track).*(obj.VTHET(p,t,track)*obj.me+sign(obj.qsim)*obj.qe*obj.Atheta(obj.R(p,t,track),obj.Z(p,t,track))); end function quantity=Vpar(obj,varargin) %Vpar Computes the parallel velocity for the main specie % for the particle with index indices{1} at timepart step indices{2} % which is time obj.timepart(indices{2}) if(~iscell(varargin)) indices=mat2cell(varargin); else indices=varargin; end if strcmp(indices{1},':') p=1:obj.R.nparts; else p=indices{1}; end if strcmp(indices{2},':') t=1:length(obj.tpart); else t=indices{2}; end % if track is true we look at specific particles with their % index and follow them in time % if it is false we just care about the distribution function % and specific particles can have different positions in the % resulting array for each timestep if size(indices,1)>2 track=indices{3}; else track=false; end Zp=obj.Z(p,t,track);% get the particle axial positon Rp=obj.R(p,t,track);% get the particle radial position % interpolate the magnetic field at the particle position Bzp=interp2(obj.zgrid,obj.rgrid,obj.Bz',Zp,Rp,'makima'); Brp=interp2(obj.zgrid,obj.rgrid,obj.Br',Zp,Rp,'makima'); Bp=sqrt(Bzp.^2+Brp.^2); % calculate the projection angle of the radial and axial % directions on the magnetic field line Costhet=Bzp./Bp; Sinthet=Brp./Bp; % calculate the actuale parallel velocity quantity=obj.VR(p,t,track).*Sinthet+obj.VZ(p,t,track).*Costhet; end function quantity=Vperp(obj,varargin) %Vperp Computes the perpendicular velocity in the guidind center reference frame, % for the main specie particle indices{1} at time indices{2} if(~iscell(varargin)) indices=mat2cell(varargin); else indices=varargin; end if strcmp(indices{1},':') p=1:obj.R.nparts; else p=indices{1}; end if strcmp(indices{2},':') t=1:length(obj.tpart); else t=indices{2}; end % if track is true we look at specific particles with their % index and follow them in time % if it is false we just care about the distribution function % and specific particles can have different positions in the % resulting array for each timestep if size(indices,2)>2 track=indices{3}; else track=false; end % if gcs is true, gives the perpendicular velocity in the % guiding center system by substracting the EXB azimuthal % velocity % else gives the total perpendicular velocity if size(indices,2)>3 gcs=indices{4}; else gcs=false; end % get the particle position Zp=obj.Z(p,t,track); Rp=obj.R(p,t,track); % interpolate the magnetic field at the particle position Bzp=interp2(obj.zgrid,obj.rgrid,obj.Bz',Zp,Rp,'makima'); Brp=interp2(obj.zgrid,obj.rgrid,obj.Br',Zp,Rp,'makima'); Bp=sqrt(Bzp.^2+Brp.^2); % calculate the projecting angles Costhet=Bzp./Bp; Sinthet=Brp./Bp; Vdrift=zeros(size(Zp)); if gcs % for each particle and each timestep % calculate the azimuthal ExB drift velocity for j=1:length(t) [~, tfield]=min(abs(obj.t2d-obj.tpart(t(j)))); timeEr=obj.Er(:,:,tfield); timeEz=obj.Ez(:,:,tfield); %posindE=sub2ind(size(timeEr),Rind(:,j),Zind(:,j)); timeErp=interp2(obj.zgrid,obj.rgrid,timeEr,Zp(:,j),Rp(:,j)); timeEzp=interp2(obj.zgrid,obj.rgrid,timeEz,Zp(:,j),Rp(:,j)); Vdrift(:,j)=(timeEzp.*Brp(:,j)-timeErp.*Bzp(:,j))./Bp(:,j).^2; end end % calculate the perpendicular velocity quantity=sqrt((obj.VTHET(p,t,track)-Vdrift).^2+(obj.VR(p,t,track).*Costhet-obj.VZ(p,t,track).*Sinthet).^2); end function quantity=cyclphase(obj,varargin) %cyclphase Computes the cyclotronic phase for the main specie % for particles with indices{1} at time indices{2} if(~iscell(varargin)) indices=mat2cell(varargin); else indices=varargin; end if strcmp(indices{1},':') p=1:obj.R.nparts; else p=indices{1}; end if strcmp(indices{2},':') t=1:length(obj.tpart); else t=indices{2}; end % if track is true we look at specific particles with their % index and follow them in time % if it is false we just care about the distribution function % and specific particles can have different positions in the % resulting array for each timestep if size(indices,2)>2 track=indices{3}; else track=false; end Zp=obj.Z(p,t,track); Rp=obj.R(p,t,track); % [~, zind(1)]=min(abs(obj.zgrid-0.005262)); % [~, zind(2)]=min(abs(obj.zgrid-0.006637)); % [~, rind(1)]=min(abs(obj.rgrid-0.0784)); % [~, rind(2)]=min(abs(obj.rgrid-0.07861)); % indices=Zp=obj.zgrid(zind(1)) &... % Rp=obj.rgrid(rind(1)); %Zp=Zp(indices); %Rp=Rp(indices); %p=indices; Bzp=interp2(obj.zgrid,obj.rgrid,obj.Bz',Zp,Rp,'makima'); Brp=interp2(obj.zgrid,obj.rgrid,obj.Br',Zp,Rp,'makima'); Bp=sqrt(Bzp.^2+Brp.^2); Costhet=Bzp./Bp; Sinthet=Brp./Bp; % compute the projection of the perpendicular velocity in the % radial direction vr=(obj.VR(p,t,track).*Costhet-obj.VZ(p,t,track).*Sinthet); % Get the perpendicular velocity vperp=obj.Vperp(p,t,track,true); vr=vr(indices); vperp=vperp(indices); cospsi=vr./vperp; quantity=acos(cospsi); end function p=borderpoints(obj,subdiv) %borderpoints Return a cell array containing the curves %defining the boundary of the domain % for each boundary p(1,:) and p(2,:) give axial and radial position % for each boundary p(3,:) and p(4,:) give axial and radial normals %gw= contourc(obj.zgrid,obj.rgrid,obj.geomweight(:,:,1),[0 0]) p=cell(0,0); if nargin<2 subdiv=1; end ndiv=sum(subdiv); %outer cylinder if any(obj.geomweight(end,:,1)>=0) idp=ceil(length(obj.zgrid)/ndiv); imin=1; for j=1:length(subdiv) imax=min(imin+subdiv(j)*idp-1,length(obj.zgrid)); p{end+1}=[obj.zgrid(imin:imax)';obj.rgrid(end)*ones(imax-imin+1,1)'; zeros(imax-imin+1,1)';ones(imax-imin+1,1)']; imin=imax; end end %inner cylinder if any(obj.geomweight(1,:,1)>=0) idp=ceil(length(obj.zgrid)/ndiv); imin=1; for j=1:length(subdiv) imax=min(imin+subdiv(j)*idp-1,length(obj.zgrid)); p{end+1}=[obj.zgrid(imin:imax)';obj.rgrid(1)*ones(imax-imin+1,1)'; zeros(imax-imin+1,1)';-ones(imax-imin+1,1)']; imin=imax; end end if obj.walltype==2 % We have an elliptic insert that we want to isolate gw=obj.ellipseborder; zpos=obj.zgrid(obj.zgrid<(min(gw(1,:))) | obj.zgrid>(max(gw(1,:)))); p{2}=[zpos,obj.rgrid(end)*ones(size(zpos))]'; p{1}=[obj.zgrid';obj.rgrid(1)*ones(size(obj.zgrid))']; gw=obj.ellipseborder; p{3}=gw; elseif obj.walltype~=0 % extract all the walls gw=contourc(obj.zgrid,obj.rgrid,obj.geomweight(:,:,1),[0 0]); [x,y,~]=C2xyz(gw); for i=1:length(x) %subdiv=[4,1,2]; ndiv=sum(subdiv); idp=ceil(length(x{i})/ndiv); imin=1; for j=1:length(subdiv) imax=min(imin+subdiv(j)*idp-1,length(x{i})); p{end+1}=[x{i}(imin:imax);y{i}(imin:imax)]; imin=imax; end end end % figure % for i=1:length(p) % plot(p{i}(1,:),p{i}(2,:)) % hold on % end end function p=ellipseborder(obj) %ellipseborder returns the boundary points defining the %elliptic insert z=linspace(-0.998,0.998,1000)*obj.z_r; p=zeros(4,length(z)); for i=1:length(z) p(1,i)=z(i)+obj.z_0; p(2,i)=obj.r_0-obj.r_r*sqrt(1-(z(i)/obj.z_r)^2); p(3,i)=2/(obj.z_r^2)*(z(i)); p(4,i)=2/(obj.r_r^2)*(p(2,i)-obj.r_0); end norm=sqrt(p(3,:).^2+p(4,:).^2); p(3,:)=double(obj.interior)*p(3,:)./norm; p(4,:)=double(obj.interior)*p(4,:)./norm; end function charge=totcharge(obj,fieldstep) % Integrates the density profile over the full volume to obtain % the total number of electrons in the volume n=splinedensity(obj.fullpath, '/data/fields/moments', obj.knotsr, obj.knotsz, obj.femorder,ones(size(obj.CellVol)), 1, 1); charge=sum(sum(n(:,:,fieldstep))); end function Gamma=Axialflux(obj,timestep,zpos) % Computes the axial particle flux n*Uz at timestep timestep and axial position zpos Gamma=obj.fluidUZ(:,zpos,timestep).*obj.N(:,zpos,timestep); end function Gamma=Metallicflux(obj,timestep,subdiv) % Computes the particle flux at time obj.t2d(timestep) on the % metallic boundaries if nargin<3 subdiv=1; end % We find the borderpoints p=obj.borderpoints(subdiv); gamma=cell(size(p)); Nr=cell(size(p)); Nz=cell(size(p)); for i=1:length(p) bp=p{i}; if size(bp,1)==2 % We get the normals at these positions and normalise them Nr{i}=-interp2(obj.zgrid,obj.rgrid,obj.geomweight(:,:,3),bp(1,:),bp(2,:)); Nz{i}=-interp2(obj.zgrid,obj.rgrid,obj.geomweight(:,:,2),bp(1,:),bp(2,:)); norm=sqrt(Nr{i}.^2+Nz{i}.^2); Nr{i}=Nr{i}./norm; Nz{i}=Nz{i}./norm; else Nr{i}=bp(4,:); Nz{i}=bp(3,:); end gamma{i}=zeros(size(bp,2),length(timestep)); end [z,r]=ndgrid(obj.zgrid,obj.rgrid); N=obj.N(:,:,timestep(1)); n=griddedInterpolant(z,r,N'); uz=griddedInterpolant(z,r,obj.fluidUZ(:,:,timestep(1))'); ur=griddedInterpolant(z,r,obj.fluidUR(:,:,timestep(1))'); % we get the density and fluid velocities at the desired time % steps and interpolate them at the boundary position for j=1:length(timestep) n.Values=obj.N(:,:,timestep(j))'; uz.Values=obj.fluidUZ(:,:,timestep(j))'; ur.Values=obj.fluidUR(:,:,timestep(j))'; for i=1:length(p) bp=p{i}; gamma{i}(:,j)=n(bp(1:2,:)').*(ur(bp(1:2,:)').*Nr{i}'+uz(bp(1:2,:)').*Nz{i}'); end end % return the boundary position p and the corresponding flux % gamma Gamma.p=p; Gamma.gamma=gamma; end function [I, pos]=OutCurrents(obj,timestep, subdiv) % Computes the Outgoing currens at the simulation axial boundaries at timestep timestep % This is simply the surface integral of the axial flux if nargin<3 subdiv=1; end flux=obj.Axialflux(timestep,[1 obj.nz+1]); Iz=squeeze(trapz(obj.rgrid,flux.*obj.rgrid)*2*pi*obj.qsim/obj.weight); Iz(1,:)=-Iz(1,:); gamm=obj.Metallicflux(timestep, subdiv); Im=zeros(length(gamm.p),length(timestep)); pos=cell(size(gamm.p)); for i=1:length(gamm.p) p=gamm.p{i}; pos{i}=p; flux=gamm.gamma{i}; for j=1:length(timestep) Im(i,j)=pi/2*sum((p(2,1:end-1)+p(2,2:end)).*(flux(2:end,j)+flux(1:end-1,j))'... .*sqrt((p(1,2:end)-p(1,1:end-1)).^2+(p(2,2:end)-p(2,1:end-1)).^2)); end end I=-cat(1,Iz,Im*obj.qsim/obj.weight); end - function model=potentialwellmodel(obj,timestep) - % Computes the potential well at the given timestep and return the model to be able to - % interpolate either using grid coordinates or magnetic field line coordinates - % the potential well is calculated along each magnetic field - % line by taking the difference between a local potential well maximum - % and the maximum local minimum along the line on - % each side of the maximum - - % model.z and model.r are the axial and radial positions where - % the potential depth has been calculated and is used with a - % scatteredinterpolant to calculate the well depth at the - % desired position - % model.pot is the potential well depth - - % model.rathet is the magnetic field vector value at the - % corresponding position multiplied by the radial position - if iscell(timestep) - timestep=cell2mat(timestep); - end - % if one of the timesteps is 0 we take the external potential - id=find(timestep==0); - if(~isempty(id)) - timestep(id)=[]; - end - Phi=-obj.pot(:,:,timestep); - if(~isempty(id)) - phiext=-obj.potxt(:,:,1); - if isempty(obj.potxt) - phiext=-obj.pot(:,:,1); - end - Phi=cat(3,Phi(:,:,1:id-1),phiext,Phi(:,:,id:end)); - end - - % We get the magnetic field lines rA_theta values - %lvls=sort(unique([obj.rAthet(:,1)',obj.rAthet(:,end)', obj.rAthet(1,:),obj.rAthet(end,:)])); - Blines=obj.rAthet; - lvls=linspace(min(Blines(obj.geomweight(:,:,1)>0)),max(Blines(obj.geomweight(:,:,1)>0)),300); - Blines(obj.geomweight(:,:,1)<0)=NaN; - lvls(isnan(lvls))=[]; - - % We obtain the magnetic field lines coordinates for each - % level in r and z - contpoints=contourc(obj.zgrid,obj.rgrid,Blines,lvls(1:end)); - [x,y,zcont]=C2xyz(contpoints); - - % memory allocation for spped - - potfinal=zeros(numel(cell2mat(x)),length(timestep)); - Pot=cell(1,size(x,2)-1); - rathet=cell(1,size(x,2)-1); - [z,r]=ndgrid(obj.zgrid,obj.rgrid); - - % for each timestep we calculate the well - for i=1:length(timestep)+~isempty(id) - locPhi=Phi(:,:,i); - % We delete points outside of the domain - locPhi(obj.geomweight(:,:,1)<0)=0; - - - locPhi=griddedInterpolant(z,r,locPhi','makima'); - % For each field line we remove the lowest maximum - for j=1:size(x,2) - %for i=1:size(pot,1) - xloc=x{j}; - yloc=y{j}; - - rathet{j}=zcont(j)*ones(1,length(xloc)); - - if(length(xloc)>=3) - - Pot{j}=locPhi(xloc,yloc); - locpot=Pot{j}; - %locpot=locpot-min(locpot); - % along the given field line j we calculate the - % minimum on the left and right side of the - % position k and calculate the local well depth - for k=2:length(locpot)-1 - left=max(locpot(1:k-1)); - right=max(locpot(k+1:end)); - Pot{j}(k)=locpot(k)-min(left,right); - end - Pot{j}(1)=0; - Pot{j}(end)=0; - else - Pot{j}=zeros(size(xloc)); - end - end - potfinal(:,i)=cell2mat(Pot); - end - potfinal(potfinal>0)=NaN; - model.z=cell2mat(x); - model.r=cell2mat(y); - model.pot=-potfinal; - model.rathet=cell2mat(rathet); - end - function [pot] = PotentialWell(obj,fieldstep) %PotentialWell Computes the potential well at the given timestep on the FEM grid points % interpolates the model data on rgrid and zgrid model=obj.potentialwellmodel(fieldstep); z=model.z; r=model.r; modpot=model.pot; [Zmesh,Rmesh]=meshgrid(obj.zgrid,obj.rgrid); pot=zeros(length(obj.zgrid),length(obj.rgrid),length(fieldstep)); for i=1:length(fieldstep) pot(:,:,i)=griddata(z,r,modpot(:,i),Zmesh,Rmesh)'; end end function Epar = Epar(obj,fieldstep) % Computes the electric field component parallel to the magnetic field line Epar=obj.Er(:,:,fieldstep).*(obj.Br./obj.B)' + (obj.Bz./obj.B)'.*obj.Ez(:,:,fieldstep); end function Eperp = Eperp(obj,fieldstep) % Computes the electric field component perpendicular to the magnetic field line Eperp=obj.Er(:,:,fieldstep).*(obj.Bz./obj.B)' - (obj.Br./obj.B)'.*obj.Ez(:,:,fieldstep); end function Ekin = Ekin(obj,varargin) %Ekin Computes the classical kinetic energy of particles indices{1} at % time obj.tpart(indices{2}) in Joules if(~iscell(varargin)) indices=mat2cell(varargin); else indices=varargin; end if strcmp(indices{1},':') p=1:obj.R.nparts; else p=indices{1}; end if strcmp(indices{2},':') t=1:length(obj.tpart); else t=indices{2}; end % if track is true we look at specific particles with their % index and follow them in time % if it is false we just care about the distribution function % and specific particles can have different positions in the % resulting array for each timestep if size(indices,1)>2 track=indices{3}; else track=false; end Vr=obj.VR(p,t,track); Vthet= obj.VTHET(p,t,track); Vz=obj.VZ(p,t,track); Ekin=0.5*obj.msim/obj.weight*(Vr.^2+Vthet.^2+Vz.^2); end function sig=sigio(obj,E,init) %sigio returns the total ionisation cross-section in m^2 % at energy E[eV] % init is only used during the loading of the h5 file if nargin <3 init=false; end sig=zeros(size(E)); if(~init &&( ~obj.neutcol.present || isempty(obj.neutcol.io_cross_sec))) sig=zeros(size(E)); return end for i=1:length(E(:)) if(E(i)>obj.neutcol.Eion) sig(ind2sub(size(E),i))=obj.fit_cross_sec(E(ind2sub(size(E),i)),obj.neutcol.io_cross_sec); end end end function sig=sigmio(obj,E) %sigmio returns the total ionisation cross-section for momentum exchange for the incoming electron in m^2 % at energy E[eV] sig=zeros(size(E)); if(~obj.neutcol.present || isempty(obj.neutcol.iom_cross_sec)) return end for i=1:length(E(:)) if(E(i)>obj.neutcol.Eion) sig(ind2sub(size(E),i))=obj.fit_cross_sec(E(ind2sub(size(E),i)),obj.neutcol.iom_cross_sec); end end end function sigm=sigmela(obj,E) %sigmela returns the elastic collision cross-section for momentum exchange for the incoming electron in m^2 % at energy E[eV] sigm=zeros(size(E)); if(~obj.neutcol.present || isempty(obj.neutcol.ela_cross_sec)) return end for i=1:length(E(:)) sigm(ind2sub(size(E),i))=obj.fit_cross_sec(E(ind2sub(size(E),i)),obj.neutcol.ela_cross_sec); end end function sig=sigela(obj,E) %sigmela returns the elastic collision cross-section for the incoming electron in m^2 % at energy E[eV] % if used this will give the frequency of elastic collisions E0=obj.neutcol.E0; chi=E./(0.25*E0+E); sig=(2*chi.^2)./((1-chi).*((1+chi).*log((1+chi)./(1-chi))-2*chi)).*obj.sigmela(E); end function [Forces, Density]=Forcespline(obj,it,fdens,getmean) %Forcesplie calculates the fluid force terms in each direction %at time obj.t2d(it) % if fdens return the force density in N/m^3 othewise give % the force in N % if getmean return only the time averaged quanties over % time samples[it(1)...it(end] if strcmp(it,':') it=floor(0.95*size(obj.t2d)):size(obj.t2d)-1; end if nargin<3 fdens=true; end if nargin <4 getmean=false; end % To be able to calculate the centered finite difference in % time, we remove the first and last time indices it(it<2)=[]; it(it>length(obj.t2d)-1)=[]; m_e=obj.msim/obj.weight; q_e=obj.qsim/obj.weight; n=obj.N(:,:,it); [r,~]=meshgrid(obj.rgrid,obj.zgrid); Rinv=1./r'; Rinv(isinf(Rinv))=0; % get inverse of density to get the force in N Density.N=n; invn=1./n; invn(isnan(invn) | isinf(invn))=0; % Calculate electric forces Eforcer=q_e*obj.Er(:,:,it); Eforcez=q_e*obj.Ez(:,:,it); Dragforcer=zeros(size(n,1),size(n,2),size(n,3)); Dragforcethet=zeros(size(n,1),size(n,2),size(n,3)); Dragforcez=zeros(size(n,1),size(n,2),size(n,3)); time=obj.t2d(it); Forces.it=it; Forces.time=time; if getmean if ~fdens n=ones(size(n)); end % Electric forces Forces.Eforcer=mean(n.*q_e.*obj.Er(:,:,it),3); Forces.Eforcez=mean(n.*q_e.*obj.Ez(:,:,it),3); % Magnetic forces Forces.Bforcer=mean(q_e.*obj.fluidUTHET(:,:,it).*obj.Bz'.*n,3); Forces.Bforcethet=mean(q_e.*(obj.fluidUZ(:,:,it).*obj.Br'-obj.fluidUR(:,:,it).*obj.Bz').*n,3); Forces.Bforcez=mean(-q_e.*obj.fluidUTHET(:,:,it).*obj.Br'.*n,3); % Inertial forces Forces.inertforcer=mean(-m_e.*n.*(-obj.fluidUTHET(:,:,it).^2.*Rinv... +obj.fluidUR(:,:,it).*obj.fluidUR.der(:,:,it,[1 0])... +obj.fluidUZ(:,:,it).*obj.fluidUR.der(:,:,it,[0 1])),3); Forces.inertforcethet=mean(-m_e*n.*(obj.fluidUR(:,:,it).*obj.fluidUTHET(:,:,it).*Rinv... +obj.fluidUR(:,:,it).*obj.fluidUTHET.der(:,:,it,[1 0])... +obj.fluidUZ(:,:,it).*obj.fluidUTHET.der(:,:,it,[0 1])),3); Forces.inertforcez=mean(-m_e*n.*(obj.fluidUR(:,:,it).*obj.fluidUZ.der(:,:,it,[1 0])... +obj.fluidUZ(:,:,it).*obj.fluidUZ.der(:,:,it,[0 1])),3); % Pressure forces Forces.Pressforcer=mean(-n.*( squeeze(obj.Presstens.der(1,:,:,it,[1 0]))... + squeeze(obj.Presstens(1,:,:,it) - obj.Presstens(4,:,:,it)).*Rinv... + squeeze(obj.Presstens.der(3,:,:,it,[0 1])))... .*invn,3); Forces.Pressforcethet=mean(-n.*( squeeze(obj.Presstens.der(2,:,:,it,[1 0]))... + squeeze(obj.Presstens.der(5,:,:,it,[0 1])) ... + 2*squeeze(obj.Presstens(2,:,:,it)).*Rinv ... ).*invn,3); Forces.Pressforcez=mean(-n.*( squeeze(obj.Presstens.der(3,:,:,it,[1 0]))... + squeeze(obj.Presstens(3,:,:,it)).*Rinv... + squeeze(obj.Presstens.der(6,:,:,it,[0 1])) )... .*invn,3); % ellastic coll drag forces if( obj.neutcol.present) Ek=squeeze(obj.fluidEkin(1,:,:,it)+obj.fluidEkin(2,:,:,it)+obj.fluidEkin(3,:,:,it)); sigm=obj.sigmela(Ek/obj.qe)+obj.sigio(Ek/obj.qe)+obj.sigmio(Ek/obj.qe); dragfreq=obj.neutcol.neutdens.*sigm.*sqrt(2*obj.weight/obj.msim*Ek); Forces.Dragforcer=mean(-m_e*n.*dragfreq.*obj.fluidUR(:,:,it),3); Forces.Dragforcethet=mean(-m_e*n.*dragfreq.*obj.fluidUTHET(:,:,it),3); Forces.Dragforcez=mean(-m_e*n.*dragfreq.*obj.fluidUZ(:,:,it),3); else Forces.Dragforcer=0; Forces.Dragforcethet=0; Forces.Dragforcez=0; end % effective drag frequency due to the maxwellian source if( obj.maxwellsrce.present) dragfreqsrc=obj.maxwellsrce.frequency*obj.weight/(pi*diff(obj.maxwellsrce.zlim)*(obj.maxwellsrce.rlim(2)^2-obj.maxwellsrce.rlim(1)^2)).*invn; dragfreqsrc(isinf(dragfreqsrc))=0; Forces.Dragforcer=Forces.Dragforcer+mean(-n.*m_e.*dragfreqsrc.*obj.fluidUR(:,:,it),3); Forces.Dragforcethet=Forces.Dragforcethet+mean(-n.*m_e.*dragfreqsrc.*obj.fluidUTHET(:,:,it),3); Forces.Dragforcez=Forces.Dragforcez+mean(-n.*m_e.*dragfreqsrc.*obj.fluidUZ(:,:,it),3); end % Time derivative for fluid accelleration cdt=(obj.t2d(it+1)-obj.t2d(it-1)); cdt=reshape(cdt,1,1,[]); Forces.durdt=mean(m_e*(obj.fluidUR(:,:,it+1)-obj.fluidUR(:,:,it-1))./cdt,3); Forces.duthetdt=mean(m_e*(obj.fluidUTHET(:,:,it+1)-obj.fluidUTHET(:,:,it-1))./cdt,3); Forces.duzdt=mean(m_e*(obj.fluidUZ(:,:,it+1)-obj.fluidUZ(:,:,it-1))./cdt,3); else % Allocate memory Bforcer=zeros(size(n,1),size(n,2),size(n,3)); Bforcez=zeros(size(n,1),size(n,2),size(n,3)); Bforcethet=zeros(size(n,1),size(n,2),size(n,3)); inertforcer=zeros(size(n,1),size(n,2),size(n,3)); inertforcez=zeros(size(n,1),size(n,2),size(n,3)); inertforcethet=zeros(size(n,1),size(n,2),size(n,3)); Pressforcer=zeros(size(n,1),size(n,2),size(n,3)); Pressforcethet=zeros(size(n,1),size(n,2),size(n,3)); Pressforcez=zeros(size(n,1),size(n,2),size(n,3)); durdt=zeros(size(n,1),size(n,2),size(n,3)); duthetdt=zeros(size(n,1),size(n,2),size(n,3)); duzdt=zeros(size(n,1),size(n,2),size(n,3)); fluiduThet=obj.fluidUTHET(:,:,it); Density.fluiduThet=fluiduThet; for j=1:size(n,3) % Magnetic forces Bforcer(:,:,j)=q_e.*fluiduThet(:,:,j).*obj.Bz'; Bforcethet(:,:,j)=q_e.*(obj.fluidUZ(:,:,it(j)).*obj.Br'-obj.fluidUR(:,:,it(j)).*obj.Bz'); Bforcez(:,:,j)=-q_e.*fluiduThet(:,:,j).*obj.Br'; % Inertial forces inertforcer(:,:,j)=-m_e.*(-fluiduThet(:,:,j).^2.*Rinv... +obj.fluidUR(:,:,it(j)).*obj.fluidUR.der(:,:,it(j),[1 0])... +obj.fluidUZ(:,:,it(j)).*obj.fluidUR.der(:,:,it(j),[0 1])); inert1=obj.fluidUR(:,:,it(j)).*fluiduThet(:,:,j).*Rinv; inert2=obj.fluidUR(:,:,it(j)).*obj.fluidUTHET.der(:,:,it(j),[1 0]); inert3=obj.fluidUZ(:,:,it(j)).*obj.fluidUTHET.der(:,:,it(j),[0 1]); inertforcethet(:,:,j)=-m_e.*(inert1... +inert2... +inert3); inertforcez(:,:,j)=-m_e.*(obj.fluidUR(:,:,it(j)).*obj.fluidUZ.der(:,:,it(j),[1 0])... +obj.fluidUZ(:,:,it(j)).*obj.fluidUZ.der(:,:,it(j),[0 1])); % Pressure forces Pr1=squeeze(obj.Presstens.der(1,:,:,it(j),[1 0])); Pr2=squeeze(obj.Presstens(1,:,:,it(j)) - obj.Presstens(4,:,:,it(j))).*Rinv; Pr3=squeeze(obj.Presstens.der(3,:,:,it(j),[0 1])); Pressforcer(:,:,j)=-( Pr1... + Pr2... + Pr3 )... .*invn(:,:,j); Pthet1=squeeze(obj.Presstens.der(2,:,:,it(j),[1 0])); Pthet2=squeeze(obj.Presstens.der(5,:,:,it(j),[0 1])); Pthet3=2*squeeze(obj.Presstens(2,:,:,it(j))).*Rinv; Pressforcethet(:,:,j)=-( Pthet1... + Pthet2 ... + Pthet3 ... ).*invn(:,:,j); Pz1=squeeze(obj.Presstens.der(3,:,:,it(j),[1 0])); Pz2=squeeze(obj.Presstens(3,:,:,it(j))).*Rinv; Pz3=squeeze(obj.Presstens.der(6,:,:,it(j),[0 1])); Pressforcez(:,:,j)=-( Pz1... + Pz2... + Pz3 )... .*invn(:,:,j); % ellastic coll drag forces if( obj.neutcol.present) Ek=squeeze(obj.fluidEkin(1,:,:,it(j))+obj.fluidEkin(2,:,:,it(j))+obj.fluidEkin(3,:,:,it(j))); sigm=obj.sigmela(Ek/obj.qe)+obj.sigio(Ek/obj.qe)+obj.sigmio(Ek/obj.qe); dragfreq=obj.neutcol.neutdens.*sigm.*sqrt(2*obj.weight/obj.msim*Ek); Dragforcer(:,:,j)=-m_e*dragfreq.*obj.fluidUR(:,:,it(j)); Dragforcethet(:,:,j)=-m_e*dragfreq.*obj.fluidUTHET(:,:,it(j)); Dragforcez(:,:,j)=-m_e*dragfreq.*obj.fluidUZ(:,:,it(j)); end % effective drag frequency due to the maxwellian source if( obj.maxwellsrce.present) dragfreqsrc=obj.maxwellsrce.frequency*obj.weight/(pi*diff(obj.maxwellsrce.zlim)*(obj.maxwellsrce.rlim(2)^2-obj.maxwellsrce.rlim(1)^2))*invn(:,:,j); dragfreqsrc(isinf(dragfreqsrc))=0; Dragforcer(:,:,j)=Dragforcer(:,:,j)+-m_e*dragfreqsrc.*obj.fluidUR(:,:,it(j)); Dragforcethet(:,:,j)=Dragforcethet(:,:,j)+-m_e*dragfreqsrc.*obj.fluidUTHET(:,:,it(j)); Dragforcez(:,:,j)=Dragforcez(:,:,j)+-m_e*dragfreqsrc.*obj.fluidUZ(:,:,it(j)); end % Time derivative cdt=(obj.t2d(it(j)+1)-obj.t2d(it(j)-1)); durdt(:,:,j)=m_e*(obj.fluidUR(:,:,it(j)+1)-obj.fluidUR(:,:,it(j)-1))/cdt; duthetdt(:,:,j)=m_e*(obj.fluidUTHET(:,:,it(j)+1)-obj.fluidUTHET(:,:,it(j)-1))/cdt; duzdt(:,:,j)=m_e*(obj.fluidUZ(:,:,it(j)+1)-obj.fluidUZ(:,:,it(j)-1))/cdt; end if(~fdens) Forces.Eforcer=Eforcer; Forces.Eforcez=Eforcez; Forces.Bforcer=Bforcer; Forces.Bforcethet=Bforcethet; Forces.Bforcez=Bforcez; Forces.inertforcer=inertforcer; Forces.inertforcethet=inertforcethet; Forces.inertforcez=inertforcez; Forces.Pressforcer=Pressforcer; Forces.Pressforcethet=Pressforcethet; Forces.Pressforcez=Pressforcez; Forces.durdt=durdt; Forces.duthetdt=duthetdt; Forces.duzdt=duzdt; Forces.Dragforcer=Dragforcer; Forces.Dragforcethet=Dragforcethet; Forces.Dragforcez=Dragforcez; else % multiply by density to have force density Forces.Eforcer=Eforcer.*n; Forces.Eforcez=Eforcez.*n; Forces.Bforcer=Bforcer.*n; Forces.Bforcethet=Bforcethet.*n; Forces.Bforcez=Bforcez.*n; Forces.inertforcer=inertforcer.*n; Forces.inertforcethet=inertforcethet.*n; Forces.inertforcez=inertforcez.*n; Forces.Pressforcer=Pressforcer.*n; Forces.Pressforcethet=Pressforcethet.*n; Forces.Pressforcez=Pressforcez.*n; Forces.durdt=durdt.*n; Forces.duthetdt=duthetdt.*n; Forces.duzdt=duzdt.*n; Forces.Dragforcer=Dragforcer.*n; Forces.Dragforcethet=Dragforcethet.*n; Forces.Dragforcez=Dragforcez.*n; end end end function [lr,rb,lz,zb]= clouddims(obj,it,zpos,fracn) % clouddims return the cloud axial and radial limit at time it % and axial position zpos % fracn defines the fraction of the maximum density below which % we consider to have a vacuum if nargin<4 fracn=0.1; end % get the density n=obj.N(:,:,it); lr=cell(1,length(it)); lz=lr; rb=lr; zb=rb; for i=1:size(n,3) nthresh=fracn*max(max(n(:,:,i))); % find the points outside of the cloud outside=find(n(:,zpos,i)2) rmpos=outside(j); rppos=outside(j+1); lr{i}(k)=obj.rgrid(rppos-1)-obj.rgrid(rmpos+1); rb{i}(:,k)=[max(rmpos+1,1) min(rppos-1,sum(obj.nnr))]; k=k+1; end end maxgap=2; k=1; for I=rmpos+1:rppos-1 outside=find(n(I,:,i)maxgap) maxgap=zgap(j); zmpos=outside(j); zppos=outside(j+1); lz{i}(k)=obj.zgrid(zppos-1)-obj.zgrid(zmpos+1); zb{i}(:,k)=[max(zmpos+1,1) min(zppos-1,obj.nz)]; k=k+1; end end end end end %------------------------------------------ % Functions for plotting evolving quantities function displaysplbound(obj,ax,rescale) %displaysplbound display on axis ax the boundary of the %simulation domain and the Dirichlet and Neumann walls defined %with spline curves if nargin<2 ax=gca; end if nargin<3 rescale=1; end hold on for i=1:obj.spl_bound.nbsplines knots=obj.spl_bound.boundary(i).knots(1:end); coeffs=obj.spl_bound.boundary(i).coefs'*rescale; pp=spmak(knots,coeffs); sizec=size(coeffs,2); order=length(knots)-sizec; s=linspace(knots(order),knots(sizec+1),1000); fittedpos=fnval(pp,s); plot(fittedpos(1,:),fittedpos(2,:),'-') plot(coeffs(1,:),coeffs(2,:),'rx','markersize',14) end end function displayraddim(obj,it,zpos,fracn) %displayraddim display the evolution of the radial dimension of the cloud in %time to find if the cloud size get below a critical radial %size at which the ionisation is not sufficient to compensate %the losses % also plot the well radial dimensions in time if nargin<3 zpos=floor(length(obj.zgrid)/2); end if nargin<4 fracn=0.1; end [lr,rb,lz,zb]=obj.clouddims(it,zpos,fracn); t=obj.t2d(it); Lr=zeros(size(lr)); er=obj.Er(:,:,it); r_min=Lr; r_minpred=r_min; well_r=Lr; nb=Lr; for i=1:length(lr) if ~isempty(lr{i}) && ~isempty(lz{i}) [Lr(i),id]=max(lr{i}); rm=rb{i}(1,id); rp=rb{i}(2,id); nb(i)=mean(obj.N(rm:rp,zpos,it(i))); Lp=min(lz{i}); Lm=mean(lz{i}); rpos=rm:rp; vperp=-er(rpos,zpos,i)./obj.Bz(zpos,rpos)'; Ek=0.5*obj.me*vperp.^2/obj.qe; sigio=obj.sigio(Ek); sigd=obj.sigmela(Ek)+obj.sigmio(Ek)+sigio; omegap2=obj.qe^2*obj.N(rpos,zpos,it(i))/obj.eps_0/obj.me; omegac2=(obj.qe*obj.Bz(zpos,rpos)'/obj.me).^2; ur=er(rpos,zpos,i)*obj.qe./((omegap2-omegac2)*obj.me).*sigd.*vperp*obj.neutcol.neutdens; r_minpred(i)=mean(obj.N(rp,zpos,it(i))*Lp*ur./(nb(i)*obj.neutcol.neutdens*sigio.*vperp*Lm));%mean(1./(-1/obj.rgrid(rm)+obj.neutcol.neutdens*sigio.*vperp./ur*(Lm/Lp)*nb(i)/obj.N(rp,zpos,it(i)))); rpos=rp; vperp=-er(rpos,zpos,i)./obj.Bz(zpos,rpos)'; Ek=0.5*obj.me*vperp.^2/obj.qe; sigio=obj.sigio(Ek); ur=obj.fluidUR(rpos,zpos,it(i)); r_min(i)=max(obj.N(rp,zpos,it(i))*Lp*ur/(nb(i)*obj.neutcol.neutdens*sigio.*vperp*Lm),0);%max(mean(1./(-1/obj.rgrid(rm)+obj.neutcol.neutdens*sigio.*vperp./ur*(Lm/Lp)*nb(i)/obj.N(rp,zpos,it(i)))),0); nb(i)=nb(i)*Lm*2*pi*obj.rgrid(rm)*Lr(i); else Lr(i)=NaN; r_min(i)=NaN; r_minpred(i)=NaN; end potwell=obj.PotentialWell(it(i))'; outside=find(isnan(potwell(:,zpos))); gap=diff(outside); for j=1:length(gap) if(gap(j)>2) rmpos=outside(j)+1; rppos=outside(j+1)-1; well_r(i)=obj.rgrid(rppos)-obj.rgrid(rmpos); end end end f=figure('Name', sprintf('%s rlims B=%f phi=%f',obj.name,obj.B0, obj.phinorm*(obj.potout-obj.potinn))); plot(t,Lr,'displayname','\Deltar_{cloud}','linewidth',1.3) hold on plot(t,r_min,'displayname','\Deltar_{min} (u_r simu)','linewidth',1.3) plot(t,r_minpred,'displayname','\Deltar_{min} (u_r pred)','linewidth',1.3) plot(t,well_r,'displayname','\Deltar_{well}','linewidth',1.3) ylabel('\Delta r [m]') yyaxis right plot(t,nb,'--','displayname','N') legend('location','eastoutside') xlabel('t [s]') ylabel('N') set(gca,'fontsize',12) yyaxis left ylimits=ylim; %ylim([ylimits(1) 1.1*max(Lr)]) title(sprintf('cloud radial limits at z=%1.2e[m]',obj.zgrid(zpos))) obj.savegraph(f,sprintf('%s/%s_%d_rlims',obj.folder,obj.name,zpos),[15 10]); end function displaypsi(obj,deltat) %% plot the initial and final radial profile at position z=0 and show the normalized enveloppe function Psi % relevant for Davidson annular distribution function f=figure('Name', sprintf('%s Psi',obj.name)); f.Name= sprintf('%s Psi',obj.name); zpos=floor(length(obj.zgrid)/2); tinit=1; tend=length(obj.t2d); if iscell(deltat) deltat=cell2mat(deltat); end if(obj.R.nt<2) h0=obj.H0; p0=obj.P0; else h0=mean(H(obj,{1:obj.VR.nparts,obj.VR.nt,false})); p0=mean(P(obj,{1:obj.VR.nparts,obj.VR.nt,false})); end lw=1.5; Mirrorratio=(obj.Rcurv-1)/(obj.Rcurv+1); locpot=mean(obj.pot(:,zpos,tend-deltat:tend),3); psi=1+obj.qe*locpot(:)/h0-1/(2*obj.me*h0)*(p0./obj.rgrid+obj.qe*0.5*obj.B0.*(obj.rgrid-obj.width/pi*Mirrorratio*cos(2*pi*obj.zgrid(zpos)/obj.width)*besseli(1,2*pi*obj.rgrid/obj.width))).^2; locdens=mean(obj.N(:,zpos,tend-deltat:tend),3); [maxn,In]=max(locdens);%M.N(:,zpos,tinit)); plot(obj.rgrid,obj.N(:,zpos,tinit),'bx-','DisplayName',sprintf('t=%1.2f[ns]',obj.t2d(tinit)*1e9),'linewidth',lw) hold on plot(obj.rgrid,locdens,'rx-','DisplayName',sprintf('t=[%1.2f-%1.2f] [ns] averaged',obj.t2d(tend-deltat)*1e9,obj.t2d(tend)*1e9),'linewidth',lw) plot(obj.rgrid(In-2:end),1./obj.rgrid(In-2:end)*maxn*obj.rgrid(In),'DisplayName','N=c*1/r','linewidth',lw) plot(obj.rgrid(In-2:end),1./obj.rgrid(In-2:end).^2*maxn*obj.rgrid(In)^2,'DisplayName','N=c*1/r^2','linewidth',lw) plot(obj.rgrid(In-2:end),1./obj.rgrid(In-2:end).^4*maxn*obj.rgrid(In)^4,'DisplayName','N=c*1/r^4','linewidth',lw) xlabel('r [m]') ylabel('n_e [m^{-3}]') I=find(psi>0); if (length(I)>1) I=[I(1)-2; I(1)-1; I; I(end)+1; I(end)+2]; else I=obj.nnr(1):length(psi); end rq=linspace(obj.rgrid(max(I(1),1)),obj.rgrid(I(end)),500); psiinterp=interp1(obj.rgrid(I),psi(I),rq,'pchip'); zeroindices=find(diff(psiinterp>=0),2); maxpsiinterp=max(psiinterp); plot(rq,maxn*psiinterp/abs(maxpsiinterp),'Displayname','normalized \Psi [a.u.]','linewidth',lw) ylim([0 inf]) for i=1:length(zeroindices) border=plot([rq(zeroindices(i)) rq(zeroindices(i))],[0 obj.rgrid(In)/obj.rgrid(In-2)*maxn],'k--','linewidth',lw); set(get(get(border,'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); end legend xlim([0 0.02]) grid on title(sprintf('Radial density profile at z=%1.2e[m]',obj.zgrid(zpos))) obj.savegraph(f,sprintf('%sPsi',obj.name),[15 10]); end function f=displayrprofile(obj,t,zpos,init) %% plot the initial and final radial profile at the axial center of the simulation space % also plot the azimuthal fluid rotation frequency profile % t: time index considered % zpos: axial position index % init: initial time considered for comparison f=figure('Name', sprintf('%s Prof',obj.name)); if nargin < 3 || length(zpos)<1 zpos=floor(length(obj.zgrid)/2); end if nargin<4 init=false; end if(iscell(t)) t=cell2mat(t); end lw=1.5; if init tinit=t(1); t=t(2:end); end locdens=mean(obj.N(:,zpos,t),3); %inverse of radius Rinv=1./obj.rgrid; Rinv(isnan(Rinv))=0; %azimuthal velocity and azimuthal rotation frequency in m/s and %1/s vthet=mean(obj.fluidUTHET(:,zpos,t),3); omegare=(vthet.*Rinv); % plot the initial density if(init) plot(obj.rgrid,obj.N(:,zpos,tinit),'bx-','DisplayName',sprintf('t=%1.2f[ns]',obj.t2d(tinit)*1e9),'linewidth',lw) end hold on %plot the time averaged current density plot(obj.rgrid,locdens,'rx-','DisplayName',sprintf('t=[%1.2f-%1.2f] [ns] averaged',obj.t2d(t(1))*1e9,obj.t2d(t(end))*1e9),'linewidth',lw) xlabel('r [m]') ylabel('n_e [m^{-3}]') legend('location','Northwest') % limit the axis to the simulation domain if obj.conformgeom xlim([obj.rgrid(1) obj.rgrid(sum(obj.nnr(1:2)))]) else xlim([obj.rgrid(1) obj.rgrid(end)]) end grid on ylimits=ylim(); % plot the metallic walls for a constant radius coaxial % configuration if obj.conformgeom plot(obj.rgrid(1)*[1 1],ylimits,'k--') plot(obj.rgrid(end)*[1 1],ylimits,'k--') else plot(obj.r_a*[1 1],ylimits,'k--') if obj.walltype==0 plot(obj.r_b*[1 1],ylimits,'k--') elseif obj.walltype==1 rmax=obj.r_0-obj.r_r*sqrt(1-(obj.zgrid(zpos)-obj.z_0)^2/obj.z_r^2); plot(rmax*[1 1],ylimits,'k--') end end yyaxis right % plot the azimuthal fluid rotation frequency profile plot(obj.rgrid,omegare,'DisplayName',sprintf('<\\omega_{re}> t=[%1.2f-%1.2f] [ns] averaged',obj.t2d(t(1))*1e9,obj.t2d(t(end))*1e9),'linewidth',lw) ylabel('\omega_{re} [1/s]') title(sprintf('Radial density profile at z=%1.2e[m]',obj.zgrid(zpos))) obj.savegraph(f,sprintf('%srProf',obj.name),[15 10]); end function displayenergy(obj) %% Plot the time evolution of the system energy and number of simulated macro particles tmin=1; tmax=length(obj.ekin); f=figure('Name', sprintf('%s Energy',obj.name)); subplot(2,1,1) plot(obj.t0d(tmin:tmax),obj.ekin(tmin:tmax),'o-',... obj.t0d(tmin:tmax),obj.epot(tmin:tmax),'d-',... obj.t0d(tmin:tmax),obj.etot(tmin:tmax),'h-',... obj.t0d(tmin:tmax),obj.etot0(tmin:tmax),'h-',... obj.t0d(tmin:tmax),obj.eerr(tmin:tmax),'x--') %obj.t0d(tmin:tmax),obj.ekin(tmin:tmax)-obj.epot(tmin:tmax),'--', legend('E_{kin}', 'E_{pot}', 'E_{tot}','E_{ref}','E_{err}') xlabel('Time [s]') ylabel('Energies [J]') grid on xlimits=xlim(); subplot(2,1,2) try semilogy(obj.t0d(tmin:tmax),abs(obj.eerr(tmin:tmax)./obj.etot0(tmin:tmax)),'h-') catch semilogy(obj.t0d(tmin:tmax),abs(obj.eerr(tmin:tmax)/obj.etot(2)),'h-') end + hold on xlabel('t [s]') ylabel('E_{err}/E_{tot}') xlim(xlimits) grid on try yyaxis right plot(obj.t0d(tmin:tmax),abs(obj.npart(tmin:tmax)./obj.npart(1)*100),'d--') ylabel('Nparts %') %ylim([0 110]) catch end + ylimits=ylim; + for i=1:length(obj.restarttimes) + plot(obj.restarttimes(i)*[1 1],ylimits,'k--') + end + obj.savegraph(f,sprintf('%s/%sEnergy',obj.folder,obj.name)); end function f=displaycharge(obj,f,linelegend) %% Plot the time evolution of the system charge of electrons % f: figure handle if you want to stack several such curves % on the same figure % linelegend: legend for this charge evolution tmin=1; tmax=length(obj.ekin); if nargin<2 f=figure('Name', sprintf('%s Charge',obj.name)); end if nargin<3 linelegend=''; end ax=f.CurrentAxes; if isempty(ax) ax=axes(f); end try plot(ax,obj.t0d(tmin:tmax),abs(obj.npart(tmin:tmax)*obj.qsim),'linewidth',1.5,'displayname',linelegend) hold on ylabel(ax,'Total charge [C]') xlabel(ax,'t [s]') grid on if(nargin>2) legend end set(ax,'fontsize',12) catch end if nargin < 2 obj.savegraph(f,sprintf('%s/%scharge',obj.folder,obj.name)); end end function displaySimParticles(obj) %% Plot the time evolution of the number of simulated markers in the main specie f=figure('Name', sprintf('%s Trapped particles',obj.name)); plot(obj.t0d,obj.npart,'linewidth',1.5) xlabel('t [s]') ylabel('N particles') set(gca,'fontsize',12) obj.savegraph(f,sprintf('%s/%sntrapped',obj.folder,obj.name),[10 12]); end function displayLarmorRad(obj,time2d) if nargin<2 time2d=length(obj.t2d); end % Plot the larmor radius for created particles with low energy % the larmor radius is calculated by considering that the % initial perpendicular velocity \approx the ExB velocity - rl=abs(obj.me/obj.qe*(-obj.Er(:,:,time2d).*obj.Bz'+obj.Ez(:,:,time2d).*obj.Br')./(obj.B.^3)'); + if time2d>0 + Er=obj.Er(:,:,time2d); + Ez=obj.Ez(:,:,time2d); + else + Er=obj.Erxt(:,:,1); + Ez=obj.Ezxt(:,:,1); + end + + rl=abs(obj.me/obj.qe*(-Er.*obj.Bz'+Ez.*obj.Br')./(obj.B.^3)'); figure rl(obj.geomweight(:,:,1)<0)=0; contourf(obj.zgrid,obj.rgrid,rl) hold on contour(obj.zgrid,obj.rgrid,obj.geomweight(:,:,1),[0 0],'r-','linewidth',3) - n=obj.N(:,:,time2d); - maxN=max(n (:)); - n=n/maxN*mean(rl(:)); - contour(obj.zgrid,obj.rgrid,n,linspace(0,1,6)*mean(rl(:)),'r:','linewidth',3) + if time2d>0 + n=obj.N(:,:,time2d); + maxN=max(n (:)); + n=n/maxN*mean(rl(:)); + contour(obj.zgrid,obj.rgrid,n,linspace(0,1,6)*mean(rl(:)),'r:','linewidth',3) + end c=colorbar; xlabel('z [m]') ylabel('r [m]') c.Label.String='r_L [m]'; end function displayHP(obj,tstart) % Plot the histogramm of the total energy and canonical angular momentum at time tstart and % end time of the simulation over the full simulation space for the main specie if(iscell(tstart)) tstart=cell2mat(tstart); end if(obj.R.nt>=2) tstart=obj.R.nt; f=figure('Name', sprintf('%s HP',obj.name)); legtext=sprintf("t=%2.1f - %2.1f [ns]",obj.tpart(tstart)*1e9,obj.tpart(end)*1e9); subplot(1,2,1) partsmax=min(obj.nbparts(end),obj.R.nparts); Hloc=H(obj,{1:obj.nbparts(1),1,false}); h1=histogram(Hloc,20,'BinLimits',[min(Hloc(:)) max(Hloc(:))],'DisplayName',sprintf("t=%2.3d [ns]",obj.tpart(1)*1e9)); hold on Hloc=H(obj,{1:partsmax,obj.R.nt,false}); %,'Binwidth',h1.BinWidth h1=histogram(Hloc,20,'BinLimits',[min(Hloc(:)) max(Hloc(:))],'DisplayName',legtext); ylabel('counts') xlabel('H [J]') legend subplot(1,2,2) Ploc=P(obj,{1:obj.nbparts(1),1,false}); h2=histogram(Ploc,50,'BinLimits',[min(Ploc(:)) max(Ploc(:))],'DisplayName',sprintf("t=%2.3d [ns]",obj.tpart(1)*1e9)); hold on Ploc=P(obj,{1:partsmax,obj.R.nt,false}); histogram(Ploc,50,'BinLimits',[min(Ploc(:)) max(Ploc(:))],'DisplayName',legtext); ylabel('counts') xlabel('P [kg\cdotm^2\cdots^{-1}]') %clear P %clear H legend %xlim([0.95*h2.BinLimits(1) 1.05*h2.BinLimits(2)]) obj.savegraph(f,sprintf('%s/%sParts_HP',obj.folder,obj.name)); end end function displayaveragetemp(obj) % Computes and show the particles average temperature as a function of time f=figure('Name',sprintf('%s potinn=%f part temperature',obj.name,obj.potinn*obj.phinorm)); vr2=obj.VR(:,:,false); vr2=mean(vr2.^2,1)-mean(vr2,1).^2; vz2=obj.VZ(:,:,false); vz2=mean(vz2.^2,1)-mean(vz2,1).^2; vthet2=obj.VTHET(:,:,false); vthet2=mean(vthet2.^2,1)-mean(vthet2,1).^2; plot(obj.tpart,0.5*obj.me*vr2/obj.qe,'displayname','T_r') hold on plot(obj.tpart,0.5*obj.me*vz2/obj.qe,'displayname','T_z') plot(obj.tpart,0.5*obj.me*vthet2/obj.qe,'displayname','T_{thet}') xlabel('time [s]') ylabel('T [eV]') title(sprintf('\\phi_a=%.1f kV \\phi_b=%.1f kV R=%.1f',obj.potinn*obj.phinorm/1e3,obj.potout*obj.phinorm/1e3,obj.Rcurv)) legend grid obj.savegraph(f,sprintf('%s/%s_partstemp',obj.folder,obj.name)); end function displayCurrentsevol(obj,timesteps) % Computes and display the time evolution of the outgoing currents on each domain boundary % at timesteps timesteps if nargin<2 timesteps=1:length(obj.t2d); end currents=obj.OutCurrents(timesteps); f=figure('Name',sprintf('%s Currents',obj.name)); if(obj.B(1,1)>obj.B(end,1)) lname='HFS'; rname='LFS'; else lname='LFS'; rname='HFS'; end plot(obj.t2d(timesteps),currents(1,:),'Displayname',lname,'linewidth',1.8); hold on plot(obj.t2d(timesteps),currents(2,:),'Displayname',rname,'linewidth',1.8); plot(obj.t2d(timesteps),currents(3,:),'Displayname','outer cylinder','linewidth',1.8); plot(obj.t2d(timesteps),currents(4,:),'Displayname','inner cylinder','linewidth',1.8); if size(currents,1)>=5 plot(obj.t2d(timesteps),currents(5,:),'Displayname','ellipse','linewidth',1.8); end legend('location','Northeast') xlabel('time [s]') ylabel('I [A]') grid on set(gca,'fontsize',12) title(sprintf('\\phi_b-\\phi_a=%.2g kV, R=%.1f',(obj.potout-obj.potinn)*obj.phinorm/1e3,obj.Rcurv)) obj.savegraph(f,sprintf('%s/%s_outCurrents',obj.folder,obj.name),[16 12]); end function displayChargeLossevol(obj,timesteps,toptitle,scalet,dens) % Computes and display the time evolution of the outgoing currents on each domain boundary % at time obj.t2d(timesteps) %scalet=true scales the time by the ellastic collision %frequency %dens = true plot the time evolution of the maximum electron %density in the simulation domain otherwise plot the total %number of electrons in the domain if nargin<2 timesteps=1:length(obj.t2d); end if nargin<4 scalet=true; end if nargin <5 dens=true; end if scalet if obj.neutcol.present vexb0=(obj.Ez(:,:,1).*obj.Br'-obj.Er(:,:,1).*obj.Bz')./(obj.B'.^2); vexb0(obj.geomweight(:,:,1)<=0)=0; E=0.5*obj.msim/obj.weight*mean(abs(vexb0(:)))^2/obj.qe; taucol=1/(obj.neutcol.neutdens*mean(abs(vexb0(:)))*(obj.sigio(E)+obj.sigmela(E)+obj.sigmio(E))); try Sio_S=1e17*(obj.neutcol.neutdens*mean(abs(vexb0(:)))*obj.sigio(E))/(obj.maxwellsrce.frequency*obj.weight/(pi*(obj.maxwellsrce.rlim(2)^2-obj.maxwellsrce.rlim(1)^2)*diff(obj.maxwellsrce.zlim))) catch end tlabel='t/\tau_d [-]'; else taucol=2*pi/obj.omece; tlabel='t/\tau_ce [-]'; end else taucol=1e-9; tlabel='t [ns]'; end if dens N=obj.N(:,:,timesteps); geomw=obj.geomweight(:,:,1); geomw(geomw<0)=0; geomw(geomw>0)=1; N=N.*geomw; nmax=squeeze(max(max(N,[],1),[],2)); tn=(obj.t2d(timesteps)); nlabel='n_{e,max} [m^{-3}]'; ndlabel='n_{e,max}'; else t0dst=find(obj.t0d>=obj.t2d(timesteps(1)),1,'first'); t0dlst=find(obj.t0d<=obj.t2d(timesteps(end)),1,'last'); tn=obj.t0d(t0dst:t0dlst); nmax=obj.npart(t0dst:t0dlst)*obj.weight; nlabel='Nb e^-'; ndlabel='Nb e^-'; end [currents,pos]=obj.OutCurrents(timesteps); P=obj.neutcol.neutdens*obj.kb*300/100;% pressure at room temperature in mbar currents=currents/P; f=figure('Name',sprintf('%s Charges',obj.name)); % Plot the evolution of nb of particles yyaxis right p=plot(tn/taucol,nmax,'b-.','linewidth',1.8,'Displayname',ndlabel); ylabel(nlabel) ax=gca; ax.YAxis(2).Color=p.Color; ylim([0 inf]) if(obj.B(1,1)>obj.B(end,1)) lname='HFS'; rname='LFS'; else lname='LFS'; rname='HFS'; end yyaxis left mincurr=max(currents(:))*5e-3; if (max(currents(1,:)>mincurr)) plot(obj.t2d(timesteps)/taucol,currents(1,:),'r:','Displayname',lname,'linewidth',1.8); end hold on if (max(currents(2,:)>mincurr)) plot(obj.t2d(timesteps)/taucol,currents(2,:),'r--','Displayname',rname,'linewidth',1.8); end if (max(currents(3,:)>mincurr)) plot(obj.t2d(timesteps)/taucol,currents(3,:),'r-','Displayname','outer cylinder','linewidth',1.8); end if (max(currents(4,:)>mincurr)) plot(obj.t2d(timesteps)/taucol,currents(4,:),'Displayname','inner cylinder','linewidth',1.8); end if (size(currents,1)>=5 && max(currents(5,:)>mincurr)) plot(obj.t2d(timesteps)/taucol,currents(5,:),'r-','Displayname','ellipse','linewidth',1.8); end xlabel(tlabel) ylabel('I/p_n [A/mbar]') grid on set(gca,'fontsize',12) ax.YAxis(1).Color='red'; legend('Orientation','horizontal','location','south','numcolumns',3) if nargin <3 title(sprintf('\\phi_b-\\phi_a=%.2g kV, B=%f T',(obj.potout-obj.potinn)*obj.phinorm/1e3,max(obj.B(:)))) elseif ~isempty(toptitle) title(toptitle) end obj.savegraph(f,sprintf('%s/%s_ChargeEvol%i%i',obj.folder,obj.name,scalet,dens),[16 14]); end function displaytotcurrevol(obj,timesteps,toptitle,scalet,dens,subdiv,nmean) % Computes and display the time evolution of the outgoing % currents at time obj.t2d(timesteps) %scalet=true scales the time by the ellastic collision %frequency %dens = true plot the time evolution of the maximum electron %density in the simulation domain otherwise plot the total %number of electrons in the domain % also plot in a subplot the color coded boundary corresponding % to each current if nargin<2 timesteps=1:length(obj.t2d); end if nargin<3 scalet=true; end if nargin <4 dens=true; end if nargin<5 subdiv=1; end if nargin<6 nmean=1; end if scalet if obj.neutcol.present vexb0=(obj.Ez(:,:,1).*obj.Br'-obj.Er(:,:,1).*obj.Bz')./(obj.B'.^2); vexb0(obj.geomweight(:,:,1)<=0)=0; E=0.5*obj.msim/obj.weight*mean(abs(vexb0(:)))^2/obj.qe; taucol=1/(obj.neutcol.neutdens*mean(abs(vexb0(:)))*(obj.sigio(E)+obj.sigmela(E)+obj.sigmio(E))); try Sio_S=1e17*(obj.neutcol.neutdens*mean(abs(vexb0(:)))*obj.sigio(E))/(obj.maxwellsrce.frequency*obj.weight/(pi*(obj.maxwellsrce.rlim(2)^2-obj.maxwellsrce.rlim(1)^2)*diff(obj.maxwellsrce.zlim))) catch end tlabel='t/\tau_d [-]'; else taucol=2*pi/obj.omece; tlabel='t/\tau_ce [-]'; end else taucol=1e-9; tlabel='t [ns]'; end if dens N=obj.N(:,:,timesteps); geomw=obj.geomweight(:,:,1); geomw(geomw<0)=0; geomw(geomw>0)=1; N=N.*geomw; %[~,idl]=max(N(:,:,end),[],'all','linear'); %[ir,iz]=ind2sub(size(geomw),idl); - nmax=squeeze(max(max(N,[],1),[],2)); - %nmax=squeeze(N(ir,iz,:)); + %nmax=squeeze(max(max(N,[],1),[],2)); tn=(obj.t2d(timesteps)); + nmax=zeros(2,length(tn)); + nrhalf=find(obj.rgrid>0.07); + + nmax(1,:)=squeeze(max(max(N(1:nrhalf,:,:),[],1),[],2)); + nmax(2,:)=squeeze(max(max(N(nrhalf+1:end,:,:),[],1),[],2)); + + nlabel='n_{e,max} [m^{-3}]'; ndlabel='n_{e,max}'; else t0dst=find(obj.t0d>=obj.t2d(timesteps(1)),1,'first'); t0dlst=find(obj.t0d<=obj.t2d(timesteps(end)),1,'last'); tn=obj.t0d(t0dst:t0dlst); nmax=obj.npart(t0dst:t0dlst)*obj.weight; nlabel='Nb e^-'; ndlabel='Nb e^-'; end [currents,pos]=obj.OutCurrents(timesteps,subdiv); P=obj.neutcol.neutdens*obj.kb*300/100;% pressure at room temperature in mbar currents=currents/P; f=figure('Name',sprintf('%s Charges',obj.name)); tiledlayout(2,1) nexttile % Plot the evolution of nb of particles yyaxis right - p=plot(tn/taucol,nmax,'b-.','linewidth',1.8,'Displayname',ndlabel); + for i=1:size(nmax,1) + p=plot(tn/taucol,nmax(i,:),'b','linewidth',1.8,'Displayname',sprintf('%s, %d',ndlabel,i)); + hold on + end ylabel(nlabel) axl=gca; axl.YAxis(2).Color=p.Color; ylim([0 inf]) if(obj.B(1,1)>obj.B(end,1)) lname='HFS'; rname='LFS'; else lname='LFS'; rname='HFS'; end yyaxis( 'left'); map=colormap(lines); set(axl,'linestyleorder',{'-',':','--','*','+'},... 'ColorOrder',map(2:7,:), 'NextPlot','replacechildren') p(1)=plot(axl,obj.t2d(timesteps)/taucol,movmean(currents(1,:),nmean),'Displayname',lname,'linewidth',1.8); hold on p(2)=plot(axl,obj.t2d(timesteps)/taucol,movmean(currents(2,:),nmean),'Displayname',rname,'linewidth',1.8); % Plot the currents for i=3:size(currents,1) p(i)=plot(axl,obj.t2d(timesteps)/taucol,movmean(currents(i,:),nmean),'Displayname',sprintf('border %i',i-2),'linewidth',1.8); end plot(axl,obj.t2d(timesteps)/taucol,movmean(sum(currents(:,:),1,'omitnan'),nmean),'k-','Displayname','total','linewidth',1.8); xlabel(tlabel) ylabel('I/p_n [A/mbar]') grid on set(gca,'fontsize',12) ax.YAxis(1).Color='black'; %legend('Orientation','horizontal','location','north','numcolumns',3) if ~isempty(toptitle) title(toptitle) end ax2=nexttile; geomw=obj.geomweight(:,:,1); geomw(geomw<=0)=0; geomw(geomw>0)=NaN; [c1,hContour]=contourf(ax2,obj.zgrid*1000,obj.rgrid*1000,geomw, [0 0]); hold on drawnow; grid on; for i=1:length(pos) plot(ax2,pos{i}(1,:)*1000,pos{i}(2,:)*1000,'linestyle',p(i+2).LineStyle,... 'color',p(i+2).Color,'marker',p(i+2).Marker,... 'displayname',sprintf('border %i',i),'linewidth',1.8) hold on end title('Domain') plot(ax2,ones(size(obj.rgrid))*obj.zgrid(1)*1000,obj.rgrid*1000,'linestyle',p(1).LineStyle,... 'color',p(1).Color,'marker',p(1).Marker,... 'displayname',lname,'linewidth',1.8) plot(ax2,ones(size(obj.rgrid))*obj.zgrid(end)*1000,obj.rgrid*1000,'linestyle',p(2).LineStyle,... 'color',p(2).Color,'marker',p(2).Marker,... 'displayname',rname,'linewidth',1.8) xlabel('z [mm]') ylabel('r [mm]') grid on set(gca,'fontsize',12) hFills=hContour.FacePrims; [hFills.ColorType] = deal('truecoloralpha'); % default = 'truecolor' try hFills(1).ColorData = uint8([150;150;150;255]); for idx = 2 : numel(hFills) hFills(idx).ColorData(4) = 0; % default=255 end catch end %legend('Orientation','horizontal','location','north','numcolumns',4) fprintf('mean total current: %f [A/mbar]\n',mean(sum(currents(:,max(1,size(currents,2)-30):end),1,'omitnan'))); %if nargin <3 % sgtitle(sprintf('\\phi_b-\\phi_a=%.2g kV, B=%f T',(obj.potout-obj.potinn)*obj.phinorm/1e3,mean(obj.B(:)))) %elseif ~isempty(toptitle) % sgtitle(toptitle) %end if length(subdiv)>1 obj.savegraph(f,sprintf('%s/%s_totIEvol%i%i_div',obj.folder,obj.name,scalet,dens),[16 14]); else obj.savegraph(f,sprintf('%s/%s_totIEvol%i%i',obj.folder,obj.name,scalet,dens),[16 14]); end end function display2Dpotentialwell(obj,timestep,rcoord,clims) % Display the 2D potential well at time obj.t2d(timestep) % if rcoord is true, the potential is evaluated at grid points in r,z coordinates % if false, the potential is evaluated at grid points in magnetic field line coordinates % clims are the values limits in eV for the color coding of the % potential well if iscell(timestep) timestep=cell2mat(timestep); end if nargin <3 rcoord=true; end if nargin<4 clims=[-inf inf]; end f=figure('Name',sprintf('%s Potential well',obj.name)); ax1=gca; model=obj.potentialwellmodel(timestep); z=model.z; r=model.r; Pot=model.pot; rathet=model.rathet; - if (timestep==0) - title(sprintf('Potential well Vacuum')) - else - title(sprintf('Potential well t=%1.2f [ns]',obj.t2d(timestep)*1e9)) - end + N0=obj.N(:,:,1); id=find(timestep==0); timestep(id)=[]; Nend=obj.N(:,:,timestep); if(~isempty(id)) N0=zeros(obj.N.nr,obj.N.nz); Nend=cat(3,Nend(:,:,1:id-1),N0,Nend(:,:,id:end)); end Nend=mean(Nend,3); geomw=obj.geomweight(:,:,1); %z(isnan(Pot))=[]; %r(isnan(Pot))=[]; %Pot(isnan(Pot))=[]; if rcoord [Zmesh,Rmesh]=meshgrid(obj.zgrid,obj.rgrid); Pot=griddata(z,r,Pot,Zmesh,Rmesh,'natural'); %Pot(obj.geomweight(:,:,1)<=0)=NaN; contourf(obj.zgrid(1:end)*1e3,obj.rgrid(1:end)*1e3,Pot(1:end,1:end),40,'edgecolor','none','Displayname','Well') xlabel('z [mm]') ylabel('r [mm]') xlim([obj.zgrid(1) obj.zgrid(end)]*1e3) ylim([obj.rgrid(1) obj.rgrid(end)]*1e3) hold(gca, 'on') rdisp=obj.rgrid; %% Magnetic field lines Blines=obj.rAthet; levels=linspace(min(Blines(obj.geomweight(:,:,1)>0)),max(Blines(obj.geomweight(:,:,1)>0)),20); Blines(obj.geomweight(:,:,1)<0)=NaN; - [~,h1]=contour(obj.zgrid*1000,obj.rgrid*1000,Blines,real(levels),'k-.','linewidth',1,'Displayname','Magnetic field lines'); + [~,h1]=contour(obj.zgrid*1000,obj.rgrid*1000,Blines,real(levels),'k-.','linewidth',0.8,'Displayname','Magnetic field lines'); else rdisp=sort(obj.rAthet(:,end)); [Zmesh,Rmesh]=meshgrid(obj.zgrid,rdisp); Pot=griddata(z,rathet,Pot,Zmesh,Rmesh); [Zinit,~]=meshgrid(obj.zgrid,obj.rAthet(:,1)); % if isempty(obj.maxwellsrce) % end N0=griddata(Zinit,obj.rAthet,N0,Zmesh,Rmesh); Nend=griddata(Zinit,obj.rAthet,Nend,Zmesh,Rmesh); geomw=griddata(Zinit,obj.rAthet,geomw,Zmesh,Rmesh); Pot(geomw<=0)=0; surface(obj.zgrid(1:end),rdisp,Pot(1:end,1:end),'edgecolor','none') ylabel('rA_\theta [Tm^2]') xlabel('z [m]') xlim([obj.zgrid(1) obj.zgrid(end)]) ylim([min(rdisp) max(rdisp)]) hold(gca, 'on') end + if (timestep==0) + title(sprintf('Potential well Vacuum')) + else + title(sprintf('Potential well t=%1.2f [ns]',obj.t2d(timestep)*1e9)) + end maxdensend=max(Nend(:)); contourscale=0.1; Nend=(Nend-contourscale*maxdensend)/maxdensend; maxdens0=max(N0(:)); contourscale=0.1; N0=(N0-contourscale*maxdens0)/maxdens0; contour(obj.zgrid*1e3,rdisp*1e3,Nend,linspace(0,1-contourscale,5),'k--','linewidth',1.5,'Displayname','Cloud Boundaries'); contour(obj.zgrid*1e3,rdisp*1e3,N0,[0 0],'k-.','linewidth',1.5,'Displayname','Source boundaries'); %contour(obj.zgrid*1e3,rdisp*1e3,geomw,[0 0],'-','linecolor',[0.5 0.5 0.5],'linewidth',1.5,'Displayname','Vessel Boundaries'); c=colorbar; colormap('jet'); % Grey outline showing the metalic walls geomw(obj.geomweight(:,:,1)>0)=-1; geomw(obj.geomweight(:,:,1)<=0)=1; [c1,hContour]=contourf(ax1,obj.zgrid*1000,obj.rgrid*1000,geomw, [0 0]); drawnow; xlim(ax1,[obj.zgrid(1)*1000 obj.zgrid(end)*1000]) if(obj.conformgeom) ylim([ax1 ],[obj.rgrid(1)*1000 obj.rgrid(rgridend)*1000]) else ylim([ax1],[obj.rgrid(1)*1000 obj.rgrid(end)*1000]) end %ylim(ax1,[0.05*1000 obj.rgrid(end)*1000]) %xlim([obj.zgrid(1) 0.185]*1e3) xlabel(ax1,'z [mm]') ylabel(ax1,'r [mm]') view(ax1,2) c.Label.String= 'depth [eV]'; f.PaperUnits='centimeters'; caxis(clims) grid on; hFills=hContour.FacePrims; [hFills.ColorType] = deal('truecoloralpha'); % default = 'truecolor' try drawnow hFills(1).ColorData = uint8([150;150;150;255]); for idx = 2 : numel(hFills) hFills(idx).ColorData(4) = 0; % default=255 end catch end % add central and external metallic walls if we have a coaxial % configuration if( obj.walltype >=2 && obj.walltype<=4) rectangle('Position',[obj.zgrid(1) obj.r_b obj.zgrid(end)-obj.zgrid(1) 0.001]*1e3,'FaceColor',[150 150 150]/255,'Edgecolor','none') ylimits=ylim; ylim([ylimits(1),ylimits(2)+1]) end if sum(obj.geomweight(:,1,1))==0 rectangle('Position',[obj.zgrid(1) obj.r_a-0.001 obj.zgrid(end)-obj.zgrid(1) 0.001]*1e3,'FaceColor',[150 150 150]/255,'Edgecolor','none') ylimits=ylim; ylim([ylimits(1)-1,ylimits(2)]) end %axis equal + %xlim([-100 200]) [max_depth,id]=max(abs(Pot(:))); [idr,idz]=ind2sub(size(Pot),id); fprintf('Maximum potential wel depth: %f eV\n',max_depth) fprintf('at location r=%f z=%f [mm]\n',obj.rgrid(idr)*1e3, obj.zgrid(idz)*1e3) papsize=[14 8]; if rcoord obj.savegraph(f,sprintf('%s/%s_wellr%i',obj.folder,obj.name,floor(mean(timestep))),papsize); else obj.savegraph(f,sprintf('%s/%s_wellpsi%i',obj.folder,obj.name,floor(mean(timestep))),papsize); end end function display1Dpotentialwell(obj,timestep,rpos) % Display the potential well along the magentic field line % passing by rgrid(rpos) at the center of the simulation space if iscell(timestep) timestep=cell2mat(timestep); end f=figure('Name',sprintf('%s 1D Potential well',obj.name)); model=obj.potentialwellmodel(timestep); z=model.z; r=model.r; Pot=model.pot; rathet=model.rathet; if (mod(rpos, 1) ~= 0) [~,rpos]=min(abs(M.rgrid-rpos)); end crpos=obj.rgrid(rpos); id=find(timestep==0); timestep(id)=[]; n=obj.N(:,:,timestep); if(~isempty(timestep==0)) N0=zeros(obj.N.nr+1,obj.N.nz+1); n=cat(3,n(:,:,1:id-1),N0,n(:,:,id:end)); end n=mean(n,3); linepot=zeros(length(obj.zgrid),length(timestep)); rathetpos=obj.rAthet(rpos,ceil(length(obj.zgrid)/2)); F=scatteredInterpolant(z',rathet',Pot(:,1)); for i=1:length(timestep) F=scatteredInterpolant(z',rathet',Pot(:,i)); linepot(:,i)=F(obj.zgrid,rathetpos*ones(size(obj.zgrid))); %linepot(:,i)=griddata(z,rathet,pot(:,i),obj.zgrid,rathetpos); end linepot=mean(linepot,2); [Zinit,~]=meshgrid(obj.zgrid,obj.rAthet(:,1)); n=griddata(Zinit,obj.rAthet,n,obj.zgrid,rathetpos); plot(obj.zgrid,linepot) ylabel('Potentiel [eV]') xlabel('z [m]') xlim([obj.zgrid(1) obj.zgrid(end)]) hold(gca, 'on') yyaxis right plot(obj.zgrid,n) ylabel('n [m^{-3}]') if length(timestep)==1 title(sprintf('Potential well t=%1.2f [ns] r=%1.2f [mm]',obj.t2d(timestep)*1e9,1e3*crpos)) else title(sprintf('Potential well t=[%1.2f-%1.2f] [ns] r=%1.2f [mm]',obj.t2d(timestep(1))*1e9,obj.t2d(timestep(end))*1e9,1e3*crpos)) end obj.savegraph(f,sprintf('%s/%s_well1Dr_%d',obj.folder,obj.name,rpos)); end function displayVdistribRThetZ(obj,timestep, rpos, zpos) %displayVdistribRThetZ plot the velocity distribution function % in m/s %extracted from the markers at position window from rpos(1) %rpos(end) and zpos(1) to zpos(end) % and at time obj.tpart(timestep) %rpos and zpos are given as grid indices if(obj.R.nt>=2) if nargin<2 timesteppart=length(obj.tpart); else timesteppart=timestep; end if nargin<3 || isempty(rpos) rpos=1:length(obj.rgrid); rspan=[obj.rgrid(1) obj.rgrid(end)]; else r=[obj.rgrid(1);(obj.rgrid(1:end-1)+obj.rgrid(2:end))*0.5;obj.rgrid(end)]; rspan=[r(rpos) r(rpos+1)]; end if nargin<4 || isempty(zpos) zpos=1:length(obj.zgrid); zspan=[obj.zgrid(1) obj.zgrid(end)]; else z=[obj.zgrid(1);(obj.zgrid(1:end-1)+obj.zgrid(2:end))*0.5;obj.zgrid(end)]; zspan=[z(zpos) z(zpos+1)]; end nbp=min(obj.nbparts(1),obj.R.nparts); R=obj.R(1:nbp,1,false); Z=obj.Z(1:nbp,1,false); Vr=obj.VR(1:nbp,1,false); Vz=obj.VZ(1:nbp,1,false); Vthet=obj.VTHET(1:nbp,1,false); ids=R>=rspan(1) & R<=rspan(2) & Z>=zspan(1) & Z<=zspan(2); Vr=Vr(ids); Vz=Vz(ids); Vthet=Vthet(ids); vTr=std(Vr,1); vTz=std(Vz,1); vTthet=std(Vthet,1); nbp=min(obj.nbparts(timesteppart),obj.R.nparts); Rend=obj.R(1:nbp,timesteppart,false); Zend=obj.Z(1:nbp,timesteppart,false); Vrend=obj.VR(1:nbp,timesteppart,false); Vzend=obj.VZ(1:nbp,timesteppart,false); Vthetend=obj.VTHET(1:nbp,timesteppart,false); ids=Rend>=rspan(1) & Rend<=rspan(2) & Zend>=zspan(1) & Zend<=zspan(2); nbtot=sum(ids) Vrend=Vrend(ids); Vzend=Vzend(ids); Vthetend=Vthetend(ids); vTrend=std(Vrend,1); vTzend=std(Vzend,1); vTthetend=std(Vthetend,1); binwidth=abs(max(Vrend)-min(Vrend))/sqrt(length(Vrend)); f=figure('Name',sprintf("%s vrz distrib",obj.file)); [~,time2did]=min(abs(obj.t2d-obj.tpart(timestep))); subplot(1,4,1); obj.dispV(Vr,Vrend,'V_r [m/s]',[1,timesteppart]) [~,time2did]=min(abs(obj.t2d-obj.tpart(timestep))); if length(rpos)==1 vexb=-obj.Er(rpos,zpos,time2did)/obj.Bz(zpos,rpos)'; vexb=mean(vexb(:)); if ~isempty(obj.neutcol.ela_cross_sec) % plot the radial drift velocity as nu_dE_r/(B\Omega_c) vdr=obj.neutcol.neutdens*obj.sigmela(vexb^2*obj.me*0.5/obj.qe)*vexb*-obj.Er(rpos,zpos,time2did)... ./(obj.B(zpos,rpos)'.*obj.B(zpos,rpos)'*obj.qe/obj.me); vdr=mean(vdr(:)); ylimits=ylim; plot(vdr*[1 1],ylimits,'k--','displayname',sprintf('V_{d,pred}=%1.2g [m/s]',vdr)) end end subplot(1,4,2); obj.dispV(Vthet,Vthetend,'V\theta [m/s]',[1,timesteppart]) hold on drawnow ylimits=ylim; if length(rpos)==1 if ~isempty(obj.Erxt) vexbext=-obj.Erxt(rpos,zpos)/obj.Bz(zpos,rpos)'; plot(vexbext*[1 1],ylimits,'k--','displayname',sprintf('V_{ExB,ext}=%1.2g [m/s]',vexbext)) end plot(vexb*[1 1],ylimits,'k-.','displayname',sprintf('V_{ExB,tot}=%1.2g [m/s]',vexb)) end subplot(1,4,3); obj.dispV(Vz,Vzend,'Vz [m/s]',[1,timesteppart]) subplot(1,4,4); obj.dispV(sqrt(Vr.^2+(Vthet).^2+Vz.^2),sqrt(Vrend.^2+(Vthetend).^2+Vzend.^2),'Vtot [m/s]',[1,timesteppart],'maxwell') sgtitle(sprintf('t=%1.2e[ns] r=[%2.1f, %2.1f] [mm] z=[%2.1f, %2.1f] [mm]',obj.tpart(timestep)*1e9, rspan*1e3, zspan*1e3)) obj.savegraph(f,sprintf('%s/%sParts_V_RZ',obj.folder,obj.name),[25 14]); end end function displayEkin(obj,timestep, rpos, zpos) %displayEkin plot the kinetic energy distribution function in %eV %extracted from the markers at position window from rpos(1) %rpos(end) and zpos(1) to zpos(end) % and at time obj.tpart(timestep) %rpos and zpos are given as grid indices if(obj.R.nt>=2) if nargin<2 timesteppart=[1 length(obj.tpart)]; else if length(timestep)<2 timesteppart=[1 timestep]; else timesteppart=[timestep(1) timestep(end)]; end end if nargin<3 || isempty(rpos) rspan=[obj.rgrid(1) obj.rgrid(end)]; else r=[obj.rgrid(1);(obj.rgrid(1:end-1)+obj.rgrid(2:end))*0.5;obj.rgrid(end)]; rspan=[r(rpos) r(rpos+1)]; end if nargin<4 || isempty(zpos) zspan=[obj.zgrid(1) obj.zgrid(end)]; else z=[obj.zgrid(1);(obj.zgrid(1:end-1)+obj.zgrid(2:end))*0.5;obj.zgrid(end)]; zspan=[z(zpos) z(zpos+1)]; end nbp=min(obj.nbparts(timesteppart(1)),obj.R.nparts); R=obj.R(1:nbp,timesteppart(1),false); Z=obj.Z(1:nbp,timesteppart(1),false); Ekin=obj.Ekin(1:nbp,timesteppart(1),false); ids=R>=rspan(1) & R<=rspan(2) & Z>=zspan(1) & Z<=zspan(2); Ekin=Ekin(ids)/obj.qe; nbp=min(obj.nbparts(timesteppart(2)),obj.R.nparts); Rend=obj.R(1:nbp,timesteppart(2),false); Zend=obj.Z(1:nbp,timesteppart(2),false); Ekinend=obj.Ekin(1:nbp,timesteppart(2),false); ids=Rend>=rspan(1) & Rend<=rspan(2) & Zend>=zspan(1) & Zend<=zspan(2); Ekinend=Ekinend(ids)/obj.qe; f=figure('Name',sprintf("%s E_k distrib",obj.file)); obj.dispV(Ekin,Ekinend,'E_k',timesteppart,'maxwell') sgtitle(sprintf('dt=%1.2e[ns] r=[%2.1f, %2.1f] [mm] z=[%2.1f, %2.1f] [mm]',obj.dt*1e9, rspan*1e3, zspan*1e3)) obj.savegraph(f,sprintf('%s/%sParts_E_kin',obj.folder,obj.name)); end end function displayVdistribParPer(obj,timestep, rpos, zpos, gcs) %displayVdistribParPer plot the velocity distribution function % in m/s for the parallel and perpendicular velocity %extracted from the markers at position window from rpos(1) %rpos(end) and zpos(1) to zpos(end) % and at time obj.tpart(timestep) %rpos and zpos are given as grid indices % gcs define if you give the perpendicular velocity in the % guiding center frame or in the laboratory frame if(obj.R.nt>=2) if nargin<2 timesteppart=length(obj.tpart); else timesteppart=timestep; end if nargin<3 || isempty(rpos) rspan=[obj.rgrid(1) obj.rgrid(end)]; else r=[obj.rgrid(1);(obj.rgrid(1:end-1)+obj.rgrid(2:end))*0.5;obj.rgrid(end)]; rspan=[r(rpos) r(rpos+1)]; end if nargin<4 || isempty(zpos) zspan=[obj.zgrid(1) obj.zgrid(end)]; else z=[obj.zgrid(1);(obj.zgrid(1:end-1)+obj.zgrid(2:end))*0.5;obj.zgrid(end)]; zspan=[z(zpos) z(zpos+1)]; end if nargin<5 gcs=false; % define if we look in the guiding center system end nbp=min(obj.nbparts(1),obj.R.nparts); R=obj.R(1:nbp,1,false); Z=obj.Z(1:nbp,1,false); ids=R>=rspan(1) & R<=rspan(2) & Z>=zspan(1) & Z<=zspan(2); Vperp=obj.Vperp(1:nbp,1,false,gcs); Vpar=obj.Vpar(1:nbp,1,false); Vperp=Vperp(ids); Vpar=Vpar(ids); nbp=min(obj.nbparts(timesteppart),obj.R.nparts); R=obj.R(1:nbp,timesteppart,false); Z=obj.Z(1:nbp,timesteppart,false); ids=R>=rspan(1) & R<=rspan(2) & Z>=zspan(1) & Z<=zspan(2); Vperpend=obj.Vperp(1:nbp,timesteppart,false,gcs); Vparend=obj.Vpar(1:nbp,timesteppart,false); Vperpend=Vperpend(ids); Vparend=Vparend(ids); %binwidth=abs(max(Vparend)-min(Vparend))/500; f=figure('Name',sprintf("%s v parper distrib",obj.file)); subplot(1,2,1) if gcs lgd='v_\perp gcs [m/s]'; else lgd='v_\perp [m/s]'; end obj.dispV(Vperp,Vperpend,lgd,[1,timesteppart], 'maxwell') subplot(1,2,2) obj.dispV(abs(Vpar),abs(Vparend),'v_{par} [m/s]',[1,timesteppart],'None') sgtitle(sprintf('t=%1.2e[ns] r=[%2.1f, %2.1f] [mm] z=[%2.1f, %2.1f] [mm]',obj.tpart(timestep)*1e9, rspan*1e3, zspan*1e3)) obj.savegraph(f,sprintf('%s/%sParts_V_parper',obj.folder,obj.name)); if gcs obj.savegraph(f,sprintf('%s/%sParts_V_parpergcs',obj.folder,obj.name)); else obj.savegraph(f,sprintf('%s/%sParts_V_parper',obj.folder,obj.name)); end end end function display2DVdistrib(obj,timestep, rpos, zpos, gcs) %display2DVdistrib plot the velocity distribution function % in m/s for the parallel and perpendicular velocity % and for the radial azimuthal velocity % as a 2D contour plot the show the velocity phase space distribution %extracted from the markers at position window from rpos(1) %rpos(end) and zpos(1) to zpos(end) % and at time obj.tpart(timestep) %rpos and zpos are given as grid indices % gcs define if you give the perpendicular velocity in the % guiding center frame or in the laboratory frame if(obj.R.nt>=2) if nargin<2 timesteppart=length(obj.tpart); else timesteppart=timestep; end if nargin<3 || isempty(rpos) rspan=[obj.rgrid(1) obj.rgrid(end)]; else r=[obj.rgrid(1);(obj.rgrid(1:end-1)+obj.rgrid(2:end))*0.5;obj.rgrid(end)]; rspan=[r(rpos(1)) r(rpos(end)+1)]; end if nargin<4 || isempty(zpos) zspan=[obj.zgrid(1) obj.zgrid(end)]; else z=[obj.zgrid(1);(obj.zgrid(1:end-1)+obj.zgrid(2:end))*0.5;obj.zgrid(end)]; zspan=[z(zpos(1)) z(zpos(end)+1)]; end if nargin<5 gcs=false; % define if we look in the guiding center system end nbp=min(obj.nbparts(timesteppart),obj.R.nparts); R=obj.R(1:nbp,timesteppart,false); Z=obj.Z(1:nbp,timesteppart,false); ids=R>=rspan(1) & R<=rspan(2) & Z>=zspan(1) & Z<=zspan(2); Vperp=obj.Vperp(1:nbp,timesteppart,false,gcs); Vpar=obj.Vpar(1:nbp,timesteppart,false); Vr=obj.VR(1:nbp,timesteppart,false); Vthet=obj.VTHET(1:nbp,timesteppart,false); Vper=Vperp(ids); Vpar=Vpar(ids); Vr=Vr(ids); Vthet=Vthet(ids); nbp=sum(ids(:)); f=figure('Name',sprintf("%s v parper distrib",obj.file)); subplot(2,1,1) [N,Xedges,Yedges] = histcounts2(Vpar,Vper,20); Xedges=(Xedges(1:end-1)+Xedges(2:end))/2; Yedges=(Yedges(1:end-1)+Yedges(2:end))/2; contourf(Xedges,Yedges,N') xlabel('v_{par} [m/s]') ylabel('v_{\perp} [m/s]') c=colorbar; c.Label.String='Counts'; subplot(2,1,2) [N,Xedges,Yedges] = histcounts2(Vthet,Vr,20); Xedges=(Xedges(1:end-1)+Xedges(2:end))/2; Yedges=(Yedges(1:end-1)+Yedges(2:end))/2; contourf(Xedges,Yedges,N') %histogram2(Vthet,Vr,'displaystyle','tile','binmethod','auto') %scatter(Vthet,Vr) xlabel('v_\theta [m/s]') ylabel('v_r [m/s]') c=colorbar; c.Label.String='Counts'; sgtitle(sprintf('t=%1.2e[ns] r=[%2.1f, %2.1f] [mm] z=[%2.1f, %2.1f] [mm] N=%3i',mean(obj.tpart(timestep))*1e9, rspan*1e3, zspan*1e3,nbp)) mkdir(sprintf('%s/vdist',obj.folder)) if gcs obj.savegraph(f,sprintf('%s/vdist/%sParts_V_2dparpergcs_r%iz%it%i',obj.folder,obj.name,floor(mean(rpos)),floor(mean(zpos)),floor(mean(timestep)))); else obj.savegraph(f,sprintf('%s/vdist/%sParts_V_2dparper_r%iz%it%i',obj.folder,obj.name,floor(mean(rpos)),floor(mean(zpos)),floor(mean(timestep)))); end end end function [p, maxnb, c]=displayPhaseSpace(obj,type,partsstep, Rindex, Zindex,legendtext, figtitle, f, maxnb, c, gcs) if nargin<8 f=figure; f=gca; end if nargin<7 figtitle=sprintf('r=%1.2f [mm] z=%1.2f [mm] \\Delta\\phi=%1.1f[kV] R=%1.1f',obj.rgrid(Rindex)*1e3,obj.zgrid(Zindex)*1e3,(obj.potout-obj.potinn)*obj.phinorm/1e3,obj.Rcurv); end if nargin <6 legendtext=sprintf('t=%1.3g [s]',obj.tpart(partsstep)); end fieldstep=find(obj.tpart(partsstep(end))==obj.t2d,1); if nargin>=10 ctemp=c; n=zeros(length(c{1}),length(c{2})); else nbins=15; n=zeros(nbins); end if nargin <11 gcs=true; end for i=1:length(partsstep) odstep=find(obj.tpart(partsstep(i))==obj.t0d); nbp=min(obj.R.nparts,obj.nbparts(partsstep(i))); Rp=obj.R(1:nbp,partsstep(i),false); Zp=obj.Z(1:nbp,partsstep(i),false); deltar=obj.dr(2)/2; deltarm=obj.rgrid(Rindex)-sqrt(obj.rgrid(Rindex)^2-deltar^2-2*obj.rgrid(Rindex)*deltar); deltaz=obj.dz/2; Indices=Rp>=obj.rgrid(Rindex)-deltarm & Rp=obj.zgrid(Zindex)-deltaz & Zp0)),max(Blines(obj.geomweight(:,:,1)>0)),20); + Blines(obj.geomweight(:,:,1)<0)=NaN; + [~,h1]=contour(ax1,obj.zgrid*1000,obj.rgrid*1000,Blines,real(levels),'-.','color','k','linewidth',1.5,'Displayname','Magnetic field lines'); + + % Draw the metallic boundaries and the geometry itself + [c1,hContour]=contourf(ax1,obj.zgrid*1000,obj.rgrid*1000,-geomw,[0,0],'linewidth',1.5); + drawnow; + xlim(ax1,[obj.zgrid(1)*1000 obj.zgrid(end)*1000]) + % Change the color of the metallic boundaries to grey + hFills=hContour.FacePrims; + [hFills.ColorType] = deal('truecoloralpha'); % default = 'truecolor' + try + hFills(end).ColorData = uint8([150;150;150;255]); + for idx = 1 : numel(hFills)-1 + hFills(idx).ColorData(4) = 0; % default=255 + end + catch + end + grid on; hold on; f.PaperOrientation='landscape'; f.PaperUnits='centimeters'; papsize=[16 14]; f.PaperSize=papsize; - print(f,sprintf('%sfluid_dens',obj.name),'-dpdf','-fillpage') - savefig(f,sprintf('%sfluid_dens',obj.name)) + %axis equal + obj.savegraph(f,sprintf('%sfluid_dens',obj.name)) end function displayconfiguration(obj,fieldstart,fieldend) %displayconfiguration plot the configuration of the simulation % domain withe boundaries, the magnetic field lines the % electric equipotential lines and the electron density % averaged in time between t2d(fieldstart) and t2d(fieldend) dens=mean(obj.N(:,:,fieldstart:fieldend),3); geomw=obj.geomweight(:,:,1); maxdens=max(dens(:)); geomw(geomw<0)=0; geomw(geomw>0)=maxdens; dens(geomw<=0)=0; geomw(geomw>0)=NaN; f=figure('Name', sprintf('%s fields',obj.name)); ax1=gca; title(sprintf('Configuration')) %dens(dens<=1e13)=NaN; %% electron density h=contourf(ax1,obj.zgrid*1000,obj.rgrid*1000,dens,50,'Displayname','n_e [m^{-3}]', 'linestyle','none'); hold on; colormap(flipud(hot)); %% Magnetic field lines Blines=obj.rAthet; levels=linspace(min(Blines(obj.geomweight(:,:,1)>0)),max(Blines(obj.geomweight(:,:,1)>0)),20); [~,h1]=contour(ax1,obj.zgrid*1000,obj.rgrid*1000,Blines,real(levels),'-.','color','k','linewidth',1.5,'Displayname','Magnetic field lines'); %% Equipotential lines Pot=mean(obj.pot(:,:,fieldstart:fieldend),3); Pot(obj.geomweight(:,:,1)<0)=NaN; %levels=8;%[-3.4 -5 -10 -15 -20 -25];%7; potcolor='b';%[0.3660 0.6740 0.1880]; [c1,h2]=contour(ax1,obj.zgrid*1000,obj.rgrid*1000,Pot,'--','color',potcolor,'ShowText','on','linewidth',1.2,'Displayname','Equipotentials [kV]'); clabel(c1,h2,'Color',potcolor) % Grey outline shows metallic parts [c1,hContour]=contourf(ax1,obj.zgrid*1000,obj.rgrid*1000,geomw, [0 0]); drawnow; % set the axia limits xlim(ax1,[obj.zgrid(1)*1000 obj.zgrid(end)*1000]) if(obj.conformgeom) ylim([ax1 ],[obj.rgrid(1)*1000 obj.rgrid(rgridend)*1000]) else ylim([ax1],[obj.rgrid(1)*1000 obj.rgrid(end)*1000]) end legend([h1,h2],{'Magnetic field lines','Equipotentials [V]'},'location','northeast') xlabel(ax1,'z [mm]') ylabel(ax1,'r [mm]') c = colorbar(ax1); c.Label.String= 'n[m^{-3}]'; view(ax1,2) grid on; hFills=hContour.FacePrims; [hFills.ColorType] = deal('truecoloralpha'); % default = 'truecolor' try hFills(1).ColorData = uint8([150;150;150;255]); for idx = 2 : numel(hFills) hFills(idx).ColorData(4) = 0; % default=255 end catch end [~, name, ~] = fileparts(obj.file); % with this you could show the outline of the maxwellian source % if obj.maxwellsrce.present % rlen=diff(obj.maxwellsrce.rlim); % zlen=diff(obj.maxwellsrce.zlim); % rectangle('Position',[obj.maxwellsrce.zlim(1) obj.maxwellsrce.rlim(1) zlen rlen]*1000,'Edgecolor','g','Linewidth',2,'Linestyle','--') % end % in case of coaxial configuration, extend the display domain % and add grey rectangles to show metallic boundaries if( obj.walltype >=2 && obj.walltype<=4) rectangle('Position',[obj.zgrid(1) obj.r_b obj.zgrid(end)-obj.zgrid(1) 0.001]*1e3,'FaceColor',[150 150 150]/255,'Edgecolor','none') ylimits=ylim; ylim([ylimits(1),ylimits(2)+1]) end if sum(obj.geomweight(:,1,1))==0 rectangle('Position',[obj.zgrid(1) obj.r_a-0.001 obj.zgrid(end)-obj.zgrid(1) 0.001]*1e3,'FaceColor',[150 150 150]/255,'Edgecolor','none') ylimits=ylim; ylim([ylimits(1)-1,ylimits(2)]) end f.PaperUnits='centimeters'; %axis equal papsize=[14 5 ]; obj.savegraph(f,sprintf('%s/%sFields',obj.folder,obj.name),papsize); end function displaymagfield(obj) %displaymagfield display the magnetic field lines and the %amplitude of the magnetic field using a contour % also show the domain boundaries B=obj.B'; f=figure('Name', sprintf('%s B field',obj.name)); B(obj.geomweight(:,:,1)<0)=NaN; ax1=gca; title(sprintf('Configuration')) h=contourf(ax1,obj.zgrid*1000,obj.rgrid*1000,B,linspace(min(B(:)),max(B(:)),50),'Displayname','B [T]', 'linestyle','none'); hold on; %% Magnetic field lines Blines=obj.rAthet; levels=linspace(min(Blines(obj.geomweight(:,:,1)>0)),max(Blines(obj.geomweight(:,:,1)>0)),50); Blines(obj.geomweight(:,:,1)<0)=NaN; [~,h1]=contour(ax1,obj.zgrid*1000,obj.rgrid*1000,Blines,real(levels),'r-.','linewidth',1.5,'Displayname','Magnetic field lines'); colormap(ax1,'parula') % Grey outline geomw=obj.geomweight(:,:,1); geomw(geomw>0)=NaN; geomw(geomw<0)=min(B(:)); [c1,hContour]=contourf(ax1,obj.zgrid*1000,obj.rgrid*1000,geomw, [0 0]); drawnow; xlim(ax1,[obj.zgrid(1)*1000 obj.zgrid(end)*1000]) if(obj.conformgeom) ylim([ax1 ],[obj.rgrid(1)*1000 obj.rgrid(rgridend)*1000]) else ylim([ax1],[obj.rgrid(1)*1000 obj.rgrid(end)*1000]) end legend([h1],{'Magnetic field lines'},'location','northwest') xlabel(ax1,'z [mm]') ylabel(ax1,'r [mm]') %title(ax1,sprintf('Density t=[%1.2g-%1.2g]s n_e=%1.2gm^{-3}',M.t2d(fieldstart),M.t2d(fieldend),double(maxdens))) c = colorbar(ax1); c.Label.String= 'B [T]'; view(ax1,2) %set(h,'edgecolor','none'); grid on; hFills=hContour.FacePrims; [hFills.ColorType] = deal('truecoloralpha'); % default = 'truecolor' %caxis([min(B(:)) max(B(:))]) try hFills(1).ColorData = uint8([150;150;150;255]); for idx = 2 : numel(hFills) hFills(idx).ColorData(4) = 0; % default=255 end catch end [~, name, ~] = fileparts(obj.file); if( obj.walltype >=2 && obj.walltype<=4) rectangle('Position',[obj.zgrid(1) obj.r_b obj.zgrid(end)-obj.zgrid(1) 0.001]*1e3,'FaceColor',[150 150 150]/255,'Edgecolor','none') ylimits=ylim; ylim([ylimits(1),ylimits(2)+1]) end if(isempty(obj.spl_bound)) rectangle('Position',[obj.zgrid(1) obj.r_a-0.001 obj.zgrid(end)-obj.zgrid(1) 0.001]*1e3,'FaceColor',[150 150 150]/255,'Edgecolor','none') ylimits=ylim; ylim([ylimits(1)-1,ylimits(2)]) end f.PaperUnits='centimeters'; %axis equal papsize=[14 5 ]; pos=f.Position; pos(3)=floor(1.3*pos(3)); f.Position=pos; obj.savegraph(f,sprintf('%s/%s_Bfield',obj.folder,obj.name),papsize); end - function displaySurfFluxes(obj,timesteps, ids) - %displaySurfFluxes plot the time evolution of the current - %densities on the domain boundaries for times t2d(timesteps) - %also plot the different boundaries to see which flux belong to - %which boundary - - mflux= obj.Metallicflux(timesteps); - lflux= -squeeze(obj.Axialflux(timesteps,1))'; - rflux= squeeze(obj.Axialflux(timesteps,length(obj.zgrid)))'; - - time=obj.t2d(timesteps); - - if nargin<3 - ids=1:length(mflux); - end - - %% - P=obj.neutcol.neutdens*obj.kb*300/100;% pressure at room temperature in mbar - f=figure('name','fluxevol'); - tiledlayout('flow') - j=1 - for i=1:length(mflux.p) - if(find(i+2==ids)) - ax(j)=nexttile; - j=j+1; - if issorted(mflux.p{i}(1,:),'strictascend') - contourf(mflux.p{i}(1,:)*100,time*1e9,mflux.gamma{i}'*obj.qe/(100^2)/P,'linestyle','none') - xlabel('z [cm]') - else - contourf(linspace(0,1,length(mflux.p{i}(1,:))),time*1e9,mflux.gamma{i}'*obj.qe/(100^2)/P,'linestyle','none') - xlabel('s [-]') - end - title(sprintf('Wall %i',i)) - - c=colorbar; - c.Label.String= 'j\cdotn [A/(cm^2 mbar)]'; - end - end - - if(find(1==ids)) - ax(j+1)=nexttile; - contourf(obj.rgrid*100,time*1e9,lflux*obj.qe/(100^2)/P,'linestyle','none') - title('left') - xlabel('r [cm]') - c=colorbar; - c.Label.String= 'j\cdotn [A/(cm^2 mbar)]'; - end - - if(find(2==ids)) - ax(j+2)=nexttile; - contourf(obj.rgrid*100,time*1e9,rflux*obj.qe/(100^2)/P,'linestyle','none') - title('right') - xlabel('r [cm]') - c=colorbar; - c.Label.String= 'j\cdotn [A/(cm^2 mbar)]'; - end - - - ylabel(ax,'t [ns]') - - nexttile; - for i=1:length(mflux.p) - plot(mflux.p{i}(1,:)*100,mflux.p{i}(2,:)*100,'displayname',sprintf('Wall %i',i),'linewidth',2) - hold on - end - legend('location','eastoutside') - title('Domain') - plot(ones(size(obj.rgrid))*obj.zgrid(1)*100,obj.rgrid*100,'displayname','left','linewidth',2) - plot(ones(size(obj.rgrid))*obj.zgrid(end)*100,obj.rgrid*100,'displayname','right','linewidth',2) - xlabel('z [cm]') - ylabel('r [cm]') - %xlim([obj.zgrid(1) obj.zgrid(end)]*100) - %ylim([obj.rgrid(1) obj.rgrid(end)]*100) - - obj.savegraph(f,sprintf('%s/%s_surfFluxEvol',obj.folder,obj.name),[16 14]); - end - function displaySurfFlux(obj,timestep, subdiv) %displaySurfFlux plot the current densities %on the domain boundaries for time t2d(timestep) %directly on the boundaries themselves %make it easier to see where the currents are collected if nargin<3 subdiv=1; end mflux= obj.Metallicflux(timestep,subdiv); lflux= -squeeze(obj.Axialflux(timestep,1))'; rflux= squeeze(obj.Axialflux(timestep,length(obj.zgrid)))'; time=obj.t2d(timestep); if nargin<3 ids=1:length(mflux); end %% P=obj.neutcol.neutdens*obj.kb*300/100;% pressure at room temperature in mbar f=figure('name','fluxevol'); linew=5; %obj.displaysplbound(gca,1e3); contour(obj.zgrid*1e3,obj.rgrid*1e3,obj.geomweight(:,:,1),[0 0],'b-','linewidth',1.5); hold on for i=1:length(mflux.p) x=mflux.p{i}(1,:)*1000; y=mflux.p{i}(2,:)*1000; y(end)=NaN; c=mflux.gamma{i}'*obj.qe/(100^2)/P; c(c<=0)=NaN; patch(x,y,c,'EdgeColor','interp','LineWidth',linew); hold on end x=obj.zgrid(1)*ones(size(obj.rgrid))*1000; y=obj.rgrid*1000; y(end)=NaN; c=lflux*obj.qe/(100^2)/P; c(c<=0)=NaN; patch(x,y,c,'EdgeColor','interp','LineWidth',linew); x=obj.zgrid(end)*ones(size(obj.rgrid))*1e3; y=obj.rgrid*1000; y(end)=NaN; c=rflux*obj.qe/(100^2)/P; c(c<=0)=NaN; patch(x,y,c,'EdgeColor','interp','LineWidth',linew); title(sprintf('t=%4.2f [ns]',time*1e9)) c=colorbar; c.Label.String= 'j\cdotn [A/(cm^2 mbar)]'; xlabel('z [mm]') ylabel('r [mm]') colormap(jet) set(gca,'colorscale','log') %% Magnetic field lines Blines=obj.rAthet; levels=linspace(min(Blines(obj.geomweight(:,:,1)>0)),max(Blines(obj.geomweight(:,:,1)>0)),20); Blines(obj.geomweight(:,:,1)<0)=NaN; [~,h1]=contour(obj.zgrid*1000,obj.rgrid*1000,Blines,real(levels),'m-.','linewidth',1.5,'Displayname','Magnetic field lines'); %axis equal obj.savegraph(f,sprintf('%s/%s_surfFlux_it2d_%i',obj.folder,obj.name,timestep),[16 14]); end % interactive window to display the terms of the pressure tensor dispespicPressure(obj,logdensity,showgrid,fixed,temperature) % interactive window to display the electron density, magnetic % field lines, electric potential and field at given time steps dispespicFields(obj,logdensity,showgrid,fixed,parper) function displaycollfreq(obj) %displaycollfreq plot the collision frequencies in Hz/mbar for a range of %electron kinetic energies in eV for the different collision %processes considered: ionisation and elastic collisions E=logspace(1,4,1000); v=sqrt(2/obj.msim*obj.weight*E*obj.qe); P=obj.neutcol.neutdens*obj.kb*300/100;% pressure at room temperature in mbar tauio=P./(obj.neutcol.neutdens*obj.sigio(E).*v); tauiom=P./(obj.neutcol.neutdens*obj.sigmio(E).*v); tauelam=P./(obj.neutcol.neutdens*obj.sigmela(E).*v); f=figure('name','t scales coll'); loglog(E,1./tauio,'displayname','ionisation','linewidth',1.5) hold on loglog(E,1./tauiom,'displayname','ionisation momentum','linewidth',1.5) loglog(E,1./tauelam,'displayname','elastic','linewidth',1.5) loglog(E,1./tauio+1./tauiom+1./tauelam,'displayname','total drag','linewidth',1.5) loglog([E(1) E(end)],1./(2*pi/obj.omece)* [1 1],'--','displayname','cyclotronic','linewidth',1.5) xlabel('Electron kinetic energy [eV]') ylabel('\nu [Hz/mbar]') legend('location','southeast') grid on obj.savegraph(f,sprintf('%s/collfreqscales',obj.folder),[14 12]); end function displaycrosssec(obj) %displaycrosssec plot the collision crosssections in m^2 for a range of %electron kinetic energies in eV for the different collision %processes considered: ionisation and elastic collisions E=logspace(1,4,1000); sig_io=obj.sigio(E); sig_iom=obj.sigmio(E); sig_elam=obj.sigmela(E); f=figure('name','t scales coll'); loglog(E,sig_io,'displayname','ionisation','linewidth',1.5) hold on loglog(E,sig_iom,'displayname','ionisation momentum','linewidth',1.5) loglog(E,sig_elam,'displayname','elastic','linewidth',1.5) loglog(E,sig_io+sig_elam+sig_iom,'displayname','total drag','linewidth',1.5) xlabel('Energy [eV]') ylabel('\sigma [m^{2}]') legend('location','southeast') grid on obj.savegraph(f,sprintf('%s/coll_cross_sec_scales',obj.folder),[14 12]); end %------------------------------------------ % Helper functions needed for other functions function [zpos,rpos]=getpos(obj,tstep) % interactive window to return an specific axial and radial % position picked from the cloud density if nargin<2 tstep=length(obj.t2d); end n=obj.N(:,:,tstep); n(obj.geomweight(:,:,1)<0)=NaN; figure contourf(obj.zgrid,obj.rgrid,n); xlabel('z [m]') ylabel('r [m]') [x,y]=ginput(1); zpos=find(x>obj.zgrid,1,'last'); rpos=find(y>obj.rgrid,1,'last'); hold on plot(obj.zgrid(zpos),obj.rgrid(rpos),'rx') fprintf('zpos=%i rpos=%i z=%1.4f r=%1.4f\n',zpos,rpos,obj.zgrid(zpos),obj.rgrid(rpos)) end function changed=ischanged(obj) %ischanged Check if the file has been changed since the initial loading of the file %and if some data must be reloaded try filedata=dir(obj.fullpath); checkedtimestamp=filedata.date; if (max(checkedtimestamp > obj.timestamp) ) changed=true; return end changed=false; return catch changed=true; return end end function dispV(obj,V,Vend,label,t, dist, vd) %dispV generic functio to plot the velocity distribution and %comapare two timesteps V and Vend at time t(1) and t(2) if nargin<6 dist='gaussian'; end if nargin<7 vd=0; end vmean=mean(V(~isnan(V))); vtherm=std(V(~isnan(V)),1); vmeanend=mean(Vend(~isnan(Vend))); vthermend=std(Vend(~isnan(Vend)),1); if(length(V)>1) [Counts,edges]=histcounts(V,'binmethod','scott'); binwidth=mean(diff(edges)); plot([edges(1) 0.5*(edges(2:end)+edges(1:end-1)) edges(end)],[0 Counts 0],'DisplayName',sprintf("t=%2.3d [ns]",obj.tpart(t(1))*1e9)); hold on end hold on [Counts,edges]=histcounts(Vend,'binmethod','scott'); plot([edges(1) 0.5*(edges(2:end)+edges(1:end-1)) edges(end)],[0 Counts 0],'DisplayName',sprintf("t=%2.3d [ns]",obj.tpart(t(2))*1e9)); if strcmp(dist,'maxwell') vfit=linspace(0,edges(end),300); a=vmeanend/sqrt(2); dist=sqrt(2/pi)*vfit.^2.*exp(-((vfit).^2-vd^2)/2/a^2)/a^3; dist=dist/max(dist); plot(vfit,max(Counts)*dist,'displayname',sprintf('Maxw mu=%2.2g sigma=%2.2g',vmeanend,vthermend)) elseif strcmp(dist,'gaussian') vfit=linspace(edges(1),edges(end),300); dist=exp(-(vfit-vmeanend).^2/2/vthermend^2); plot(vfit,max(Counts)*dist,'displayname',sprintf('gauss mu=%2.2g sigma=%2.2g',vmeanend,vthermend)) end ylabel('counts') xlabel(label) grid on legend('location','southoutside','orientation','vertical') end function cross_sec=fit_cross_sec(obj,energy,crosssec_table) %Interpolate the cross-section at the given energy using the %crosssec_table and an exponential fitting cross_sec=0; if (energy<=0 || isnan(energy) || isinf(energy)) return end id=find(energy>crosssec_table(:,1),1,'last'); if(isempty(id)) id=1; end id=min(size(crosssec_table,1)-1,id); id=max(1,id); cross_sec=crosssec_table(id,2)*(energy/crosssec_table(id,1))^crosssec_table(id,3); end function fighandle=savegraph(obj, fighandle, name, papsize) %% Saves the given figure as a pdf a .fig and an eps using export_fig fighandle.PaperUnits='centimeters'; if (nargin < 4) papsize=[14 16]; end + set(fighandle, 'Color', 'w'); fighandle.PaperSize=papsize; + export_fig(fighandle,name,'-png','-r300') print(fighandle,name,'-dpdf','-fillpage') - savefig(fighandle,name) set(fighandle, 'Color', 'w'); - export_fig(fighandle,name,'-eps') + export_fig(fighandle,name,'-eps','-painters') + end function sig=dsigmaio(obj,Ekin, Ebar, Ei, E0, chi, gamma) % calculates the integrand used for the ionisation collision % cross section for momentum exchange for the incoming electron % it is only used by obj.sigmiopre gamma=reshape(gamma,1,[],1); chi=reshape(chi,1,1,[]); siggamma=sin(gamma).*(E0^2+8*(1-chi)*(Ekin-Ei)*E0)./(E0+4*(1-chi)*(Ekin-Ei)-4*(1-chi)*(Ekin-Ei).*cos(gamma)).^2/2; sigchi=(Ekin-Ei)./(Ebar*atan((Ekin-Ei)/(2*Ebar)).*(1+(chi*(Ekin-Ei)/Ebar).^2)); dp=1- trapz(gamma,sqrt((1-chi).*(1-Ei/Ekin)).*cos(gamma).*siggamma,2);%- trapz(gamma,sqrt((1-chi).*(1-Ei/Ekin)).*cos(gamma).*siggamma,2); sig=sigchi.*dp; end function sigm=sigmiopre(obj,E, init) % returns the precalculated values used for the interpolation % of the ionisation collision cross-section for momentum % exchange for the incoming electron if nargin <3 init=false; end if(~init &&( ~obj.neutcol.present || isempty(obj.neutcol.io_cross_sec))) sigm=zeros(size(E)); return end Ebar=obj.neutcol.scatter_fac; Ei=obj.neutcol.Eion; E0=obj.neutcol.E0; nE=numel(E); nchi=300; ngamma=300; gamma=linspace(0,pi,ngamma); chi=linspace(0,0.5,nchi); %sigm2=zeros(nE,nchi); sigm=zeros(size(E)); for i=1:nE if(E(i)>=Ei) sigm2=zeros(nchi,1); for j=1:nchi %sigm2(j)=trapz(alpha,trapz(gamma,obj.dsigmaio(E(i),Ebar,Ei,E0,chi(j),alpha,gamma),2),1); sigm2(j)=obj.dsigmaio(E(i),Ebar,Ei,E0,chi(j),gamma); end sigm(i)=trapz(chi,sigm2)*obj.sigio(E(i),init); %sigm(i)=trapz(chi,trapz(alpha,trapz(gamma,dsigmaio(obj,E(i),Ebar,Ei,E0,chi,alpha,gamma),2),1),3)*obj.sigio(E(i),init); end end end end end diff --git a/matlab/@espic2dhdf5/potentialwellmodel.m b/matlab/@espic2dhdf5/potentialwellmodel.m new file mode 100644 index 0000000..a8c30b6 --- /dev/null +++ b/matlab/@espic2dhdf5/potentialwellmodel.m @@ -0,0 +1,101 @@ +function model=potentialwellmodel(obj,timestep,calcfull) +% Computes the potential well at the given timestep and return the model to be able to +% interpolate either using grid coordinates or magnetic field line coordinates +% the potential well is calculated along each magnetic field +% line by taking the difference between a local potential well maximum +% and the maximum local minimum along the line on +% each side of the maximum + +% model.z and model.r are the axial and radial positions where +% the potential depth has been calculated and is used with a +% scatteredinterpolant to calculate the well depth at the +% desired position +% model.pot is the potential well depth + +% model.rathet is the magnetic field vector value at the +% corresponding position multiplied by the radial position +if iscell(timestep) + timestep=cell2mat(timestep); +end +% Defines if only the well region is kept or if the hills are also kept +if nargin<3 + calcfull=false; +end +% if one of the timesteps is 0 we take the external potential +id=find(timestep==0); +if(~isempty(id)) + timestep(id)=[]; +end +Phi=-obj.pot(:,:,timestep); +if(~isempty(id)) + phiext=-obj.potxt(:,:,1); + if isempty(obj.potxt) + phiext=-obj.pot(:,:,1); + end + Phi=cat(3,Phi(:,:,1:id-1),phiext,Phi(:,:,id:end)); +end + +% We get the magnetic field lines rA_theta values +%lvls=sort(unique([obj.rAthet(:,1)',obj.rAthet(:,end)', obj.rAthet(1,:),obj.rAthet(end,:)])); +Blines=obj.rAthet; +lvls=linspace(min(Blines(obj.geomweight(:,:,1)>0)),max(Blines(obj.geomweight(:,:,1)>0)),200); +Blines(obj.geomweight(:,:,1)<0)=NaN; +lvls(isnan(lvls))=[]; + +% We obtain the magnetic field lines coordinates for each +% level in r and z +contpoints=contourc(obj.zgrid,obj.rgrid,Blines,lvls(1:end)); +[x,y,zcont]=C2xyz(contpoints); + +% memory allocation for spped + +potfinal=zeros(numel(cell2mat(x)),length(timestep)); +Pot=cell(1,size(x,2)-1); +rathet=cell(1,size(x,2)-1); +[z,r]=ndgrid(obj.zgrid,obj.rgrid); + +% for each timestep we calculate the well +for i=1:length(timestep)+~isempty(id) + locPhi=Phi(:,:,i); + % We delete points outside of the domain + locPhi(obj.geomweight(:,:,1)<0)=0; + + + locPhi=griddedInterpolant(z,r,locPhi','makima'); + % For each field line we remove the lowest maximum + for j=1:size(x,2) + %for i=1:size(pot,1) + xloc=x{j}; + yloc=y{j}; + + rathet{j}=zcont(j)*ones(1,length(xloc)); + + if(length(xloc)>=3) + + Pot{j}=locPhi(xloc,yloc); + locpot=Pot{j}; + %locpot=locpot-min(locpot); + % along the given field line j we calculate the + % minimum on the left and right side of the + % position k and calculate the local well depth + for k=2:length(locpot)-1 + left=max(locpot(1:k-1)); + right=max(locpot(k+1:end)); + Pot{j}(k)=locpot(k)-min(left,right); + end + Pot{j}(1)=0; + Pot{j}(end)=0; + else + Pot{j}=zeros(size(xloc)); + end + end + potfinal(:,i)=cell2mat(Pot); +end +if ~calcfull + potfinal(potfinal>0)=NaN; +end +model.z=cell2mat(x); +model.r=cell2mat(y); +model.pot=-potfinal; +model.rathet=cell2mat(rathet); +end \ No newline at end of file diff --git a/matlab/C2xyz_v2/C2xyz.m b/matlab/C2xyz_v2/C2xyz.m new file mode 100644 index 0000000..4ad99ee --- /dev/null +++ b/matlab/C2xyz_v2/C2xyz.m @@ -0,0 +1,66 @@ +function [x,y,z] = C2xyz(C) +% C2XYZ returns the x and y coordinates of contours in a contour +% matrix and their corresponding z values. C is the contour matrix given by +% the contour function. +% +% +%% Syntax +% +% [x,y] = C2xyz(C) +% [x,y,z] = C2xyz(C) +% +%% Description +% +% [x,y] = C2xyz(C) returns x and y coordinates of contours in a contour +% matrix C +% +% [x,y,z] = C2xyz(C) also returns corresponding z values. +% +% +%% Example +% Given a contour plot, you want to know the (x,y) coordinates of the contours, +% as well as the z value corresponding to each contour line. +% +% C = contour(peaks); +% [x,y,z] = C2xyz(C); +% +% This returns 1 x numberOfContourLines cells of x values and y values, and +% their corresponding z values are given in a 1 x numberOfContourLines +% array. If you'd like to plot a heavy black line along all of the z=0 +% contours and a dotted red line along the z = -2 contours, try this: +% +% hold on; % Allows plotting atop the preexisting peaks plot. +% for n = find(z==0); % only loop through the z = 0 values. +% plot(x{n},y{n},'k','linewidth',2) +% end +% +% for n = find(z==-2) % now loop through the z = -2 values. +% plot(x{n},y{n},'r:','linewidth',2) +% end +% +% * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +% Created by Chad Greene, August 2013. +% +% * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +% See also contour, contourf, clabel, contour3, and C2xy. + + +m(1)=1; +n=1; +try + while n + diff --git a/matlab/C2xyz_v2/export_fig/ImageSelection.class b/matlab/C2xyz_v2/export_fig/ImageSelection.class new file mode 100644 index 0000000..cfac41d Binary files /dev/null and b/matlab/C2xyz_v2/export_fig/ImageSelection.class differ diff --git a/matlab/C2xyz_v2/export_fig/ImageSelection.java b/matlab/C2xyz_v2/export_fig/ImageSelection.java new file mode 100644 index 0000000..7ec32fd --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/ImageSelection.java @@ -0,0 +1,38 @@ +/* + * Based on code snippet from + * http://java.sun.com/developer/technicalArticles/releases/data/ + * + * Copyright © 2008, 2010 Oracle and/or its affiliates. All rights reserved. Use is subject to license terms. + */ + +import java.awt.image.BufferedImage; +import java.awt.datatransfer.*; + +public class ImageSelection implements Transferable { + + private static final DataFlavor flavors[] = + {DataFlavor.imageFlavor}; + + private BufferedImage image; + + public ImageSelection(BufferedImage image) { + this.image = image; + } + + // Transferable + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { + if (flavor.equals(flavors[0]) == false) { + throw new UnsupportedFlavorException(flavor); + } + return image; + } + + public DataFlavor[] getTransferDataFlavors() { + return flavors; + } + + public boolean isDataFlavorSupported(DataFlavor + flavor) { + return flavor.equals(flavors[0]); + } +} \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/LICENSE b/matlab/C2xyz_v2/export_fig/LICENSE new file mode 100644 index 0000000..1a05830 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014, Oliver J. Woodford, Yair M. Altman +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/matlab/C2xyz_v2/export_fig/README.md b/matlab/C2xyz_v2/export_fig/README.md new file mode 100644 index 0000000..c54307c --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/README.md @@ -0,0 +1,272 @@ +export_fig +========== + +A toolbox for exporting figures from MATLAB to standard image and document formats nicely. + +### Overview +Exporting a figure from MATLAB the way you want it (hopefully the way it looks on screen), can be a real headache for the unitiated, thanks to all the settings that are required, and also due to some eccentricities (a.k.a. features and bugs) of functions such as `print`. The first goal of export_fig is to make transferring a plot from screen to document, just the way you expect (again, assuming that's as it appears on screen), a doddle. + +The second goal is to make the output media suitable for publication, allowing you to publish your results in the full glory that you originally intended. This includes embedding fonts, setting image compression levels (including lossless), anti-aliasing, cropping, setting the colourspace, alpha-blending and getting the right resolution. + +Perhaps the best way to demonstrate what export_fig can do is with some examples. + +*Note: `export_fig` currently supports only figures created with the `figure` function, or GUIDE. Figures created using `uifigure` or AppDesigner are only partially supported. See issues [#287](https://github.com/altmany/export_fig/issues/287), [#261](https://github.com/altmany/export_fig/issues/261) for details.* + +### Examples +**Visual accuracy** - MATLAB's exporting functions, namely `saveas` and `print`, change many visual properties of a figure, such as size, axes limits and ticks, and background colour, in unexpected and unintended ways. Export_fig aims to faithfully reproduce the figure as it appears on screen. For example: +```Matlab +plot(cos(linspace(0, 7, 1000))); +set(gcf, 'Position', [100 100 150 150]); +saveas(gcf, 'test.png'); +export_fig test2.png +``` +generates the following: + +| Figure: | test.png: | test2.png: | +|:-------:|:---------:|:----------:| +|![](https://farm6.staticflickr.com/5616/15589249291_16e485c29a_o_d.png)|![](https://farm4.staticflickr.com/3944/15406302850_4d2e1c7afa_o_d.png)|![](https://farm6.staticflickr.com/5607/15568225476_8ce9bd5f6b_o_d.png)| + +Note that the size and background colour of test2.png (the output of export_fig) are the same as those of the on screen figure, in contrast to test.png. Of course, if you want the figure background to be white (or any other colour) in the exported file then you can set this prior to exporting using: +```Matlab +set(gcf, 'Color', 'w'); +``` + +Notice also that export_fig crops and anti-aliases (smooths, for bitmaps only) the output by default. However, these options can be disabled; see the Tips section below for details. + +**Resolution** - by default, export_fig exports bitmaps at screen resolution. However, you may wish to save them at a different resolution. You can do this using either of two options: `-m`, where is a positive real number, magnifies the figure by the factor for export, e.g. `-m2` produces an image double the size (in pixels) of the on screen figure; `-r`, again where is a positive real number, specifies the output bitmap to have pixels per inch, the dimensions of the figure (in inches) being those of the on screen figure. For example, using: +```Matlab +export_fig test.png -m2.5 +``` +on the figure from the example above generates: + +![](https://farm4.staticflickr.com/3937/15591910915_dc7040c477_o_d.png) + +Sometimes you might have a figure with an image in. For example: +```Matlab +imshow(imread('cameraman.tif')) +hold on +plot(0:255, sin(linspace(0, 10, 256))*127+128); +set(gcf, 'Position', [100 100 150 150]); +``` +generates this figure: + +![](https://farm4.staticflickr.com/3942/15589249581_ff87a56a3f_o_d.png) + +Here the image is displayed in the figure at resolution lower than its native resolution. However, you might want to export the figure at a resolution such that the image is output at its native (i.e. original) size (in pixels). Ordinarily this would require some non-trivial computation to work out what that resolution should be, but export_fig has an option to do this for you. Using: +```Matlab +export_fig test.png -native +``` +produces: + +![](https://farm6.staticflickr.com/5604/15589249591_da2b2652e4_o_d.png) + +with the image being the size (in pixels) of the original image. Note that if you want an image to be a particular size, in pixels, in the output (other than its original size) then you can resize it to this size and use the `-native` option to achieve this. + +All resolution options (`-m`, `-q` and `-native`) correctly set the resolution information in PNG and TIFF files, as if the image were the dimensions of the on screen figure. + +**Shrinking dots & dashes** - when exporting figures with dashed or dotted lines using either the ZBuffer or OpenGL (default for bitmaps) renderers, the dots and dashes can appear much shorter, even non-existent, in the output file, especially if the lines are thick and/or the resolution is high. For example: +```Matlab +plot(sin(linspace(0, 10, 1000)), 'b:', 'LineWidth', 4); +hold on +plot(cos(linspace(0, 7, 1000)), 'r--', 'LineWidth', 3); +grid on +export_fig test.png +``` +generates: + +![](https://farm4.staticflickr.com/3956/15592747732_f943d4aa0a_o_d.png) + +This problem can be overcome by using the painters renderer. For example: +```Matlab +export_fig test.png -painters +``` +used on the same figure generates: + +![](https://farm4.staticflickr.com/3945/14971168504_77692f11f5_o_d.png) + +Note that not only are the plot lines correct, but the grid lines are too. + +**Transparency** - sometimes you might want a figure and axes' backgrounds to be transparent, so that you can see through them to a document (for example a presentation slide, with coloured or textured background) that the exported figure is placed in. To achieve this, first (optionally) set the axes' colour to 'none' prior to exporting, using: +```Matlab +set(gca, 'Color', 'none'); % Sets axes background +``` + +then use export_fig's `-transparent` option when exporting: +```Matlab +export_fig test.png -transparent +``` + +This will make the background transparent in PDF, EPS and PNG outputs. You can additionally save fully alpha-blended semi-transparent patch objects to the PNG format. For example: + +```Matlab +logo; +alpha(0.5); +``` + +generates a figure like this: + +![](https://farm4.staticflickr.com/3933/15405290339_b08de33528_o_d.png) + +If you then export this to PNG using the `-transparent` option you can then put the resulting image into, for example, a presentation slide with fancy, textured background, like so: + +![](https://farm6.staticflickr.com/5599/15406302920_59beaefff1_o_d.png) + +and the image blends seamlessly with the background. + +**Image quality** - when publishing images of your results, you want them to look as good as possible. By default, when outputting to lossy file formats (PDF, EPS and JPEG), export_fig uses a high quality setting, i.e. low compression, for images, so little information is lost. This is in contrast to MATLAB's print and saveas functions, whose default quality settings are poor. For example: +```Matlab +A = im2double(imread('peppers.png')); +B = randn(ceil(size(A, 1)/6), ceil(size(A, 2)/6), 3) * 0.1; +B = cat(3, kron(B(:,:,1), ones(6)), kron(B(:,:,2), ones(6)), kron(B(:,:,3), ones(6))); +B = A + B(1:size(A, 1),1:size(A, 2),:); +imshow(B); +print -dpdf test.pdf +``` +generates a PDF file, a sub-window of which looks (when zoomed in) like this: + +![](https://farm6.staticflickr.com/5613/15405290309_881b2774d6_o_d.png) + +while the command + +```Matlab +export_fig test.pdf +``` +on the same figure produces this: + +![](https://farm4.staticflickr.com/3947/14971168174_687473133f_o_d.png) + +While much better, the image still contains some compression artifacts (see the low level noise around the edge of the pepper). You may prefer to export with no artifacts at all, i.e. lossless compression. Alternatively, you might need a smaller file, and be willing to accept more compression. Either way, export_fig has an option that can suit your needs: `-q`, where is a number from 0-100, will set the level of lossy image compression (again in PDF, EPS and JPEG outputs only; other formats are lossless), from high compression (0) to low compression/high quality (100). If you want lossless compression in any of those formats then specify a greater than 100. For example: +```Matlab +export_fig test.pdf -q101 +``` +again on the same figure, produces this: + +![](https://farm6.staticflickr.com/5608/15405803908_934512c1fe_o_d.png) + +Notice that all the noise has gone. + +### Tips +**Anti-aliasing** - the anti-aliasing which export_fig applies to bitmap outputs by default makes the images look nice, but it can also blur images and increase exporting time and memory requirements, so you might not always want it. You can set the level of anti-aliasing by using the `-a` option, where is 1 (no anti-aliasing), 2, 3 (default) or 4 (maximum anti-aliasing). + +**Cropping** - by default, export_fig crops its output to minimize the amount of empty space around the figure. If you'd prefer the figure to be uncropped, and instead have the same appearance (in terms of border width) as the on screen figure, then use the `-nocrop` option. + +**Colourspace** - by default, export_fig generates files in the RGB [colourspace](https://en.wikipedia.org/wiki/Color_space). However, you can also export in greyscale or the CMYK colourspace, using the `-grey` (or `-gray`) and `-cmyk` options respectively. The CMYK option is useful for publishers who require documents in this colourspace, but the option is only supported for PDF, EPS and TIFF files. + +**Specifying a target directory** - you can get export_fig to save output files to any directory (for which you have write permission), simply by specifying the full or relative path in the filename. For example: +```Matlab +export_fig ../subdir/fig.png; +export_fig('C:/Users/Me/Documents/figures/myfig', '-pdf', '-png'); +``` + +**Variable file names** - often you might want to save a series of figures in a for loop, each with a different name. For this you can use the functional form of input arguments, i.e. `export_fig(arg1, arg2)`, and construct the filename string in a variable. Here's an example of this: +```Matlab +for a = 1:5 + plot(rand(5, 2)); + export_fig(sprintf('plot%d.png', a)); +end +``` +When using the functional form like this, be sure to put string variables in quotes: +```Matlab +export_fig(sprintf('plot%d', a), '-a1', '-pdf', '-png'); +``` + +**Specifying the figure/axes** - if you have multiple figures open you can specify which figure to export using its handle: +```Matlab +export_fig(figure_handle, filename); +``` +Equally, if your figure contains several subplots then you can export just one of them by giving export_fig the handle to the relevant axes: +```Matlab +export_fig(axes_handle, filename); +``` + +**Multiple formats** - save time by exporting to multiple formats simultaneously. E.g.: +```Matlab +export_fig filename -pdf -eps -png -jpg -tiff +``` + +**Other file formats** - if you'd like to save your figure to a bitmap format that is not supported by export_fig, e.g. animated GIF, PPM file or a frame in a movie, then you can use export_fig to output the image, and optionally an alpha-matte, to the workspace. E.g.: +```Matlab +frame = export_fig; +``` +or +```Matlab +[frame, alpha] = export_fig; +``` +These variables can then be saved to other image formats using other functions, such as imwrite. + +**Appending to a file** - you can use the `-append` option to append the figure to the end of an image/document, if it already exists. This is supported for PDF and TIFF files only. Note that if you wish to append a lot of figures consecutively to a PDF, it can be more efficient to save all the figures to PDF separately then append them all in one go at the end (e.g. using [append_pdfs](http://www.mathworks.com/matlabcentral/fileexchange/31215-appendpdfs)). + +**Output to clipboard** - you can use the `-clipboard` option to copy the specified figure or axes to the system clipboard, for easy paste into other documents (e.g., Word or PowerPoint). Note that the image is copied in bitmap (not vector) format. + +**Font size** - if you want to place an exported figure in a document with the font a particular size then you need to set the font to that size in the figure, and not resize the output of export_fig in the document. To avoid resizing, simply make sure that the on screen figure is the size you want the output to be in the document before exporting. + +**Renderers** - MATLAB has three renderers for displaying and exporting figures: painters, OpenGL and ZBuffer. The different renderers have different [features](http://www.mathworks.com/access/helpdesk/help/techdoc/creating_plots/f3-84337.html#f3-102410), so if you aren't happy with the result from one renderer try another. By default, vector formats (i.e. PDF and EPS outputs) use the painters renderer, while other formats use the OpenGL renderer. Non-default renderers can be selected by using one of these three export_fig input options: `-painters`, `-opengl`, `-zbuffer`: +```Matlab +export_fig test.png -painters +``` + +**Artifacts** - sometimes the output that you get from export_fig is not what you expected. If an output file contains artifacts that aren't in the on screen figure then make sure that the renderer used for rendering the figure on screen is the same as that used for exporting. To set the renderer used to display the figure, use: +```Matlab +set(figure_handle, 'Renderer', 'opengl'); +``` +After matching the two renderers, if the artifact appears in the on screen figure then you'll need to fix that before exporting. Alternatively you can try changing the renderer used by export_fig. Finally check that it isn't one of the known issues mentioned in the section below. + +**Smoothed/interpolated images in output PDF** - if you produce a PDF using export_fig and images in the PDF look overly smoothed or interpolated, this is because the software you are using to view the PDF is smoothing or interpolating the image data. The image is not smoothed in the PDF file itself. If the software has an option to disable this feature, you should select it. Alternatively, use another PDF viewer that doesn't exhibit this problem. + +**Locating Ghostscript/pdftops** - You may find a dialogue box appears when using export_fig, asking you to locate either [Ghostscript](http://www.ghostscript.com) or [pdftops (part of the Xpdf package)](http://www.xpdfreader.com). These are separate applications which export_fig requires to perform certain functions. If such a dialogue appears it is because export_fig can't find the application automatically. This is because you either haven't installed it, or it isn't in the normal place. Make sure you install the applications correctly first. They can be downloaded from the following places: + 1. Ghostscript: [www.ghostscript.com](http://www.ghostscript.com) + 2. pdftops (install the Xpdf package): [www.xpdfreader.com](http://www.xpdfreader.com) + +If you choose to install them in a non-default location then point export_fig +to this location using the dialogue box. + +**Undefined function errors** - If you download and run export_fig and get an error similar to this: +``` +??? Undefined function or method 'print2array' for input arguments of type 'double'. +``` +then you are missing one or more of the files that come in the export_fig package. Make sure that you click the "Get from GitHub" button at the top-right of the download [page](http://www.mathworks.co.uk/matlabcentral/fileexchange/23629-exportfig), then extract all the files in the zip file to the same directory. You should then have all the necessary files. + +### Known issues +There are lots of problems with MATLAB's exporting functions, especially `print`. Export_fig is simply a glorified wrapper for MATLAB's `print` function, and doesn't solve all of its bugs (yet?). Some of the problems I know about are: + +**Fonts** - when using the painters renderer, MATLAB can only export a small number of fonts, details of which can be found [here](http://www.mathworks.com/help/releases/R2014a/matlab/creating_plots/choosing-a-printer-driver.html#f3-96545). Export_fig attempts to correct font names in the resulting EPS file (up to a maximum of 11 different fonts in one figure), but this is not always guaranteed to work. In particular, the text positions will be affected. It also does not work for text blocks where the 'Interpreter' property is set to 'latex'. + +Also, when using the painters renderer, ghostscript will sometimes throw an error such as `Error: /undefined in /findfont`. This suggests that ghostscript could not find a definition file for one of your fonts. One possible fix for this is to make sure the file `EXPORT_FIG_PATH/.ignore/gs_font_path.txt` exists and contains a list of paths to the folder(s) containing the necessary font definitions (make sure that they are TrueType definitions!), separated by a semicolon. + +**RGB color data not yet supported in Painter's mode** - you will see this as a warning if you try to export a figure which contains patch objects whose face or vertex colors are specified as an RGB colour, rather than an index into the colormap, using the painters renderer (the default renderer for vector output). This problem can arise if you use `pcolor`, for example. This is a problem with MATLAB's painters renderer, which also affects `print`; there is currently no fix available in export_fig (other than to export to bitmap). The suggested workaround is to avoid colouring patches using RGB. First, try to use colours in the figure's colourmap (instructions [here](http://www.mathworks.co.uk/support/solutions/en/data/1-6OTPQE/)) - change the colourmap, if necessary. If you are using `pcolor`, try using [uimagesc](http://www.mathworks.com/matlabcentral/fileexchange/11368) (on the file exchange) instead. + +**Dashed contour lines appear solid** - when using the painters renderer, MATLAB cannot generate dashed lines using the `contour` function (either on screen or in exported PDF and EPS files). Details can be found [here](http://www.mathworks.com/support/solutions/en/data/1-14PPHB/?solution=1-14PPHB). + +**Text size** - when using the OpenGL or ZBuffer renderers, large text can be resized relative to the figure when exporting at non-screen-resolution (including using anti-alising at screen resolution). This is a feature of MATLAB's `print `function. In this case, try using the `-painters` option. + +**Lighting and transparency** - when using the painters renderer, transparency and lighting effects are not supported. Sorry, but this is an inherent feature of MATLAB's painters renderer. To find out more about the capabilities of each rendering method, see [here](http://www.mathworks.com/access/helpdesk/help/techdoc/creating_plots/f3-84337.html#f3-102410). You can still export transparent objects to vector format (SVG) using the excellent [plot2svg](http://www.mathworks.com/matlabcentral/fileexchange/7401) package, then convert this to PDF, for example using [Inkscape](http://inkscape.org/). However, it can't handle lighting. + +**Lines in patch objects** - when exporting patch objects to PDF using the painters renderer (default), sometimes the output can appear to have lines across the middle of rectangular patches; these lines are the colour of the background, as if there is a crack in the patch, allowing you to see through. This appears to be due to bugs in MATLAB's internal vector rendering code. These lines can often be removed from the PDF using software such as [InkScape](https://inkscape.org). Sometimes disabling anti-aliasing in the PDF-reader software can get rid of the lines ([discussion](https://github.com/altmany/export_fig/issues/44)). + +**Out of memory** - if you run into memory issues when using export_fig, some ways to get round this are: + 1. Reduce the level of anti-aliasing. + 2. Reduce the size of the figure. + 3. Reduce the export resolution (dpi). + 4. Change the renderer to painters or ZBuffer. + +**Errors** - the other common type of errors people get with export_fig are OpenGL errors. This isn't a fault of export_fig, but either a bug in MATLAB's `print`, or your graphics driver getting itself into a state. Always make sure your graphics driver is up-to-date. If it still doesn't work, try using the ZBuffer renderer. + +### Raising issues +If you think you have found a genuine error or issue with export_fig **that is not listed above**, first ensure that the figure looks correct on screen when rendered using the renderer that export_fig is set to use (e.g. if exporting to PDF or EPS, does the figure look correct on screen using the painters renderer, or if exporting to bitmap, does the figure look correct on screen using the OpenGL renderer?). If it looks wrong then the problem is there, and I cannot help (other than to suggest you try exporting using a different renderer). + +Secondly, if exporting to bitmap, do try all the renderers (i.e. try the options `-opengl`, `-zbuffer` and `-painters` separately), to see if one of them does produce an acceptable output, and if so, use that. + +If this still does not help, then ensure that you are using the latest version of export_fig, which is available [here](https://github.com/altmany/export_fig/archive/master.zip). + +If the figure looks correct on screen, but an error exists in the exported output (which cannot be solved using a different renderer) then please feel free to raise an [issue](https://github.com/altmany/export_fig/issues). Please be sure to include the .fig file, the export_fig command you use, the output you get, and a description of what you expected. I can't promise anything, but if it's easy to fix I may indeed do it. Often I will find that the error is due to a bug in MATLAB's `print` function, in which case I will suggest you submit it as a bug to TheMathWorks, and inform me of any fix they suggest. Also, if there's a feature you'd like that isn't supported please tell me what it is and I'll consider implementing it. + +### And finally... + +![](https://farm4.staticflickr.com/3956/15591911455_b9008bd77e_o_d.jpg) + +If you've ever wondered what's going on in the logo on the export_fig download page (reproduced here), then this explanantion is for you. The logo is designed to demonstrate as many of export_fig's features as possible: + +Given a figure containing a translucent mesh (top right), export_fig can export to pdf (bottom centre), which allows the figure to be zoomed-in without losing quality (because it's a vector graphic), but isn't able to reproduce the translucency. Also, depending on the PDF viewer program, small gaps appear between the patches, which are seen here as thin white lines. + +By contrast, when exporting to png (top left), translucency is preserved (see how the graphic below shows through), and the figure is anti-aliased. However, zooming-in does not reveal more detail since png is a bitmap format. Also, lines appear less sharp than in the pdf output. + diff --git a/matlab/C2xyz_v2/export_fig/append_pdfs.m b/matlab/C2xyz_v2/export_fig/append_pdfs.m new file mode 100644 index 0000000..d8bd376 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/append_pdfs.m @@ -0,0 +1,151 @@ +function append_pdfs(varargin) +%APPEND_PDFS Appends/concatenates multiple PDF files +% +% Example: +% append_pdfs(outputFilename, inputFilename1, inputFilename2, ...) +% append_pdfs(outputFilename, inputFilenames_list{:}) +% append_pdfs(outputFilename, inputFilenames_cell_or_string_array) +% append_pdfs output.pdf input1.pdf input2.pdf +% +% This function appends multiple PDF files to an existing PDF file, or +% concatenates them into a PDF file if the output file doesn't yet exist. +% +% This function requires that you have ghostscript installed on your +% system. Ghostscript can be downloaded from: http://www.ghostscript.com +% +% IN: +% output - string of output file name (including the extension, .pdf). +% If it exists it is appended to; if not, it is created. +% input1 - string of an input file name (including the extension, .pdf). +% All input files are appended in order. +% input_list - cell array list of input file name strings. All input +% files are appended in order. + +% Copyright: Oliver Woodford, 2011-2014, Yair Altman 2015- + +%{ +% Thanks to Reinhard Knoll for pointing out that appending multiple pdfs in +% one go is much faster than appending them one at a time. + +% Thanks to Michael Teo for reporting the issue of a too long command line. +% Issue resolved on 5/5/2011, by passing gs a command file. + +% Thanks to Martin Wittmann for pointing out quality issue when appending bitmaps +% Issue resolved (to best of my ability) 1/6/2011, using the prepress setting + +% 26/02/15: If temp dir is not writable, use the output folder for temp +% files when appending (Javier Paredes); sanity check of inputs +% 24/01/18: Fixed error in case of existing output file (append mode) +% 24/01/18: Fixed issue #213: non-ASCII characters in folder names on Windows +% 06/12/18: Avoid an "invalid escape-char" warning upon error +% 22/03/20: Alert if ghostscript.m is not found on Matlab path +% 29/03/20: Accept a cell-array of input files (issue #299); accept both "strings", 'chars' +%} + + if nargin < 2, return; end % sanity check + + % Convert strings => chars; strtrim extra spaces + varargin = cellfun(@str2char,varargin,'un',false); + + % Convert cell array into individual strings (issue #299) + if nargin==2 && iscell(varargin{2}) + varargin = {varargin{1} varargin{2}{:}}; %#ok + end + + % Ensure that ghostscript() exists on the Matlab path + if ~exist('ghostscript','file') + error('export_fig:append_pdfs:ghostscript', 'The ghostscript.m function is required by append_pdf.m. Install the complete export_fig package from https://www.mathworks.com/matlabcentral/fileexchange/23629-export_fig or https://github.com/altmany/export_fig') + end + + % Are we appending or creating a new file + append = exist(varargin{1}, 'file') == 2; + output = [tempname '.pdf']; + try + % Ensure that the temp dir is writable (Javier Paredes 26/2/15) + fid = fopen(output,'w'); + fwrite(fid,1); + fclose(fid); + delete(output); + isTempDirOk = true; + catch + % Temp dir is not writable, so use the output folder + [dummy,fname,fext] = fileparts(output); %#ok + fpath = fileparts(varargin{1}); + output = fullfile(fpath,[fname fext]); + isTempDirOk = false; + end + if ~append + output = varargin{1}; + varargin = varargin(2:end); + end + + % Create the command file + if isTempDirOk + cmdfile = [tempname '.txt']; + else + cmdfile = fullfile(fpath,[fname '.txt']); + end + prepareCmdFile(cmdfile, output, varargin{:}); + + % Call ghostscript + [status, errMsg] = ghostscript(['@"' cmdfile '"']); + + % Check for ghostscript execution errors + if status && ~isempty(strfind(errMsg,'undefinedfile')) && ispc %#ok + % Fix issue #213: non-ASCII characters in folder names on Windows + for fileIdx = 2 : numel(varargin) + [fpath,fname,fext] = fileparts(varargin{fileIdx}); + varargin{fileIdx} = fullfile(normalizePath(fpath),[fname fext]); + end + % Rerun ghostscript with the normalized folder names + prepareCmdFile(cmdfile, output, varargin{:}); + [status, errMsg] = ghostscript(['@"' cmdfile '"']); + end + + % Delete the command file + delete(cmdfile); + + % Check for ghostscript execution errors + if status + errMsg = strrep(errMsg,'\','\\'); % Avoid an "invalid escape-char" warning + error('YMA:export_fig:append_pdf',errMsg); + end + + % Rename the file if needed + if append + movefile(output, varargin{1}, 'f'); + end +end + +% Prepare a text file with ghostscript directives +function prepareCmdFile(cmdfile, output, varargin) + fh = fopen(cmdfile, 'w'); + fprintf(fh, '-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile="%s" -f', output); + fprintf(fh, ' "%s"', varargin{:}); + fclose(fh); +end + +% Convert long/non-ASCII folder names into their short ASCII equivalents +function pathStr = normalizePath(pathStr) + [fpath,fname,fext] = fileparts(pathStr); + if isempty(fpath) || strcmpi(fpath,pathStr), return, end + dirOutput = evalc(['system(''dir /X /AD "' pathStr '*"'')']); + shortName = strtrim(regexprep(dirOutput,{'.*> *',[fname fext '.*']},'')); + if isempty(shortName) + shortName = [fname fext]; + end + fpath = normalizePath(fpath); %recursive until entire fpath is processed + pathStr = fullfile(fpath, shortName); +end + +% Convert a possible string => char +function value = str2char(value) + try + value = controllib.internal.util.hString2Char(value); + catch + if isa(value,'string') + value = char(value); + end + end + value = strtrim(value); +end diff --git a/matlab/C2xyz_v2/export_fig/copyfig.m b/matlab/C2xyz_v2/export_fig/copyfig.m new file mode 100644 index 0000000..9a5b8cb --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/copyfig.m @@ -0,0 +1,59 @@ +function fh = copyfig(fh) +%COPYFIG Create a copy of a figure, without changing the figure +% +% Examples: +% fh_new = copyfig(fh_old) +% +% This function will create a copy of a figure, but not change the figure, +% as copyobj sometimes does, e.g. by changing legends. +% +% IN: +% fh_old - The handle of the figure to be copied. Default: gcf. +% +% OUT: +% fh_new - The handle of the created figure. + +% Copyright (C) Oliver Woodford 2012, Yair Altman 2015 + +% 26/02/15: If temp dir is not writable, use the dest folder for temp +% destination files (Javier Paredes) +% 15/04/15: Suppress warnings during copyobj (Dun Kirk comment on FEX page 2013-10-02) +% 09/09/18: Fix issue #252: Workaround for cases where copyobj() fails for any reason + + % Set the default + if nargin == 0 + fh = gcf; + end + % Is there a legend? + useCopyobj = isempty(findall(fh, 'Type', 'axes', 'Tag', 'legend')); + if useCopyobj + % Safe to copy using copyobj + oldWarn = warning('off'); %Suppress warnings during copyobj (Dun Kirk comment on FEX page 2013-10-02) + try + fh = copyobj(fh, 0); + catch + % Fix issue #252: Workaround for cases where copyobj() fails for any reason + useCopyobj = false; % if copyobj() croaks, use file save/load below + end + warning(oldWarn); + end + if ~useCopyobj + % copyobj will change the figure, so save and then load it instead + tmp_nam = [tempname '.fig']; + try + % Ensure that the temp dir is writable (Javier Paredes 26/2/15) + fid = fopen(tmp_nam,'w'); + fwrite(fid,1); + fclose(fid); + delete(tmp_nam); % cleanup + catch + % Temp dir is not writable, so use the current folder + [dummy,fname,fext] = fileparts(tmp_nam); %#ok + fpath = pwd; + tmp_nam = fullfile(fpath,[fname fext]); + end + hgsave(fh, tmp_nam); + fh = hgload(tmp_nam); + delete(tmp_nam); + end +end diff --git a/matlab/C2xyz_v2/export_fig/crop_borders.m b/matlab/C2xyz_v2/export_fig/crop_borders.m new file mode 100644 index 0000000..b87c842 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/crop_borders.m @@ -0,0 +1,157 @@ +function [A, vA, vB, bb_rel] = crop_borders(A, bcol, padding, crop_amounts) +%CROP_BORDERS Crop the borders of an image or stack of images +% +% [B, vA, vB, bb_rel] = crop_borders(A, bcol, [padding]) +% +%IN: +% A - HxWxCxN stack of images. +% bcol - Cx1 background colour vector. +% padding - scalar indicating how much padding to have in relation to +% the cropped-image-size (0<=padding<=1). Default: 0 +% crop_amounts - 4-element vector of crop amounts: [top,right,bottom,left] +% where NaN/Inf indicate auto-cropping, 0 means no cropping, +% and any other value mean cropping in pixel amounts. +% +%OUT: +% B - JxKxCxN cropped stack of images. +% vA - coordinates in A that contain the cropped image +% vB - coordinates in B where the cropped version of A is placed +% bb_rel - relative bounding box (used for eps-cropping) + +%{ +% 06/03/15: Improved image cropping thanks to Oscar Hartogensis +% 08/06/15: Fixed issue #76: case of transparent figure bgcolor +% 21/02/16: Enabled specifying non-automated crop amounts +% 04/04/16: Fix per Luiz Carvalho for old Matlab releases +% 23/10/16: Fixed issue #175: there used to be a 1px minimal padding in case of crop, now removed +%} + + if nargin < 3 + padding = 0; + end + if nargin < 4 + crop_amounts = nan(1,4); % =auto-cropping + end + crop_amounts(end+1:4) = NaN; % fill missing values with NaN + + [h, w, c, n] = size(A); + if isempty(bcol) % case of transparent bgcolor + bcol = A(ceil(end/2),1,:,1); + end + if isscalar(bcol) + bcol = bcol(ones(c, 1)); + end + + % Crop margin from left + if ~isfinite(crop_amounts(4)) + bail = false; + for l = 1:w + for a = 1:c + if ~all(col(A(:,l,a,:)) == bcol(a)) + bail = true; + break; + end + end + if bail + break; + end + end + else + l = 1 + abs(crop_amounts(4)); + end + + % Crop margin from right + if ~isfinite(crop_amounts(2)) + bcol = A(ceil(end/2),w,:,1); + bail = false; + for r = w:-1:l + for a = 1:c + if ~all(col(A(:,r,a,:)) == bcol(a)) + bail = true; + break; + end + end + if bail + break; + end + end + else + r = w - abs(crop_amounts(2)); + end + + % Crop margin from top + if ~isfinite(crop_amounts(1)) + bcol = A(1,ceil(end/2),:,1); + bail = false; + for t = 1:h + for a = 1:c + if ~all(col(A(t,:,a,:)) == bcol(a)) + bail = true; + break; + end + end + if bail + break; + end + end + else + t = 1 + abs(crop_amounts(1)); + end + + % Crop margin from bottom + bcol = A(h,ceil(end/2),:,1); + if ~isfinite(crop_amounts(3)) + bail = false; + for b = h:-1:t + for a = 1:c + if ~all(col(A(b,:,a,:)) == bcol(a)) + bail = true; + break; + end + end + if bail + break; + end + end + else + b = h - abs(crop_amounts(3)); + end + + if padding == 0 % no padding + % Issue #175: there used to be a 1px minimal padding in case of crop, now removed + %{ + if ~isequal([t b l r], [1 h 1 w]) % Check if we're actually croppping + padding = 1; % Leave one boundary pixel to avoid bleeding on resize + bcol(:) = nan; % make the 1px padding transparent + end + %} + elseif abs(padding) < 1 % pad value is a relative fraction of image size + padding = sign(padding)*round(mean([b-t r-l])*abs(padding)); % ADJUST PADDING + else % pad value is in units of 1/72" points + padding = round(padding); % fix cases of non-integer pad value + end + + if padding > 0 % extra padding + % Create an empty image, containing the background color, that has the + % cropped image size plus the padded border + B = repmat(bcol,[(b-t)+1+padding*2,(r-l)+1+padding*2,1,n]); % Fix per Luiz Carvalho + % vA - coordinates in A that contain the cropped image + vA = [t b l r]; + % vB - coordinates in B where the cropped version of A will be placed + vB = [padding+1, (b-t)+1+padding, padding+1, (r-l)+1+padding]; + % Place the original image in the empty image + B(vB(1):vB(2), vB(3):vB(4), :, :) = A(vA(1):vA(2), vA(3):vA(4), :, :); + A = B; + else % extra cropping + vA = [t-padding b+padding l-padding r+padding]; + A = A(vA(1):vA(2), vA(3):vA(4), :, :); + vB = [NaN NaN NaN NaN]; + end + + % For EPS cropping, determine the relative BoundingBox - bb_rel + bb_rel = [l-1 h-b-1 r+1 h-t+1]./[w h w h]; +end + +function A = col(A) + A = A(:); +end diff --git a/matlab/C2xyz_v2/export_fig/eps2pdf.m b/matlab/C2xyz_v2/export_fig/eps2pdf.m new file mode 100644 index 0000000..aef0c08 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/eps2pdf.m @@ -0,0 +1,285 @@ +function eps2pdf(source, dest, crop, append, gray, quality, gs_options) +%EPS2PDF Convert an eps file to pdf format using ghostscript +% +% Examples: +% eps2pdf source dest +% eps2pdf(source, dest, crop) +% eps2pdf(source, dest, crop, append) +% eps2pdf(source, dest, crop, append, gray) +% eps2pdf(source, dest, crop, append, gray, quality) +% eps2pdf(source, dest, crop, append, gray, quality, gs_options) +% +% This function converts an eps file to pdf format. The output can be +% optionally cropped and also converted to grayscale. If the output pdf +% file already exists then the eps file can optionally be appended as a new +% page on the end of the eps file. The level of bitmap compression can also +% optionally be set. +% +% This function requires that you have ghostscript installed on your system. +% Ghostscript can be downloaded from: http://www.ghostscript.com +% +% Inputs: +% source - filename of the source eps file to convert. The filename is +% assumed to already have the extension ".eps". +% dest - filename of the destination pdf file. The filename is assumed +% to already have the extension ".pdf". +% crop - boolean indicating whether to crop the borders off the pdf. +% Default: true. +% append - boolean indicating whether the eps should be appended to the +% end of the pdf as a new page (if the pdf exists already). +% Default: false. +% gray - boolean indicating whether the output pdf should be grayscale +% or not. Default: false. +% quality - scalar indicating the level of image bitmap quality to +% output. A larger value gives a higher quality. quality > 100 +% gives lossless output. Default: ghostscript prepress default. +% gs_options - optional ghostscript options (e.g.: '-dNoOutputFonts'). If +% multiple options are needed, enclose in call array: {'-a','-b'} + +% Copyright (C) Oliver Woodford 2009-2014, Yair Altman 2015- + +% Suggestion of appending pdf files provided by Matt C at: +% http://www.mathworks.com/matlabcentral/fileexchange/23629 + +% Thank you Fabio Viola for pointing out compression artifacts, leading to the quality setting. +% Thank you Scott for pointing out the subsampling of very small images, which was fixed for lossless compression settings. + +% 09/12/11: Pass font path to ghostscript +% 26/02/15: If temp dir is not writable, use the dest folder for temp destination files (Javier Paredes) +% 28/02/15: Enable users to specify optional ghostscript options (issue #36) +% 01/03/15: Upon GS error, retry without the -sFONTPATH= option (this might solve +% some /findfont errors according to James Rankin, FEX Comment 23/01/15) +% 23/06/15: Added extra debug info in case of ghostscript error; code indentation +% 04/10/15: Suggest a workaround for issue #41 (missing font path; thanks Mariia Fedotenkova) +% 22/02/16: Bug fix from latest release of this file (workaround for issue #41) +% 20/03/17: Added informational message in case of GS croak (issue #186) +% 16/01/18: Improved appending of multiple EPS files into single PDF (issue #233; thanks @shartjen) +% 18/10/19: Workaround for GS 9.51+ .setpdfwrite removal problem (issue #285) +% 18/10/19: Warn when ignoring GS fontpath or quality options; clarified error messages +% 15/01/20: Added information about the GS/destination filepath in case of error (issue #294) +% 20/01/20: Attempted fix for issue #285: unsupported patch transparency in some Ghostscript versions +% 12/02/20: Improved fix for issue #285: add -dNOSAFER and -dALLOWPSTRANSPARENCY (thanks @linasstonys) +% 26/08/21: Added GS version to error message; fixed some problems with PDF append (issue #339) + + % Intialise the options string for ghostscript + options = ['-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile="' dest '"']; + + % Set crop option + if nargin < 3 || crop + options = [options ' -dEPSCrop']; + end + + % Set the font path + fp = font_path(); + if ~isempty(fp) + options = [options ' -sFONTPATH="' fp '"']; + end + + % Set the grayscale option + if nargin > 4 && gray + options = [options ' -sColorConversionStrategy=Gray -dProcessColorModel=/DeviceGray']; + end + + % Set the bitmap quality + qualityOptions = ''; + if nargin > 5 && ~isempty(quality) + qualityOptions = ' -dAutoFilterColorImages=false -dAutoFilterGrayImages=false'; + if quality > 100 + qualityOptions = [qualityOptions ' -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode']; + qualityOptions = [qualityOptions ' -c ".setpdfwrite << /ColorImageDownsampleThreshold 10 /GrayImageDownsampleThreshold 10 >> setdistillerparams"']; + else + qualityOptions = [qualityOptions ' -dColorImageFilter=/DCTEncode -dGrayImageFilter=/DCTEncode']; + v = 1 + (quality < 80); + quality = 1 - quality / 100; + s = sprintf('<< /QFactor %.2f /Blend 1 /HSample [%d 1 1 %d] /VSample [%d 1 1 %d] >>', quality, v, v, v, v); + qualityOptions = [qualityOptions ' -c ".setpdfwrite << /ColorImageDict ' s ' /GrayImageDict ' s ' >> setdistillerparams"']; + end + options = [options qualityOptions]; + end + + % Enable users to specify optional ghostscript options (issue #36) + if nargin > 6 && ~isempty(gs_options) + if iscell(gs_options) + gs_options = sprintf(' %s',gs_options{:}); + elseif ~ischar(gs_options) + error('gs_options input argument must be a string or cell-array of strings'); + else + gs_options = [' ' gs_options]; + end + options = [options gs_options]; + end + + % Check if the output file exists + if nargin > 3 && append && exist(dest, 'file') == 2 + % Store the original filesize for later use below + try + file_info = dir(dest); + orig_bytes = file_info.bytes; + catch + orig_bytes = []; + end + % File exists - append current figure to the end + tmp_nam = [tempname '.pdf']; + [fpath,fname,fext] = fileparts(tmp_nam); + try + % Ensure that the temp dir is writable (Javier Paredes 26/2/15) + fid = fopen(tmp_nam,'w'); + fwrite(fid,1); + fclose(fid); + delete(tmp_nam); + catch + % Temp dir is not writable, so use the dest folder + fpath = fileparts(dest); + tmp_nam = fullfile(fpath,[fname fext]); + end + % Copy the original (dest) pdf file to temporary folder + copyfile(dest, tmp_nam); + % Produce an interim pdf of the source eps, rather than adding the eps directly (issue #233) + % this will override the original (dest) pdf file + orig_options = options; + ghostscript([options ' -f "' source '"']); + [~,fname] = fileparts(tempname); + tmp_nam2 = fullfile(fpath,[fname fext]); % ensure using a writable folder (not necessarily tempdir) + copyfile(dest, tmp_nam2); + % Add the original pdf (tmp_nam) and interim pdf (dest=>tmp_nam2) as inputs to ghostscript + %options = [options ' -f "' tmp_nam '" "' source '"']; % append the source eps to dest pdf + options = [options ' -f "' tmp_nam '" "' tmp_nam2 '"']; % append the interim pdf to dest pdf + try + % Convert to pdf using ghostscript + [status, message] = ghostscript(options); + % The output pdf should now be in dest + + % If the returned message is non-empty, a possible error may have + % occured, so check the file size to ensure whether the file grew + if ~isempty(message) && ~isempty(orig_bytes) + file_info = dir(dest); + new_bytes = file_info.bytes; + if new_bytes < orig_bytes + 100 + % Looks like nothing substantial (if anything) was appended to + % the original pdf, so try adding the eps file directly (issue #339) + options = [orig_options ' -f "' tmp_nam '" "' source '"']; % append the source eps to dest pdf + [status, message] = ghostscript(options); + end + end + + % Delete the intermediate (temporary) files + delete(tmp_nam); + delete(tmp_nam2); + catch me + % Delete the intermediate files and rethrow the error + delete(tmp_nam); + delete(tmp_nam2); + rethrow(me); + end + else + % File doesn't exist or should be over-written + % Add the source eps file as input to ghostscript + options = [options ' -f "' source '"']; + % Convert to pdf using ghostscript + [status, message] = ghostscript(options); + end + + % Check for error + if status + % Catch and correct undefined .setopacityalpha errors (issue #285) + % (see explanation inside print2eps.m) + if ~isempty(regexpi(message,'undefined in .setopacityalpha')) + % First try with -dNOSAFER and -dALLOWPSTRANSPARENCY (thanks @linasstonys) + new_options = [options ' -dNOSAFER -dALLOWPSTRANSPARENCY']; + [status, message] = ghostscript(new_options); + if ~status % hurray! (no error) + return + elseif isempty(regexpi(message,'undefined in .setopacityalpha')) % still some other error + options = new_options; + else % we still get a .setopacityalpha error + % Remove the transparency and retry + fstrm = read_write_entire_textfile(source); + fstrm = regexprep(fstrm, '0?\.\d+ .setopacityalpha \w+\n', ''); + read_write_entire_textfile(source, fstrm); + [status, message] = ghostscript(options); + if ~status % hurray! (no error) + % Alert the user that transparency is not supported + warning('export_fig:GS:quality','Export_fig Face/Edge alpha transparancy is ignored - not supported by your Ghostscript version') + return + end + end + end + + % Retry without the -sFONTPATH= option (this might solve some GS + % /findfont errors according to James Rankin, FEX Comment 23/01/15) + orig_options = options; + if ~isempty(fp) + options = regexprep(options, ' -sFONTPATH=[^ ]+ ',' '); + [status, message] = ghostscript(options); + if ~status % hurray! (no error) + warning('export_fig:GS:fontpath','Export_fig font option is ignored - not supported by your Ghostscript version') + return + end + end + + % Retry without quality options (may solve problems with GS 9.51+, issue #285) + if ~isempty(qualityOptions) + options = strrep(orig_options, qualityOptions, ''); + [status, message] = ghostscript(options); + if ~status % hurray! (no error) + warning('export_fig:GS:quality','Export_fig quality option is ignored - not supported by your Ghostscript version') + return + end + end + + % Report error + if isempty(message) + error(['Unable to generate pdf. Ensure that the destination folder (' fileparts(dest) ') is writable.']); + elseif ~isempty(strfind(message,'/typecheck in /findfont')) %#ok + % Suggest a workaround for issue #41 (missing font path) + font_name = strtrim(regexprep(message,'.*Operand stack:\s*(.*)\s*Execution.*','$1')); + fprintf(2, 'Ghostscript error: could not find the following font(s): %s\n', font_name); + %fpath = fileparts(mfilename('fullpath')); + %gs_fonts_file = fullfile(fpath, '.ignore', 'gs_font_path.txt'); + [unused, gs_fonts_file] = user_string('gs_font_path'); %#ok + fprintf(2, ' try to add the font''s folder to your %s file\n\n', gs_fonts_file); + error('export_fig error'); + else + gs_options = strtrim(gs_options); + fprintf(2, '\nGhostscript error: '); + msg = regexprep(message, '^Error: /([^\n]+).*', '$1'); + if ~isempty(msg) && ~strcmp(msg,message) + fprintf(2,'%s',msg); + end + fprintf(2, '\n * perhaps %s is open by another application\n', dest); + try gs_version = str2num(evalc('ghostscript(''--version'');')); catch, gs_version = ''; end %#ok + if ~isempty(gs_version), gs_version = [' ' num2str(gs_version)]; end + if ~isempty(gs_options) + fprintf(2, ' * or maybe your Ghostscript version%s does not accept the extra "%s" option(s) that you requested\n', gs_version, gs_options); + end + fprintf(2, ' * or maybe you have another gs executable in your system''s path\n\n'); + fprintf(2, 'Ghostscript path: %s\n', user_string('ghostscript')); + fprintf(2, 'Ghostscript options: %s\n\n', orig_options); + error(message); + end + end +end + +% Function to return (and create, where necessary) the font path +function fp = font_path() + fp = user_string('gs_font_path'); + if ~isempty(fp) + return + end + % Create the path + % Start with the default path + fp = getenv('GS_FONTPATH'); + % Add on the typical directories for a given OS + if ispc + if ~isempty(fp) + fp = [fp ';']; + end + fp = [fp getenv('WINDIR') filesep 'Fonts']; + else + if ~isempty(fp) + fp = [fp ':']; + end + fp = [fp '/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype']; + end + user_string('gs_font_path', fp); +end diff --git a/matlab/C2xyz_v2/export_fig/export_fig.m b/matlab/C2xyz_v2/export_fig/export_fig.m new file mode 100644 index 0000000..427fca9 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/export_fig.m @@ -0,0 +1,2343 @@ +function [imageData, alpha] = export_fig(varargin) %#ok<*STRCL1> +%EXPORT_FIG Exports figures in a publication-quality format +% +% Examples: +% imageData = export_fig +% [imageData, alpha] = export_fig +% export_fig filename +% export_fig filename -format1 -format2 +% export_fig ... -nocrop +% export_fig ... -c[,,,] +% export_fig ... -transparent +% export_fig ... -native +% export_fig ... -m +% export_fig ... -r +% export_fig ... -a +% export_fig ... -q +% export_fig ... -p +% export_fig ... -d +% export_fig ... -depsc +% export_fig ... - +% export_fig ... - +% export_fig ... -append +% export_fig ... -bookmark +% export_fig ... -clipboard<:format> +% export_fig ... -update +% export_fig ... -version +% export_fig ... -nofontswap +% export_fig ... -font_space +% export_fig ... -linecaps +% export_fig ... -noinvert +% export_fig ... -preserve_size +% export_fig ... -options +% export_fig ... -silent +% export_fig ... -regexprep +% export_fig(..., handle) +% +% This function saves a figure or single axes to one or more vector and/or +% bitmap file formats, and/or outputs a rasterized version to the workspace, +% with the following properties: +% - Figure/axes reproduced as it appears on screen +% - Cropped borders (optional) +% - Embedded fonts (vector formats) +% - Improved line and grid line styles +% - Anti-aliased graphics (bitmap formats) +% - Render images at native resolution (optional for bitmap formats) +% - Transparent background supported (pdf, eps, png, tif, gif) +% - Semi-transparent patch objects supported (png, tif) +% - RGB, CMYK or grayscale output (CMYK only with pdf, eps, tif) +% - Variable image compression, including lossless (pdf, eps, jpg) +% - Optional rounded line-caps (pdf, eps) +% - Optionally append to file (pdf, tif, gif) +% - Vector formats: pdf, eps, emf, svg +% - Bitmap formats: png, tif, jpg, bmp, gif, clipboard, export to workspace +% +% This function is especially suited to exporting figures for use in +% publications and presentations, because of the high quality and +% portability of media produced. +% +% Note that the background color and figure dimensions are reproduced +% (the latter approximately, and ignoring cropping & magnification) in the +% output file. For transparent background (and semi-transparent patch +% objects), use the -transparent option or set the figure 'Color' property +% to 'none'. To make axes transparent set the axes 'Color' property to +% 'none'. PDF, EPS, TIF & PNG are the only formats that support a transparent +% background; only TIF & PNG formats support transparency of patch objects. +% +% The choice of renderer (opengl/zbuffer/painters) has a large impact on the +% output quality. The default value (opengl for bitmaps, painters for vector +% formats) generally gives good results, but if you aren't satisfied +% then try another renderer. Notes: +% 1) For vector formats (EPS,PDF), only painters generates vector graphics +% 2) For bitmap formats, only opengl correctly renders transparent patches +% 3) For bitmap formats, only painters correctly scales line dash and dot +% lengths when magnifying or anti-aliasing +% 4) Fonts may be substitued with Courier when using painters +% +% When exporting to vector format (PDF & EPS) and bitmap format using the +% painters renderer, this function requires that ghostscript is installed +% on your system. You can download this from: http://www.ghostscript.com +% When exporting to EPS it additionally requires pdftops, from the Xpdf +% suite of functions. You can download this from: http://xpdfreader.com +% +% SVG output uses Matlab's built-in SVG export if available, or otherwise the +% fig2svg (https://github.com/kupiqu/fig2svg) or plot2svg +% (https://github.com/jschwizer99/plot2svg) utilities, if available. +% Note: cropping/padding are not supported in export_fig's SVG and EMF output. +% +% Inputs: +% filename - string containing the name (optionally including full or +% relative path) of the file the figure is to be saved as. If +% a path is not specified, the figure is saved in the current +% directory. If no name and no output arguments are specified, +% the default name, 'export_fig_out', is used. If neither a +% file extension nor a format are specified, a ".png" is added +% and the figure saved in that format. +% - - string(s) containing the output file extension(s). Options: +% '-pdf', '-eps', 'emf', '-svg', '-png', '-tif', '-jpg' and '-bmp'. +% Multiple formats can be specified, without restriction. +% For example: export_fig('-jpg', '-pdf', '-png', ...) +% Note: '-tif','-tiff' are equivalent, and so are '-jpg','-jpeg'. +% -transparent - option indicating that the figure background is to be made +% transparent (PNG,PDF,TIF,EPS,EMF formats only). Implies -noinvert. +% -nocrop - option indicating that empty margins should not be cropped. +% -c[,,,] - option indicating crop amounts. Must be +% a 4-element vector of numeric values: [top,right,bottom,left] +% where NaN/Inf indicates auto-cropping, 0 means no cropping, any +% other value means cropping in pixel amounts. e.g. '-c7,15,0,NaN' +% Note: this option is not supported by SVG and EMF formats. +% -p - option to pad a border of width val to exported files, where +% val is either a relative size with respect to cropped image +% size (i.e. p=0.01 adds a 1% border). For EPS & PDF formats, +% val can also be integer in units of 1/72" points (abs(val)>1). +% val can be positive (padding) or negative (extra cropping). +% If used, the -nocrop flag will be ignored, i.e. the image will +% always be cropped and then padded. Default: 0 (i.e. no padding). +% Note: this option is not supported by SVG and EMF formats. +% -m - option val indicates the factor to magnify the figure dimensions +% when generating bitmap outputs (does not affect vector formats). +% Default: '-m1' (i.e. val=1). Note: val~=1 slows down export_fig. +% -r - option val indicates the resolution (in pixels per inch) to +% export bitmap and vector outputs, without changing dimensions of +% the on-screen figure. Default: '-r864' (for vector output only). +% Note: -m option overides -r option for bitmap exports only. +% -native - option indicating that the output resolution (when outputting +% a bitmap format) should be such that the vertical resolution +% of the first suitable image found in the figure is at the +% native resolution of that image. To specify a particular +% image to use, give it the tag 'export_fig_native'. +% Notes: This overrides any value set with the -m and -r options. +% It also assumes that the image is displayed front-to-parallel +% with the screen. The output resolution is approximate and +% should not be relied upon. Anti-aliasing can have adverse +% effects on image quality (disable with the -a1 option). +% -a1, -a2, -a3, -a4 - option indicating the amount of anti-aliasing (AA) to +% use for bitmap outputs, when GraphicsSmoothing is not available. +% '-a1'=no AA; '-a4'=max. Default: 3 for HG1, 1 for HG2. +% - - option to force a particular renderer (painters, opengl or +% [in R2014a or older] zbuffer). Default value: opengl for bitmap +% formats or figures with patches and/or transparent annotations; +% painters for vector formats without patches/transparencies. +% - - option indicating which colorspace color figures should +% be saved in: RGB (default), CMYK or gray. Usage example: '-gray'. +% Note: CMYK is only supported in PDF, EPS and TIF formats. +% -q - option to vary bitmap image quality (PDF, EPS, JPG formats only). +% A larger val, in the range 0-100, produces higher quality and +% lower compression. val > 100 results in lossless compression. +% Default: '-q95' for JPG, ghostscript prepress default for PDF,EPS. +% Note: lossless compression can sometimes give a smaller file size +% than the default lossy compression, depending on the image type. +% -append - option indicating that if the file already exists the figure is to +% be appended as a new page, instead of being overwritten (default). +% PDF, TIF & GIF output formats only (multi-image GIF = animated). +% -bookmark - option to indicate that a bookmark with the name of the +% figure is to be created in the output file (PDF format only). +% -clipboard - option to save output as an image on the system clipboard. +% -clipboard<:format> - copies to clipboard in the specified format: +% image (default), bitmap, emf, or pdf. +% Notes: Only -clipboard (or -clipboard:image, which is the same) +% applies export_fig parameters such as cropping, padding etc. +% Only the emf format supports -transparent background +% -clipboard:image create a bitmap image using export_fig processing +% -clipboard:bitmap create a bitmap image as-is (no auto-cropping etc.) +% -clipboard:emf is vector format without auto-cropping; Windows-only +% -clipboard:pdf is vector format without cropping; not universally supported +% -d - option to indicate a ghostscript setting. For example, +% -dMaxBitmap=0 or -dNoOutputFonts (Ghostscript 9.15+). +% -depsc - option to use EPS level-3 rather than the default level-2 print +% device. This solves some bugs with Matlab's default -depsc2 device +% such as discolored subplot lines on images (vector formats only). +% -update - option to download and install the latest version of export_fig +% -version - return the current export_fig version, without any figure export +% -nofontswap - option to avoid font swapping. Font swapping is automatically +% done in vector formats (only): 11 standard Matlab fonts are +% replaced by the original figure fonts. This option prevents this. +% -font_space - option to set a spacer character for font-names that +% contain spaces, used by EPS/PDF. Default: '' +% -linecaps - option to create rounded line-caps (vector formats only). +% -noinvert - option to avoid setting figure's InvertHardcopy property to +% 'off' during output (this solves some problems of empty outputs). +% -preserve_size - option to preserve the figure's PaperSize property in output +% file (PDF/EPS formats only; default is to not preserve it). +% -options - format-specific parameters as defined in Matlab's +% documentation of the imwrite function, contained in a struct under +% the format name. For example to specify the JPG Comment parameter, +% pass a struct such as this: options.JPG.Comment='abc'. Similarly, +% options.PNG.BitDepth=4. Only used by PNG,TIF,JPG,GIF output formats. +% Options can also be specified as a cell array of name-value pairs, +% e.g. {'BitDepth',4, 'Author','Yair'} - these options will be used +% by all supported output formats of the export_fig command. +% -silent - option to avoid various warning and informational messages, such +% as version update checks, transparency or renderer issues, etc. +% -regexprep - replaces all occurances of (a regular expression +% string or array of strings; case-sensitive), with the corresponding +% string(s), in EPS/PDF files (only). See regexp function's doc. +% Warning: invalid replacement can make your EPS/PDF file unreadable! +% handle - The handle of the figure, axes or uipanels (can be an array of +% handles, but the objects must be in the same figure) which is +% to be saved. Default: gcf (handle of current figure). +% +% Outputs: +% imageData - MxNxC uint8 image array of the exported image. +% alpha - MxN single array of alphamatte values in the range [0,1], +% for the case when the background is transparent. +% +% Some helpful examples and tips can be found at: +% https://github.com/altmany/export_fig +% +% See also PRINT, SAVEAS, ScreenCapture (on the Matlab File Exchange) + +%{ +% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015- + +% The idea of using ghostscript is inspired by Peder Axensten's SAVEFIG +% (fex id: 10889) which is itself inspired by EPS2PDF (fex id: 5782). +% The idea for using pdftops came from the MATLAB newsgroup (id: 168171). +% The idea of editing the EPS file to change line styles comes from Jiro +% Doke's FIXPSLINESTYLE (fex id: 17928). +% The idea of changing dash length with line width came from comments on +% fex id: 5743, but the implementation is mine :) +% The idea of anti-aliasing bitmaps came from Anders Brun's MYAA (fex id: +% 20979). +% The idea of appending figures in pdfs came from Matt C in comments on the +% FEX (id: 23629) + +% Thanks to Roland Martin for pointing out the colour MATLAB +% bug/feature with colorbar axes and transparent backgrounds. +% Thanks also to Andrew Matthews for describing a bug to do with the figure +% size changing in -nodisplay mode. I couldn't reproduce it, but included a +% fix anyway. +% Thanks to Tammy Threadgill for reporting a bug where an axes is not +% isolated from gui objects. +%} +%{ +% 23/02/12: Ensure that axes limits don't change during printing +% 14/03/12: Fix bug in fixing the axes limits (thanks to Tobias Lamour for reporting it). +% 02/05/12: Incorporate patch of Petr Nechaev (many thanks), enabling bookmarking of figures in pdf files. +% 09/05/12: Incorporate patch of Arcelia Arrieta (many thanks), to keep tick marks fixed. +% 12/12/12: Add support for isolating uipanels. Thanks to michael for suggesting it. +% 25/09/13: Add support for changing resolution in vector formats. Thanks to Jan Jaap Meijer for suggesting it. +% 07/05/14: Add support for '~' at start of path. Thanks to Sally Warner for suggesting it. +% 24/02/15: Fix Matlab R2014b bug (issue #34): plot markers are not displayed when ZLimMode='manual' +% 25/02/15: Fix issue #4 (using HG2 on R2014a and earlier) +% 25/02/15: Fix issue #21 (bold TeX axes labels/titles in R2014b) +% 26/02/15: If temp dir is not writable, use the user-specified folder for temporary EPS/PDF files (Javier Paredes) +% 27/02/15: Modified repository URL from github.com/ojwoodford to /altmany; Indented main function; Added top-level try-catch block to display useful workarounds +% 28/02/15: Enable users to specify optional ghostscript options (issue #36) +% 06/03/15: Improved image padding & cropping thanks to Oscar Hartogensis +% 26/03/15: Fixed issue #49 (bug with transparent grayscale images); fixed out-of-memory issue +% 26/03/15: Fixed issue #42: non-normalized annotations on HG1 +% 26/03/15: Fixed issue #46: Ghostscript crash if figure units <> pixels +% 27/03/15: Fixed issue #39: bad export of transparent annotations/patches +% 28/03/15: Fixed issue #50: error on some Matlab versions with the fix for issue #42 +% 29/03/15: Fixed issue #33: bugs in Matlab's print() function with -cmyk +% 29/03/15: Improved processing of input args (accept space between param name & value, related to issue #51) +% 30/03/15: When exporting *.fig files, then saveas *.fig if figure is open, otherwise export the specified fig file +% 30/03/15: Fixed edge case bug introduced yesterday (commit #ae1755bd2e11dc4e99b95a7681f6e211b3fa9358) +% 09/04/15: Consolidated header comment sections; initialize output vars only if requested (nargout>0) +% 14/04/15: Workaround for issue #45: lines in image subplots are exported in invalid color +% 15/04/15: Fixed edge-case in parsing input parameters; fixed help section to show the -depsc option (issue #45) +% 21/04/15: Bug fix: Ghostscript croaks on % chars in output PDF file (reported by Sven on FEX page, 15-Jul-2014) +% 22/04/15: Bug fix: Pdftops croaks on relative paths (reported by Tintin Milou on FEX page, 19-Jan-2015) +% 04/05/15: Merged fix #63 (Kevin Mattheus Moerman): prevent tick-label changes during export +% 07/05/15: Partial fix for issue #65: PDF export used painters rather than opengl renderer (thanks Nguyenr) +% 08/05/15: Fixed issue #65: bad PDF append since commit #e9f3cdf 21/04/15 (thanks Robert Nguyen) +% 12/05/15: Fixed issue #67: exponent labels cropped in export, since fix #63 (04/05/15) +% 28/05/15: Fixed issue #69: set non-bold label font only if the string contains symbols (\beta etc.), followup to issue #21 +% 29/05/15: Added informative error message in case user requested SVG output (issue #72) +% 09/06/15: Fixed issue #58: -transparent removed anti-aliasing when exporting to PNG +% 19/06/15: Added -update option to download and install the latest version of export_fig +% 07/07/15: Added -nofontswap option to avoid font-swapping in EPS/PDF +% 16/07/15: Fixed problem with anti-aliasing on old Matlab releases +% 11/09/15: Fixed issue #103: magnification must never become negative; also fixed reported error msg in parsing input params +% 26/09/15: Alert if trying to export transparent patches/areas to non-PNG outputs (issue #108) +% 04/10/15: Do not suggest workarounds for certain errors that have already been handled previously +% 01/11/15: Fixed issue #112: use same renderer in print2eps as export_fig (thanks to Jesús Pestana Puerta) +% 10/11/15: Custom GS installation webpage for MacOS. Thanks to Andy Hueni via FEX +% 19/11/15: Fixed clipboard export in R2015b (thanks to Dan K via FEX) +% 21/02/16: Added -c option for indicating specific crop amounts (idea by Cedric Noordam on FEX) +% 08/05/16: Added message about possible error reason when groot.Units~=pixels (issue #149) +% 17/05/16: Fixed case of image YData containing more than 2 elements (issue #151) +% 08/08/16: Enabled exporting transparency to TIF, in addition to PNG/PDF (issue #168) +% 11/12/16: Added alert in case of error creating output PDF/EPS file (issue #179) +% 13/12/16: Minor fix to the commit for issue #179 from 2 days ago +% 22/03/17: Fixed issue #187: only set manual ticks when no exponent is present +% 09/04/17: Added -linecaps option (idea by Baron Finer, issue #192) +% 15/09/17: Fixed issue #205: incorrect tick-labels when Ticks number don't match the TickLabels number +% 15/09/17: Fixed issue #210: initialize alpha map to ones instead of zeros when -transparent is not used +% 18/09/17: Added -font_space option to replace font-name spaces in EPS/PDF (workaround for issue #194) +% 18/09/17: Added -noinvert option to solve some export problems with some graphic cards (workaround for issue #197) +% 08/11/17: Fixed issue #220: axes exponent is removed in HG1 when TickMode is 'manual' (internal Matlab bug) +% 08/11/17: Fixed issue #221: alert if the requested folder does not exist +% 19/11/17: Workaround for issue #207: alert when trying to use transparent bgcolor with -opengl +% 29/11/17: Workaround for issue #206: warn if exporting PDF/EPS for a figure that contains an image +% 11/12/17: Fixed issue #230: use OpenGL renderer when exported image contains transparency (also see issue #206) +% 30/01/18: Updated SVG message to point to https://github.com/kupiqu/plot2svg and display user-selected filename if available +% 27/02/18: Fixed issue #236: axes exponent cropped from output if on right-hand axes +% 29/05/18: Fixed issue #245: process "string" inputs just like 'char' inputs +% 13/08/18: Fixed issue #249: correct black axes color to off-black to avoid extra cropping with -transparent +% 27/08/18: Added a possible file-open reason in EPS/PDF write-error message (suggested by "craq" on FEX page) +% 22/09/18: Xpdf website changed to xpdfreader.com +% 23/09/18: Fixed issue #243: only set non-bold font (workaround for issue #69) in R2015b or earlier; warn if changing font +% 23/09/18: Workaround for issue #241: don't use -r864 in EPS/PDF outputs when -native is requested (solves black lines problem) +% 18/11/18: Issue #261: Added informative alert when trying to export a uifigure (which is not currently supported) +% 13/12/18: Issue #261: Fixed last commit for cases of specifying axes/panel handle as input, rather than a figure handle +% 13/01/19: Issue #72: Added basic SVG output support +% 04/02/19: Workaround for issues #207 and #267: -transparent implies -noinvert +% 08/03/19: Issue #269: Added ability to specify format-specific options for PNG,TIF,JPG outputs; fixed help section +% 21/03/19: Fixed the workaround for issues #207 and #267 from 4/2/19 (-transparent now does *NOT* imply -noinvert; -transparent output should now be ok in all formats) +% 12/06/19: Issue #277: Enabled preservation of figure's PaperSize in output PDF/EPS file +% 06/08/19: Remove warning message about obsolete JavaFrame in R2019b +% 30/10/19: Fixed issue #261: added support for exporting uifigures and uiaxes (thanks to idea by @MarvinILA) +% 12/12/19: Added warning in case user requested anti-aliased output on an aliased HG2 figure (issue #292) +% 15/12/19: Added promo message +% 08/01/20: (3.00) Added check for newer version online (initialized to version 3.00) +% 15/01/20: (3.01) Clarified/fixed error messages; Added error IDs; easier -update; various other small fixes +% 20/01/20: (3.02) Attempted fix for issue #285 (unsupported patch transparency in some Ghostscript versions); Improved suggested fixes message upon error +% 03/03/20: (3.03) Suggest to upload problematic EPS file in case of a Ghostscript error in eps2pdf (& don't delete this file) +% 22/03/20: (3.04) Workaround for issue #15; Alert if ghostscript file not found on Matlab path +% 10/05/20: (3.05) Fix the generated SVG file, based on Cris Luengo's SVG_FIX_VIEWBOX; Don't generate PNG when only SVG is requested +% 02/07/20: (3.06) Significantly improved performance (speed) and fidelity of bitmap images; Return alpha matrix for bitmap images; Fixed issue #302 (-update bug); Added EMF output; Added -clipboard formats (image,bitmap,emf,pdf); Added hints for exportgraphics/copygraphics usage in certain use-cases; Added description of new version features in the update message; Fixed issue #306 (yyaxis cropping); Fixed EPS/PDF auto-cropping with -transparent +% 06/07/20: (3.07) Fixed issue #307 (bug in padding of bitmap images); Fixed axes transparency in -clipboard:emf with -transparent +% 07/07/20: (3.08) Fixed issue #308 (bug in R2019a and earlier) +% 18/07/20: (3.09) Fixed issue #310 (bug with tiny image on HG1); Fixed title cropping bug +% 23/07/20: (3.10) Fixed issues #313,314 (figure position changes if units ~= pixels); Display multiple versions change-log, if relevant; Fixed issue #312 (PNG: only use alpha channel if -transparent was requested) +% 30/07/20: (3.11) Fixed issue #317 (bug when exporting figure with non-pixels units); Potential solve also of issue #303 (size change upon export) +% 14/08/20: (3.12) Fixed some exportgraphics/copygraphics compatibility messages; Added -silent option to suppress non-critical messages; Reduced promo message display rate to once a week; Added progress messages during export_fig('-update') +% 07/10/20: (3.13) Added version info and change-log links to update message (issue #322); Added -version option to return the current export_fig version; Avoid JavaFrame warning message; Improved exportgraphics/copygraphics infomercial message inc. support of upcoming Matlab R2021a +% 10/12/20: (3.14) Enabled user-specified regexp replacements in generated EPS/PDF files (issue #324) +% 01/07/21: (3.15) Added informative message in case of setopacityalpha error (issue #285) +% 26/08/21: (3.16) Fixed problem of white elements appearing transparent (issue #330); clarified some error messages +% 27/09/21: (3.17) Made Matlab's builtin export the default for SVG, rather than fig2svg/plot2svg (issue #316); updated transparency error message (issues #285, #343); reduced promo message frequency +% 03/10/21: (3.18) Fixed warning about invalid escaped character when the output folder does not exist (issue #345) +% 25/10/21: (3.19) Fixed print error when exporting a specific subplot (issue #347); avoid duplicate error messages +% 11/12/21: (3.20) Added GIF support, including animated & transparent-background; accept format options as cell-array, not just nested struct +% 20/12/21: (3.21) Speedups; fixed exporting non-current figure (hopefully fixes issue #318); fixed warning when appending to animated GIF +%} + + if nargout + [imageData, alpha] = deal([]); + end + displaySuggestedWorkarounds = true; + + % Ensure the figure is rendered correctly _now_ so that properties like axes limits are up-to-date + drawnow; + pause(0.02); % this solves timing issues with Java Swing's EDT (http://undocumentedmatlab.com/blog/solving-a-matlab-hang-problem) + + % Display promo (just once every 10 days!) + persistent promo_time + if isempty(promo_time) + try promo_time = getpref('export_fig','promo_time'); catch, promo_time=-inf; end + end + if abs(now-promo_time) > 10 && ~isdeployed + programsCrossCheck; + msg = char('Gps!qspgfttjpobm!Nbumbc!bttjtubodf-!qmfbtf!dpoubdu!=%?'-1); + url = char('iuuqt;00VoepdvnfoufeNbumbc/dpn0dpotvmujoh'-1); + displayPromoMsg(msg, url); + promo_time = now; + setpref('export_fig','promo_time',now) + end + + % Parse the input arguments + fig = get(0, 'CurrentFigure'); + argNames = {}; + for idx = nargin:-1:1, argNames{idx} = inputname(idx); end + [fig, options] = parse_args(nargout, fig, argNames, varargin{:}); + + % Check for newer version and exportgraphics/copygraphics compatibility + currentVersion = 3.21; + if options.version % export_fig's version requested - return it and bail out + imageData = currentVersion; + return + end + if ~options.silent + % Check for newer version (not too often) + checkForNewerVersion(3.21); % ...(currentVersion) is better but breaks in version 3.05- due to regexp limitation in checkForNewerVersion() + + % Hint to users to use exportgraphics/copygraphics in certain cases + alertForExportOrCopygraphics(options); + %return + end + + % Ensure that we have a figure handle + if isequal(fig,-1) + return % silent bail-out + elseif isempty(fig) + error('export_fig:NoFigure','No figure found'); + else + oldWarn = warning('off','MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame'); + warning off MATLAB:ui:javaframe:PropertyToBeRemoved + uifig = handle(ancestor(fig,'figure')); + try jf = get(uifig,'JavaFrame_I'); catch, try jf = get(uifig,'JavaFrame'); catch, jf=1; end, end %#ok + warning(oldWarn); + if isempty(jf) % this is a uifigure + %error('export_fig:uifigures','Figures created using the uifigure command or App Designer are not supported by export_fig. See %s for details.', hyperlink('https://github.com/altmany/export_fig/issues/261','issue #261')); + if numel(fig) > 1 + error('export_fig:uifigure:multipleHandles', 'export_fig only supports exporting a single uifigure handle at a time; array of handles is not currently supported.') + elseif ~any(strcmpi(fig.Type,{'figure','axes'})) + error('export_fig:uifigure:notFigureOrAxes', 'export_fig only supports exporting a uifigure or uiaxes handle; other handles of a uifigure are not currently supported.') + end + % fig is either a uifigure or uiaxes handle + isUiaxes = strcmpi(fig.Type,'axes'); + if isUiaxes + % Label the specified axes so that we can find it in the legacy figure + oldUserData = fig.UserData; + tempStr = tempname; + fig.UserData = tempStr; + end + try + % Create an invisible legacy figure at the same position/size as the uifigure + hNewFig = figure('Units',uifig.Units, 'Position',uifig.Position, 'MenuBar','none', 'ToolBar','none', 'Visible','off'); + % Copy the uifigure contents onto the new invisible legacy figure + try + hChildren = allchild(uifig); %=uifig.Children; + copyobj(hChildren,hNewFig); + catch + if ~options.silent + warning('export_fig:uifigure:controls', 'Some uifigure controls cannot be exported by export_fig and will not appear in the generated output.'); + end + end + try fig.UserData = oldUserData; catch, end % restore axes UserData, if modified above + % Replace the uihandle in the input args with the legacy handle + if isUiaxes % uiaxes + % Locate the corresponding axes handle in the new legacy figure + hAxes = findall(hNewFig,'type','axes','UserData',tempStr); + if isempty(hAxes) % should never happen, check just in case + hNewHandle = hNewFig; % export the figure instead of the axes + else + hNewHandle = hAxes; % new axes handle found: use it instead of the uiaxes + end + else % uifigure + hNewHandle = hNewFig; + end + varargin(cellfun(@(c)isequal(c,fig),varargin)) = {hNewHandle}; + % Rerun export_fig on the legacy figure (with the replaced handle) + [imageData, alpha] = export_fig(varargin{:}); + % Delete the temp legacy figure and bail out + try delete(hNewFig); catch, end + return + catch err + % Clean up the temp legacy figure and report the error + try delete(hNewFig); catch, end + rethrow(err) + end + end + end + + % Isolate the subplot, if it is one + cls = all(ismember(get(fig, 'Type'), {'axes', 'uipanel'})); + if cls + % Given handles of one or more axes, so isolate them from the rest + fig = isolate_axes(fig); + else + % Check we have a figure + if ~isequal(get(fig, 'Type'), 'figure') + error('export_fig:BadHandle','Handle must be that of a figure, axes or uipanel'); + end + % Get the old InvertHardcopy mode + old_mode = get(fig, 'InvertHardcopy'); + end + % from this point onward, fig is assured to be a figure handle + + % Hack the font units where necessary (due to a font rendering bug in print?). + % This may not work perfectly in all cases. + % Also it can change the figure layout if reverted, so use a copy. + magnify = options.magnify * options.aa_factor; + if isbitmap(options) && magnify ~= 1 + fontu = findall(fig, 'FontUnits', 'normalized'); + if ~isempty(fontu) + % Some normalized font units found + if ~cls + fig = copyfig(fig); + set(fig, 'Visible', 'off'); + fontu = findall(fig, 'FontUnits', 'normalized'); + cls = true; + end + set(fontu, 'FontUnits', 'points'); + end + end + + try + % MATLAB "feature": axes limits and tick marks can change when printing + Hlims = findall(fig, 'Type', 'axes'); + if ~cls + % Record the old axes limit and tick modes + Xlims = make_cell(get(Hlims, 'XLimMode')); + Ylims = make_cell(get(Hlims, 'YLimMode')); + Zlims = make_cell(get(Hlims, 'ZLimMode')); + Xtick = make_cell(get(Hlims, 'XTickMode')); + Ytick = make_cell(get(Hlims, 'YTickMode')); + Ztick = make_cell(get(Hlims, 'ZTickMode')); + Xlabel = make_cell(get(Hlims, 'XTickLabelMode')); + Ylabel = make_cell(get(Hlims, 'YTickLabelMode')); + Zlabel = make_cell(get(Hlims, 'ZTickLabelMode')); + end + + % Set all axes limit and tick modes to manual, so the limits and ticks can't change + % Fix Matlab R2014b bug (issue #34): plot markers are not displayed when ZLimMode='manual' + set(Hlims, 'XLimMode', 'manual', 'YLimMode', 'manual'); + set_tick_mode(Hlims, 'X'); + set_tick_mode(Hlims, 'Y'); + if ~using_hg2(fig) + set(Hlims,'ZLimMode', 'manual'); + set_tick_mode(Hlims, 'Z'); + end + catch + % ignore - fix issue #4 (using HG2 on R2014a and earlier) + end + + % Fix issue #21 (bold TeX axes labels/titles in R2014b when exporting to EPS/PDF) + try + if using_hg2(fig) && isvector(options) + % Set the FontWeight of axes labels/titles to 'normal' + % Fix issue #69: set non-bold font only if the string contains symbols (\beta etc.) + % Issue #243: only set non-bold font (workaround for issue #69) in R2015b or earlier + try isPreR2016a = verLessThan('matlab','8.7'); catch, isPreR2016a = true; end + if isPreR2016a + texLabels = findall(fig, 'type','text', 'FontWeight','bold'); + symbolIdx = ~cellfun('isempty',strfind({texLabels.String},'\')); + if ~isempty(symbolIdx) + set(texLabels(symbolIdx), 'FontWeight','normal'); + if ~options.silent + warning('export_fig:BoldTexLabels', 'Bold labels with Tex symbols converted into non-bold in export_fig (fix for issue #69)'); + end + end + end + end + catch + % ignore + end + + % Fix issue #42: non-normalized annotations on HG1 (internal Matlab bug) + annotationHandles = []; + try + if ~using_hg2(fig) + annotationHandles = findall(fig,'Type','hggroup','-and','-property','Units','-and','-not','Units','norm'); + try % suggested by Jesús Pestana Puerta (jespestana) 30/9/2015 + originalUnits = get(annotationHandles,'Units'); + set(annotationHandles,'Units','norm'); + catch + end + end + catch + % should never happen, but ignore in any case - issue #50 + end + + % Fix issue #46: Ghostscript crash if figure units <> pixels + pos = get(fig, 'Position'); % Fix issues #313, #314 + oldFigUnits = get(fig,'Units'); + set(fig,'Units','pixels'); + pixelpos = get(fig, 'Position'); %=getpixelposition(fig); + + tcol = get(fig, 'Color'); + tcol_orig = tcol; + + % Set to print exactly what is there + if options.invert_hardcopy + try set(fig, 'InvertHardcopy', 'off'); catch, end % fail silently in uifigures + end + + % Set the renderer + switch options.renderer + case 1 + renderer = '-opengl'; + case 2 + renderer = '-zbuffer'; + case 3 + renderer = '-painters'; + otherwise + renderer = '-opengl'; % Default for bitmaps + end + + try + tmp_nam = ''; % initialize + + % Do the bitmap formats first + if isbitmap(options) + if abs(options.bb_padding) > 1 + displaySuggestedWorkarounds = false; + error('export_fig:padding','For bitmap output (png,jpg,tif,bmp) the padding value (-p) must be between -1 1.1 * options.magnify * pixelpos(4) %1.1 to avoid edge-cases + % Downscale the image + A = downsize(A, options.aa_factor); + alpha = downsize(alpha, options.aa_factor); + end + % Crop the margins based on the bgcolor, if requested + if options.crop + %[alpha, v] = crop_borders(alpha, 0, 1, options.crop_amounts); + %A = A(v(1):v(2),v(3):v(4),:); + [A, vA, vB] = crop_borders(A, tcol, options.bb_padding, options.crop_amounts); + if ~any(isnan(vB)) % positive padding + sz = size(A); % Fix issue #308 + B = repmat(uint8(zeros(1,1,size(alpha,3))),sz([1,2])); % Fix issue #307 %=zeros(sz([1,2]),'uint8'); + B(vB(1):vB(2), vB(3):vB(4), :) = alpha(vA(1):vA(2), vA(3):vA(4), :); % ADDED BY OH + alpha = B; + else % negative padding + alpha = alpha(vA(1):vA(2), vA(3):vA(4), :); + end + end + % Get the non-alpha image (presumably unneeded with Java-based screen-capture) + %{ + if isbitmap(options) + % Modify the intensity of the pixels' RGB values based on their alpha transparency + % TODO: not sure that we want this with Java screen-capture values! + alph = alpha(:,:,ones(1, size(A, 3))); + A = uint8(single(A) .* alph + 255 * (1 - alph)); + end + %} + % Revert the figure properties back to their original values + set(fig, 'Units',oldFigUnits, 'Position',pos, 'Color',tcol_orig); + % Check for greyscale images + if options.colourspace == 2 + % Convert to greyscale + A = rgb2grey(A); + else + % Return only one channel for greyscale + A = check_greyscale(A); + end + % Change alpha from [0:255] uint8 => [0:1] single from here onward: + alpha = single(alpha) / 255; + % Outputs + if options.im + imageData = A; + end + if options.alpha + imageData = A; + %alpha = ones(size(A, 1), size(A, 2), 'single'); %=all pixels opaque + end + % Save the images + if options.png + % Compute the resolution + res = options.magnify * get(0, 'ScreenPixelsPerInch') / 25.4e-3; + % Save the png + [format_options, bitDepth] = getFormatOptions(options, 'png'); %Issue #269 + pngOptions = {[options.name '.png'], 'ResolutionUnit','meter', 'XResolution',res, 'YResolution',res, format_options{:}}; %#ok + if options.transparent % Fix issue #312: only use alpha channel if -transparent was requested + pngOptions = [pngOptions 'Alpha',double(alpha)]; + end + if ~isempty(bitDepth) && bitDepth < 16 && size(A,3) == 3 + % BitDepth specification requires using a color-map + [img, map] = rgb2ind(A, 256); + imwrite(img, map, pngOptions{:}); + else + imwrite(A, pngOptions{:}); + end + end + if options.bmp + imwrite(A, [options.name '.bmp']); + end + if options.jpg + % Save jpeg with the specified quality + quality = options.quality; + if isempty(quality) + quality = 95; + end + format_options = getFormatOptions(options, 'jpg'); %Issue #269 + if quality > 100 + imwrite(A, [options.name '.jpg'], 'Mode','lossless', format_options{:}); + else + imwrite(A, [options.name '.jpg'], 'Quality',quality, format_options{:}); + end + end + if options.tif + % Save tif images in cmyk if wanted (and possible) + if options.colourspace == 1 && size(A, 3) == 3 + img = double(255 - A); + K = min(img, [], 3); + K_ = 255 ./ max(255 - K, 1); + C = (img(:,:,1) - K) .* K_; + M = (img(:,:,2) - K) .* K_; + Y = (img(:,:,3) - K) .* K_; + img = uint8(cat(3, C, M, Y, K)); + clear C M Y K K_ + else + img = A; + end + append_mode = {'overwrite', 'append'}; + format_options = getFormatOptions(options, 'tif'); %Issue #269 + imwrite(img, [options.name '.tif'], 'Resolution',options.magnify*get(0,'ScreenPixelsPerInch'), 'WriteMode',append_mode{options.append+1}, format_options{:}); + end + if options.gif + % Convert to color-map image required by GIF specification + [img, map] = rgb2ind(A, 256); + % Handle the case of trying to append to non-existing GIF file + % (imwrite() croaks when asked to append to a non-existing file) + filename = [options.name '.gif']; + options.append = options.append && existFile(filename); + % Set the default GIF options for imwrite() + append_mode = {'overwrite', 'append'}; + writeMode = append_mode{options.append+1}; + gifOptions = {'WriteMode',writeMode}; + if options.transparent % only use alpha channel if -transparent was requested + exp = 256 .^ (0:2); + mapVals = sum(round(map*255).*exp,2); + tcolVal = sum(round(double(tcol)).*exp); + alphaIdx = find(mapVals==tcolVal,1); + if isempty(alphaIdx) || alphaIdx <= 0, alphaIdx = 1; end + % GIF color index of uint8/logical images starts at 0, not 1 + if ~isfloat(img), alphaIdx = alphaIdx - 1; end + gifOptions = [gifOptions, 'TransparentColor',alphaIdx, ... + 'DisposalMethod','restoreBG']; + end + if ~options.append + % LoopCount and BackgroundColor can only be specified in the + % 1st GIF frame (not in append mode) + % Set default LoopCount=65535 to enable looping within MS Office + gifOptions = [gifOptions, 'LoopCount',65535, 'BackgroundColor',alphaIdx]; + end + % Set GIF-specific options specified by the user (if any) + format_options = getFormatOptions(options, 'gif'); + gifOptions = [gifOptions, format_options{:}]; + % Save the gif file + imwrite(img, map, filename, gifOptions{:}); + end + end + + % Now do the vector formats which are based on EPS + if isvector(options) + hImages = findall(fig,'type','image'); + % Set the default renderer to painters + if ~options.renderer + % Handle transparent patches + hasTransparency = ~isempty(findall(fig,'-property','FaceAlpha','-and','-not','FaceAlpha',1)); + if hasTransparency + % Alert if trying to export transparent patches/areas to non-supported outputs (issue #108) + % http://www.mathworks.com/matlabcentral/answers/265265-can-export_fig-or-else-draw-vector-graphics-with-transparent-surfaces + % TODO - use transparency when exporting to PDF by not passing via print2eps + msg = 'export_fig currently supports transparent patches/areas only in PNG output. '; + if options.pdf && ~options.silent + warning('export_fig:transparency', '%s\nTo export transparent patches/areas to PDF, use the print command:\n print(gcf, ''-dpdf'', ''%s.pdf'');', msg, options.name); + elseif ~options.png && ~options.tif && ~options.silent % issue #168 + warning('export_fig:transparency', '%s\nTo export the transparency correctly, try using the ScreenCapture utility on the Matlab File Exchange: http://bit.ly/1QFrBip', msg); + end + elseif ~isempty(hImages) + % Fix for issue #230: use OpenGL renderer when exported image contains transparency + for idx = 1 : numel(hImages) + cdata = get(hImages(idx),'CData'); + if any(isnan(cdata(:))) + hasTransparency = true; + break + end + end + end + hasPatches = ~isempty(findall(fig,'type','patch')); + if hasTransparency || hasPatches + % This is *MUCH* slower, but more accurate for patches and transparent annotations (issue #39) + renderer = '-opengl'; + else + renderer = '-painters'; + end + end + options.rendererStr = renderer; % fix for issue #112 + % Generate some filenames + tmp_nam = [tempname '.eps']; + try + % Ensure that the temp dir is writable (Javier Paredes 30/1/15) + fid = fopen(tmp_nam,'w'); + fwrite(fid,1); + fclose(fid); + delete(tmp_nam); + pdf_nam_tmp = [tempname '.pdf']; + catch + % Temp dir is not writable, so use the user-specified folder + [dummy,fname,fext] = fileparts(tmp_nam); %#ok + fpath = fileparts(options.name); + tmp_nam = fullfile(fpath,[fname fext]); + pdf_nam_tmp = fullfile(fpath,[fname '.pdf']); + end + if options.pdf + pdf_nam = [options.name '.pdf']; + try copyfile(pdf_nam, pdf_nam_tmp, 'f'); catch, end % fix for issue #65 + else + pdf_nam = pdf_nam_tmp; + end + % Generate the options for print + printArgs = {renderer}; + if ~isempty(options.resolution) % issue #241 + printArgs{end+1} = sprintf('-r%d', options.resolution); + end + if options.colourspace == 1 % CMYK + % Issue #33: due to internal bugs in Matlab's print() function, we can't use its -cmyk option + %printArgs{end+1} = '-cmyk'; + end + if ~options.crop + % Issue #56: due to internal bugs in Matlab's print() function, we can't use its internal cropping mechanism, + % therefore we always use '-loose' (in print2eps.m) and do our own cropping (in crop_borders) + %printArgs{end+1} = '-loose'; + end + if any(strcmpi(varargin,'-depsc')) + % Issue #45: lines in image subplots are exported in invalid color. + % The workaround is to use the -depsc parameter instead of the default -depsc2 + printArgs{end+1} = '-depsc'; + end + % Print to EPS file + try + % Remove background if requested (issue #207) + originalBgColor = get(fig, 'Color'); + [hXs, hXrs, hYs, hYrs, hZs, hZrs] = deal([]); + if options.transparent %&& ~isequal(get(fig, 'Color'), 'none') + if options.renderer == 1 && ~options.silent % OpenGL + warning('export_fig:openglTransparentBG', '-opengl sometimes fails to produce transparent backgrounds; in such a case, try to use -painters instead'); + end + + % Fix for issue #207, #267 (corrected) + set(fig,'Color','none'); + + % Correct black axes color to off-black (issue #249) + hAxes = findall(fig, 'Type','axes'); + [hXs,hXrs] = fixBlackAxle(hAxes, 'XColor'); + [hYs,hYrs] = fixBlackAxle(hAxes, 'YColor'); + [hZs,hZrs] = fixBlackAxle(hAxes, 'ZColor'); + + % Correct black titles to off-black + % https://www.mathworks.com/matlabcentral/answers/567027-matlab-export_fig-crops-title + try + hTitle = get(hAxes, 'Title'); + for idx = numel(hTitle) : -1 : 1 + color = get(hTitle,'Color'); + if isequal(color,[0,0,0]) || isequal(color,'k') + set(hTitle(idx), 'Color', [0,0,0.01]); %off-black + else + hTitle(idx) = []; % remove from list + end + end + catch + hTitle = []; + end + end + % Generate an eps + print2eps(tmp_nam, fig, options, printArgs{:}); %winopen(tmp_nam) + % { + % Remove the background, if desired + if options.transparent %&& ~isequal(get(fig, 'Color'), 'none') + eps_remove_background(tmp_nam, 1 + using_hg2(fig)); + + % Revert the black axes colors + set(hXs, 'XColor', [0,0,0]); + set(hYs, 'YColor', [0,0,0]); + set(hZs, 'ZColor', [0,0,0]); + set(hXrs, 'Color', [0,0,0]); + set(hYrs, 'Color', [0,0,0]); + set(hZrs, 'Color', [0,0,0]); + set(hTitle,'Color',[0,0,0]); + end + %} + % Restore the figure's previous background color (if modified) + try set(fig,'Color',originalBgColor); drawnow; catch, end + % Fix colorspace to CMYK, if requested (workaround for issue #33) + if options.colourspace == 1 % CMYK + % Issue #33: due to internal bugs in Matlab's print() function, we can't use its -cmyk option + change_rgb_to_cmyk(tmp_nam); + end + % Add a bookmark to the PDF if desired + if options.bookmark + fig_nam = get(fig, 'Name'); + if isempty(fig_nam) && ~options.silent + warning('export_fig:EmptyBookmark', 'Bookmark requested for figure with no name. Bookmark will be empty.'); + end + add_bookmark(tmp_nam, fig_nam); + end + % Generate a pdf + eps2pdf(tmp_nam, pdf_nam_tmp, 1, options.append, options.colourspace==2, options.quality, options.gs_options); + % Ghostscript croaks on % chars in the output PDF file, so use tempname and then rename the file + try + % Rename the file (except if it is already the same) + % Abbie K's comment on the commit for issue #179 (#commitcomment-20173476) + if ~isequal(pdf_nam_tmp, pdf_nam) + movefile(pdf_nam_tmp, pdf_nam, 'f'); + end + catch + % Alert in case of error creating output PDF/EPS file (issue #179) + if existFile(pdf_nam_tmp) + fpath = fileparts(pdf_nam); + if ~isempty(fpath) && exist(fpath,'dir')==0 + errMsg = ['Could not create ' pdf_nam ' - folder "' fpath '" does not exist']; + else % output folder exists + errMsg = ['Could not create ' pdf_nam ' - perhaps you do not have write permissions, or the file is open in another application']; + end + error('export_fig:PDF:create',errMsg); + else + error('export_fig:NoEPS','Could not generate the intermediary EPS file.'); + end + end + catch ex + % Restore the figure's previous background color (in case it was not already restored) + try set(fig,'Color',originalBgColor); drawnow; catch, end + % Delete the temporary eps file - NOT! (Yair 3/3/2020) + %delete(tmp_nam); + % Rethrow the EPS/PDF-generation error + rethrow(ex); + end + % Delete the eps + delete(tmp_nam); + if options.eps || options.linecaps + try + % Generate an eps from the pdf + % since pdftops can't handle relative paths (e.g., '..\'), use a temp file + eps_nam_tmp = strrep(pdf_nam_tmp,'.pdf','.eps'); + pdf2eps(pdf_nam, eps_nam_tmp); + + % Issue #192: enable rounded line-caps + if options.linecaps + fstrm = read_write_entire_textfile(eps_nam_tmp); + fstrm = regexprep(fstrm, '[02] J', '1 J'); + read_write_entire_textfile(eps_nam_tmp, fstrm); + if options.pdf + eps2pdf(eps_nam_tmp, pdf_nam, 1, options.append, options.colourspace==2, options.quality, options.gs_options); + end + end + + if options.eps + movefile(eps_nam_tmp, [options.name '.eps'], 'f'); + else % if options.pdf + try delete(eps_nam_tmp); catch, end + end + catch ex + if ~options.pdf + % Delete the pdf + delete(pdf_nam); + end + try delete(eps_nam_tmp); catch, end + rethrow(ex); + end + if ~options.pdf + % Delete the pdf + delete(pdf_nam); + end + end + % Issue #206: warn if the figure contains an image + if ~isempty(hImages) && strcmpi(renderer,'-opengl') && ~options.silent % see addendum to issue #206 + warnMsg = ['exporting images to PDF/EPS may result in blurry images on some viewers. ' ... + 'If so, try to change viewer, or increase the image''s CData resolution, or use -opengl renderer, or export via the print function. ' ... + 'See ' hyperlink('https://github.com/altmany/export_fig/issues/206', 'issue #206') ' for details.']; + warning('export_fig:pdf_eps:blurry_image', warnMsg); + end + end + + % SVG format + if options.svg + filename = [options.name '.svg']; + % Adapted from Dan Joshea's https://github.com/djoshea/matlab-save-figure : + try %if ~verLessThan('matlab', '8.4') + % Try Matlab's built-in svg engine (from Batik Graphics2D for java) + set(fig,'Units','pixels'); % All data in the svg-file is saved in pixels + printArgs = {renderer}; + if ~isempty(options.resolution) + printArgs{end+1} = sprintf('-r%d', options.resolution); + end + try + print(fig, '-dsvg', printArgs{:}, filename); + catch + % built-in print() failed, try saveas() + % Note: saveas() currently just calls print(fig,filename,'-dsvg') + % so since print() failed, saveas() will probably also fail + saveas(fig, filename); + end + if ~options.silent + warning('export_fig:SVG:print', 'export_fig used Matlab''s built-in SVG output engine. Better results may be gotten via the fig2svg utility (https://github.com/kupiqu/fig2svg).'); + end + catch %else % built-in print()/saveas() failed - maybe an old Matlab release (no -dsvg) + % Try using the fig2svg/plot2svg utilities + try + try + fig2svg(filename, fig); %https://github.com/kupiqu/fig2svg + catch + plot2svg(filename, fig); %https://github.com/jschwizer99/plot2svg + if ~options.silent + warning('export_fig:SVG:plot2svg', 'export_fig used the plot2svg utility for SVG output. Better results may be gotten via the fig2svg utility (https://github.com/kupiqu/fig2svg).'); + end + end + catch err + filename = strrep(filename,'export_fig_out','filename'); + msg = ['SVG output is not supported for your figure: ' err.message '\n' ... + 'Try one of the following alternatives:\n' ... + ' 1. saveas(gcf,''' filename ''')\n' ... + ' 2. fig2svg utility: https://github.com/kupiqu/fig2svg\n' ... % Note: replaced defunct https://github.com/jschwizer99/plot2svg with up-to-date fork on https://github.com/kupiqu/fig2svg + ' 3. export_fig to EPS/PDF, then convert to SVG using non-Matlab tools\n']; + error('export_fig:SVG:error',msg); + end + end + % SVG output was successful if we reached this point + % Add warning about unsupported export_fig options with SVG output + if ~options.silent && (any(~isnan(options.crop_amounts)) || any(options.bb_padding)) + warning('export_fig:SVG:options', 'export_fig''s SVG output does not [currently] support cropping/padding.'); + end + + % Fix the generated SVG file, based on Cris Luengo's SVG_FIX_VIEWBOX: + % https://www.mathworks.com/matlabcentral/fileexchange/49617-svg_fix_viewbox-in_name-varargin + try + % Read SVG file + s = read_write_entire_textfile(filename); + % Fix fonts #1: 'SansSerif' doesn't work on my browser, the correct CSS is 'sans-serif' + s = regexprep(s,'font-family:SansSerif;|font-family:''SansSerif'';','font-family:''sans-serif'';'); + % Fix fonts #1: The document-wide default font is 'Dialog'. What is this anyway? + s = regexprep(s,'font-family:''Dialog'';','font-family:''sans-serif'';'); + % Replace 'width="xxx" height="yyy"' with 'width="100%" viewBox="0 0 xxx yyy"' + t = regexp(s,' 1e-6 + warning('export_fig:EMF:Magnify', 'export_fig -m option is ignored for EMF export.'); + end + if ~isequal(options.bb_padding,0) || ~isempty(options.quality) + warning('export_fig:EMF:Options', 'export_fig cropping, padding and quality options are ignored for EMF export.'); + end + if ~anythingChanged + warning('export_fig:EMF:print', 'For a figure without background transparency, export_fig uses Matlab''s built-in print(''-dmeta'') function without any extra processing, so try using it directly.'); + end + end + printArgs = {renderer}; + if ~isempty(options.resolution) + printArgs{end+1} = sprintf('-r%d', options.resolution); + end + filename = [options.name '.emf']; + print(fig, '-dmeta', printArgs{:}, filename); + catch err % built-in print() failed - maybe an old Matlab release (no -dsvg) + msg = ['EMF output is not supported: ' err.message '\n' ... + 'Try to use export_fig with other formats, such as PDF or EPS.\n']; + error('export_fig:EMF:error',msg); + end + end + + % Revert the figure or close it (if requested) + if cls || options.closeFig + % Close the created figure + close(fig); + else + % Reset the hardcopy mode + try set(fig, 'InvertHardcopy', old_mode); catch, end % fail silently in uifigures + % Reset the axes limit and tick modes + for a = 1:numel(Hlims) + try + set(Hlims(a), 'XLimMode', Xlims{a}, 'YLimMode', Ylims{a}, 'ZLimMode', Zlims{a},... + 'XTickMode', Xtick{a}, 'YTickMode', Ytick{a}, 'ZTickMode', Ztick{a},... + 'XTickLabelMode', Xlabel{a}, 'YTickLabelMode', Ylabel{a}, 'ZTickLabelMode', Zlabel{a}); + catch + % ignore - fix issue #4 (using HG2 on R2014a and earlier) + end + end + % Revert the tex-labels font weights + try set(texLabels, 'FontWeight','bold'); catch, end + % Revert annotation units + for handleIdx = 1 : numel(annotationHandles) + try + oldUnits = originalUnits{handleIdx}; + catch + oldUnits = originalUnits; + end + try set(annotationHandles(handleIdx),'Units',oldUnits); catch, end + end + % Revert figure properties in case they were changed + try set(fig, 'Units',oldFigUnits, 'Position',pos, 'Color',tcol_orig); catch, end + end + + % Output to clipboard (if requested) + if options.clipboard + % Delete the output file if unchanged from the default name ('export_fig_out.png') + if strcmpi(options.name,'export_fig_out') + try + fileInfo = dir('export_fig_out.png'); + if ~isempty(fileInfo) + timediff = now - fileInfo.datenum; + ONE_SEC = 1/24/60/60; + if timediff < ONE_SEC + delete('export_fig_out.png'); + end + end + catch + % never mind... + end + end + + % Use Java clipboard by default + if strcmpi(options.clipformat,'image') + % Save the image in the system clipboard + % credit: Jiro Doke's IMCLIPBOARD: http://www.mathworks.com/matlabcentral/fileexchange/28708-imclipboard + try + error(javachk('awt', 'export_fig -clipboard output')); + catch + if ~options.silent + warning('export_fig:clipboardJava', 'export_fig -clipboard output failed: requires Java to work'); + end + return; + end + try + % Import necessary Java classes + import java.awt.Toolkit %#ok + import java.awt.image.BufferedImage %#ok + import java.awt.datatransfer.DataFlavor %#ok + + % Get System Clipboard object (java.awt.Toolkit) + cb = Toolkit.getDefaultToolkit.getSystemClipboard(); + + % Add java class (ImageSelection) to the path + if ~exist('ImageSelection', 'class') + javaaddpath(fileparts(which(mfilename)), '-end'); + end + + % Get image size + ht = size(imageData, 1); + wd = size(imageData, 2); + + % Convert to Blue-Green-Red format + try + imageData2 = imageData(:, :, [3 2 1]); + catch + % Probably gray-scaled image (2D, without the 3rd [RGB] dimension) + imageData2 = imageData(:, :, [1 1 1]); + end + + % Convert to 3xWxH format + imageData2 = permute(imageData2, [3, 2, 1]); + + % Append Alpha data (unused - transparency is not supported in clipboard copy) + alphaData2 = uint8(permute(255*alpha,[3,2,1])); %=255*ones(1,wd,ht,'uint8') + imageData2 = cat(1, imageData2, alphaData2); + + % Create image buffer + imBuffer = BufferedImage(wd, ht, BufferedImage.TYPE_INT_RGB); + imBuffer.setRGB(0, 0, wd, ht, typecast(imageData2(:), 'int32'), 0, wd); + + % Create ImageSelection object from the image buffer + imSelection = ImageSelection(imBuffer); + + % Set clipboard content to the image + cb.setContents(imSelection, []); + catch + if ~options.silent + warning('export_fig:clipboardFailed', 'export_fig -clipboard output failed: %s', lasterr); %#ok + end + end + else % use one of print()'s builtin clipboard formats + % Remove background if requested (EMF format only) + if options.transparent && strcmpi(options.clipformat,'meta') + % Set figure bgcolor to none + originalBgColor = get(fig, 'Color'); + set(fig,'Color','none'); + + % Set axes bgcolor to none + hAxes = findall(fig, 'Type','axes'); + originalAxColor = get(hAxes, 'Color'); + set(hAxes,'Color','none'); + + drawnow; %repaint before export + end + + % Call print() to create the clipboard output + clipformat = ['-d' options.clipformat]; + printArgs = {renderer}; + if ~isempty(options.resolution) + printArgs{end+1} = sprintf('-r%d', options.resolution); + end + print(fig, '-clipboard', clipformat, printArgs{:}); + + % Restore the original background color + try set(fig, 'Color',originalBgColor); catch, end + try set(hAxes, 'Color',originalAxColor); catch, end + drawnow; + end + end + + % Don't output the data to console unless requested + if ~nargout + clear imageData alpha + end + catch err + % Revert figure properties in case they were changed + try set(fig,'Units',oldFigUnits, 'Position',pos, 'Color',tcol_orig); catch, end + % Display possible workarounds before the error message + if ~isempty(regexpi(err.message,'setopacityalpha')) %#ok + % Alert the user that transparency is not supported (issue #285) + try + [unused, msg] = ghostscript('-v'); %#ok + verStr = regexprep(msg, '.*hostscript ([\d.]+).*', '$1'); + if isempty(verStr) || any(verStr==' ') + verStr = ''; + else + verStr = [' (' verStr ')']; + end + catch + verStr = ''; + end + url = 'https://github.com/altmany/export_fig/issues/285#issuecomment-815008561'; + urlStr = hyperlink(url,'details'); + errMsg = sprintf('Transparancy is not supported by your export_fig (%s) and Ghostscript%s versions. \nInstall GS version 9.28 or earlier to use transparency (%s).', num2str(currentVersion), verStr, urlStr); + %fprintf(2,'%s\n',errMsg); + error('export_fig:setopacityalpha',errMsg) %#ok + elseif displaySuggestedWorkarounds && ~strcmpi(err.message,'export_fig error') + isNewerVersionAvailable = checkForNewerVersion(currentVersion); % alert if a newer version exists + if isempty(regexpi(err.message,'Ghostscript')) %#ok + fprintf(2, 'export_fig error. '); + end + fprintf(2, 'Please ensure:\n'); + fprintf(2, ' * that the function you used (%s.m) version %s is from the expected location\n', mfilename('fullpath'), num2str(currentVersion)); + paths = which(mfilename,'-all'); + if iscell(paths) && numel(paths) > 1 + fprintf(2, ' (you appear to have %s of export_fig installed)\n', hyperlink('matlab:which export_fig -all','multiple versions')); + end + if isNewerVersionAvailable + fprintf(2, ' * and that you are using the %s of export_fig (you are not: run %s to update it)\n', ... + hyperlink('https://github.com/altmany/export_fig/archive/master.zip','latest version'), ... + hyperlink('matlab:export_fig(''-update'')','export_fig(''-update'')')); + end + fprintf(2, ' * and that you did not made a mistake in export_fig''s %s\n', hyperlink('matlab:help export_fig','expected input arguments')); + if isvector(options) + if ismac + url = 'http://pages.uoregon.edu/koch'; + else + url = 'http://ghostscript.com'; + end + fpath = user_string('ghostscript'); + fprintf(2, ' * and that %s is properly installed in %s\n', ... + hyperlink(url,'ghostscript'), ... + hyperlink(['matlab:winopen(''' fileparts(fpath) ''')'], fpath)); + end + try + if options.eps + fpath = user_string('pdftops'); + fprintf(2, ' * and that %s is properly installed in %s\n', ... + hyperlink('http://xpdfreader.com/download.html','pdftops'), ... + hyperlink(['matlab:winopen(''' fileparts(fpath) ''')'], fpath)); + end + catch + % ignore - probably an error in parse_args + end + try + % Alert per issue #149 + if ~strncmpi(get(0,'Units'),'pixel',5) + fprintf(2, ' * or try to set groot''s Units property back to its default value of ''pixels'' (%s)\n', hyperlink('https://github.com/altmany/export_fig/issues/149','details')); + end + catch + % ignore - maybe an old MAtlab release + end + fprintf(2, '\nIf the problem persists, then please %s.\n', hyperlink('https://github.com/altmany/export_fig/issues','report a new issue')); + if existFile(tmp_nam) + fprintf(2, 'In your report, please upload the problematic EPS file: %s (you can then delete this file).\n', tmp_nam); + end + fprintf(2, '\n'); + end + rethrow(err) + end +end + +function options = default_options() + % Default options used by export_fig + options = struct(... + 'name', 'export_fig_out', ... + 'crop', true, ... + 'crop_amounts', nan(1,4), ... % auto-crop all 4 image sides + 'transparent', false, ... + 'renderer', 0, ... % 0: default, 1: OpenGL, 2: ZBuffer, 3: Painters + 'pdf', false, ... + 'eps', false, ... + 'emf', false, ... + 'svg', false, ... + 'png', false, ... + 'tif', false, ... + 'jpg', false, ... + 'bmp', false, ... + 'gif', false, ... + 'clipboard', false, ... + 'clipformat', 'image', ... + 'colourspace', 0, ... % 0: RGB/gray, 1: CMYK, 2: gray + 'append', false, ... + 'im', false, ... + 'alpha', false, ... + 'aa_factor', 0, ... + 'bb_padding', 0, ... + 'magnify', [], ... + 'resolution', [], ... + 'bookmark', false, ... + 'closeFig', false, ... + 'quality', [], ... + 'update', false, ... + 'version', false, ... + 'fontswap', true, ... + 'font_space', '', ... + 'linecaps', false, ... + 'invert_hardcopy', true, ... + 'format_options', struct, ... + 'preserve_size', false, ... + 'silent', false, ... + 'regexprep', [], ... + 'gs_options', {{}}); +end + +function [fig, options] = parse_args(nout, fig, argNames, varargin) + % Parse the input arguments + + % Convert strings => chars + varargin = cellfun(@str2char,varargin,'un',false); + + % Set the defaults + native = false; % Set resolution to native of an image + options = default_options(); + options.im = (nout == 1); % user requested imageData output + options.alpha = (nout == 2); % user requested alpha output + options.handleName = ''; % default handle name + + % Go through the other arguments + skipNext = 0; + for a = 1:nargin-3 % only process varargin, no other parse_args() arguments + if skipNext > 0 + skipNext = skipNext-1; + continue; + end + if all(ishandle(varargin{a})) + fig = varargin{a}; + options.handleName = argNames{a}; + elseif ischar(varargin{a}) && ~isempty(varargin{a}) + if varargin{a}(1) == '-' + switch lower(varargin{a}(2:end)) + case 'nocrop' + options.crop = false; + options.crop_amounts = [0,0,0,0]; + case {'trans', 'transparent'} + options.transparent = true; + case 'opengl' + options.renderer = 1; + case 'zbuffer' + options.renderer = 2; + case 'painters' + options.renderer = 3; + case 'pdf' + options.pdf = true; + case 'eps' + options.eps = true; + case {'emf','meta'} + options.emf = true; + case 'svg' + options.svg = true; + case 'png' + options.png = true; + case {'tif', 'tiff'} + options.tif = true; + case {'jpg', 'jpeg'} + options.jpg = true; + case 'bmp' + options.bmp = true; + case 'rgb' + options.colourspace = 0; + case 'cmyk' + options.colourspace = 1; + case {'gray', 'grey'} + options.colourspace = 2; + case {'a1', 'a2', 'a3', 'a4'} + options.aa_factor = str2double(varargin{a}(3)); + case 'append' + options.append = true; + case 'bookmark' + options.bookmark = true; + case 'native' + native = true; + case {'clipboard','clipboard:image'} + options.clipboard = true; + options.clipformat = 'image'; + options.im = true; %ensure that imageData is created + options.alpha = true; + case 'clipboard:bitmap' + options.clipboard = true; + options.clipformat = 'bitmap'; + case {'clipboard:emf','clipboard:meta'} + options.clipboard = true; + options.clipformat = 'meta'; + case 'clipboard:pdf' + options.clipboard = true; + options.clipformat = 'pdf'; + case 'update' + updateInstalledVersion(); + fig = -1; % silent bail-out + case 'version' + options.version = true; + return % ignore any additional args + case 'nofontswap' + options.fontswap = false; + case 'font_space' + options.font_space = varargin{a+1}; + skipNext = 1; + case 'linecaps' + options.linecaps = true; + case 'noinvert' + options.invert_hardcopy = false; + case 'preserve_size' + options.preserve_size = true; + case 'options' + % Issue #269: format-specific options + inputOptions = varargin{a+1}; + %options.format_options = inputOptions; + if isempty(inputOptions), continue, end + if iscell(inputOptions) + fields = inputOptions(1:2:end)'; + values = inputOptions(2:2:end)'; + options.format_options.all = cell2struct(values, fields); + elseif isstruct(inputOptions) + formats = fieldnames(inputOptions(1)); + for idx = 1 : numel(formats) + optionsStruct = inputOptions.(formats{idx}); + %optionsCells = [fieldnames(optionsStruct) struct2cell(optionsStruct)]'; + formatName = regexprep(lower(formats{idx}),{'tiff','jpeg'},{'tif','jpg'}); + options.format_options.(formatName) = optionsStruct; %=optionsCells(:)'; + end + else + warning('export_fig:options','export_fig -options argument is not in the expected format - ignored'); + end + skipNext = 1; + case 'silent' + options.silent = true; + case 'regexprep' + options.regexprep = varargin(a+1:a+2); + skipNext = 2; + otherwise + try + wasError = false; + if strcmpi(varargin{a}(1:2),'-d') + varargin{a}(2) = 'd'; % ensure lowercase 'd' + options.gs_options{end+1} = varargin{a}; + elseif strcmpi(varargin{a}(1:2),'-c') + if strncmpi(varargin{a},'-clipboard:',11) + wasError = true; + error('export_fig:BadOptionValue','option ''%s'' cannot be parsed: only image, bitmap, emf and pdf formats are supported',varargin{a}); + end + if numel(varargin{a})==2 + skipNext = 1; + vals = str2num(varargin{a+1}); %#ok + else + vals = str2num(varargin{a}(3:end)); %#ok + end + if numel(vals)~=4 + wasError = true; + error('export_fig:BadOptionValue','option -c cannot be parsed: must be a 4-element numeric vector'); + end + options.crop_amounts = vals; + options.crop = true; + else % scalar parameter value + val = str2double(regexp(varargin{a}, '(?<=-(m|M|r|R|q|Q|p|P))-?\d*.?\d+', 'match')); + if isempty(val) || isnan(val) + % Issue #51: improved processing of input args (accept space between param name & value) + val = str2double(varargin{a+1}); + if isscalar(val) && ~isnan(val) + skipNext = 1; + end + end + if ~isscalar(val) || isnan(val) + wasError = true; + error('export_fig:BadOptionValue','option %s is not recognised or cannot be parsed', varargin{a}); + end + switch lower(varargin{a}(2)) + case 'm' + % Magnification may never be negative + if val <= 0 + wasError = true; + error('export_fig:BadMagnification','Bad magnification value: %g (must be positive)', val); + end + options.magnify = val; + case 'r' + options.resolution = val; + case 'q' + options.quality = max(val, 0); + case 'p' + options.bb_padding = val; + end + end + catch err + % We might have reached here by raising an intentional error + if wasError % intentional raise + rethrow(err) + else % unintentional + error('export_fig:BadOption',['Unrecognized export_fig input option: ''' varargin{a} '''']); + end + end + end + else + [p, options.name, ext] = fileparts(varargin{a}); + if ~isempty(p) + % Issue #221: alert if the requested folder does not exist + if ~exist(p,'dir'), error('export_fig:BadPath','Folder %s does not exist!',p); end + options.name = [p filesep options.name]; + end + switch lower(ext) + case {'.tif', '.tiff'} + options.tif = true; + case {'.jpg', '.jpeg'} + options.jpg = true; + case '.png' + options.png = true; + case '.bmp' + options.bmp = true; + case '.eps' + options.eps = true; + case '.emf' + options.emf = true; + case '.pdf' + options.pdf = true; + case '.fig' + % If no open figure, then load the specified .fig file and continue + figFilename = varargin{a}; + if isempty(fig) + fig = openfig(figFilename,'invisible'); + varargin{a} = fig; + options.closeFig = true; + options.handleName = ['openfig(''' figFilename ''')']; + else + % save the current figure as the specified .fig file and exit + saveas(fig(1),figFilename); + fig = -1; + return + end + case '.svg' + options.svg = true; + case '.gif' + options.gif = true; + otherwise + options.name = varargin{a}; + end + end + end + end + + % Quick bail-out if no figure found + if isempty(fig), return; end + + % Do border padding with repsect to a cropped image + if options.bb_padding + options.crop = true; + end + + % Set default anti-aliasing now we know the renderer + try isAA = strcmp(get(ancestor(fig, 'figure'), 'GraphicsSmoothing'), 'on'); catch, isAA = false; end + if isAA + if options.aa_factor > 1 && ~options.silent + warning('export_fig:AntiAliasing','You requested anti-aliased export_fig output of a figure that is already anti-aliased - your -a option in export_fig is ignored.') + end + options.aa_factor = 1; % ignore -a option when the figure is already anti-aliased (HG2) + elseif options.aa_factor == 0 % default + %options.aa_factor = 1 + 2 * (~(using_hg2(fig) && isAA) | (options.renderer == 3)); + options.aa_factor = 1 + 2 * (~using_hg2(fig)); % =1 in HG2, =3 in HG1 + end + if options.aa_factor > 1 && ~isAA && using_hg2(fig) && ~options.silent + warning('export_fig:AntiAliasing','You requested anti-aliased export_fig output of an aliased figure (''GraphicsSmoothing''=''off''). You will see better results if you set your figure''s GraphicsSmoothing property to ''on'' before calling export_fig.') + end + + % Convert user dir '~' to full path + if numel(options.name) > 2 && options.name(1) == '~' && (options.name(2) == '/' || options.name(2) == '\') + options.name = fullfile(char(java.lang.System.getProperty('user.home')), options.name(2:end)); + end + + % Compute the magnification and resolution + if isempty(options.magnify) + if isempty(options.resolution) + options.magnify = 1; + options.resolution = 864; + else + options.magnify = options.resolution ./ get(0, 'ScreenPixelsPerInch'); + end + elseif isempty(options.resolution) + options.resolution = 864; + end + + % Set the format to PNG, if no other format was specified + if ~isvector(options) && ~isbitmap(options) && ~options.svg && ~options.emf + options.png = true; + end + + % Check whether transparent background is wanted (old way) + if isequal(get(ancestor(fig(1), 'figure'), 'Color'), 'none') + options.transparent = true; + end + + % If requested, set the resolution to the native vertical resolution of the + % first suitable image found + if native + if isbitmap(options) + % Find a suitable image + list = findall(fig, 'Type','image', 'Tag','export_fig_native'); + if isempty(list) + list = findall(fig, 'Type','image', 'Visible','on'); + end + for hIm = list(:)' + % Check height is >= 2 + height = size(get(hIm, 'CData'), 1); + if height < 2 + continue + end + % Account for the image filling only part of the axes, or vice versa + yl = get(hIm, 'YData'); + if isscalar(yl) + yl = [yl(1)-0.5 yl(1)+height+0.5]; + else + yl = [min(yl), max(yl)]; % fix issue #151 (case of yl containing more than 2 elements) + if ~diff(yl) + continue + end + yl = yl + [-0.5 0.5] * (diff(yl) / (height - 1)); + end + hAx = get(hIm, 'Parent'); + yl2 = get(hAx, 'YLim'); + % Find the pixel height of the axes + oldUnits = get(hAx, 'Units'); + set(hAx, 'Units', 'pixels'); + pos = get(hAx, 'Position'); + set(hAx, 'Units', oldUnits); + if ~pos(4) + continue + end + % Found a suitable image + % Account for stretch-to-fill being disabled + pbar = get(hAx, 'PlotBoxAspectRatio'); + pos = min(pos(4), pbar(2)*pos(3)/pbar(1)); + % Set the magnification to give native resolution + options.magnify = abs((height * diff(yl2)) / (pos * diff(yl))); % magnification must never be negative: issue #103 + break + end + elseif options.resolution == 864 % don't use -r864 in vector mode if user asked for -native + options.resolution = []; % issue #241 (internal Matlab bug produces black lines with -r864) + end + end +end + +% Convert a possible string => char (issue #245) +function value = str2char(value) + if isa(value,'string') + value = char(value); + end +end + +function A = downsize(A, factor) + % Downsample an image + if factor <= 1 || isempty(A) %issue #310 + % Nothing to do + return + end + try + % Faster, but requires image processing toolbox + A = imresize(A, 1/factor, 'bilinear'); + catch + % No image processing toolbox - resize manually + % Lowpass filter - use Gaussian as is separable, so faster + % Compute the 1d Gaussian filter + filt = (-factor-1:factor+1) / (factor * 0.6); + filt = exp(-filt .* filt); + % Normalize the filter + filt = single(filt / sum(filt)); + % Filter the image + padding = floor(numel(filt) / 2); + if padding < 1 || isempty(A), return, end %issue #310 + onesPad = ones(1, padding); + for a = 1:size(A,3) + A2 = single(A([onesPad 1:end repmat(end,1,padding)], ... + [onesPad 1:end repmat(end,1,padding)], a)); + A(:,:,a) = conv2(filt, filt', A2, 'valid'); + end + % Subsample + A = A(1+floor(mod(end-1, factor)/2):factor:end,1+floor(mod(end-1, factor)/2):factor:end,:); + end +end + +function A = rgb2grey(A) + A = cast(reshape(reshape(single(A), [], 3) * single([0.299; 0.587; 0.114]), size(A, 1), size(A, 2)), class(A)); % #ok +end + +function A = check_greyscale(A) + % Check if the image is greyscale + if size(A, 3) == 3 && ... + all(reshape(A(:,:,1) == A(:,:,2), [], 1)) && ... + all(reshape(A(:,:,2) == A(:,:,3), [], 1)) + A = A(:,:,1); % Save only one channel for 8-bit output + end +end + +function eps_remove_background(fname, count) + % Remove the background of an eps file + % Open the file + fh = fopen(fname, 'r+'); + if fh == -1 + error('export_fig:EPS:open','Cannot open file %s.', fname); + end + % Read the file line by line + while count + % Get the next line + l = fgets(fh); + if isequal(l, -1) + break; % Quit, no rectangle found + end + % Check if the line contains the background rectangle + if isequal(regexp(l, ' *0 +0 +\d+ +\d+ +r[fe] *[\n\r]+', 'start'), 1) + % Set the line to whitespace and quit + l(1:regexp(l, '[\n\r]', 'start', 'once')-1) = ' '; + fseek(fh, -numel(l), 0); + fprintf(fh, l); + % Reduce the count + count = count - 1; + end + end + % Close the file + fclose(fh); +end + +function b = isvector(options) % this only includes EPS-based vector formats (so not SVG,EMF) + b = options.pdf || options.eps; +end + +function b = isbitmap(options) + b = options.png || options.tif || options.jpg || options.bmp || ... + options.gif || options.im || options.alpha; +end + +function [A, tcol, alpha] = getFigImage(fig, magnify, renderer, options, pos) + if options.transparent + % MATLAB "feature": figure size can change when changing color in -nodisplay mode + % Note: figure background is set to off-white, not 'w', to handle common white elements (issue #330) + set(fig, 'Color',254/255*[1,1,1], 'Position',pos); + % repaint figure, otherwise Java screencapture will see black bgcolor + % Yair 19/12/21 - unnecessary: drawnow is called at top of print2array + %drawnow; + end + % Print large version to array + try + % The following code might cause out-of-memory errors + [A, tcol, alpha] = print2array(fig, magnify, renderer); + catch + % This is more conservative in memory, but perhaps kills transparency(?) + [A, tcol, alpha] = print2array(fig, magnify/options.aa_factor, renderer, 'retry'); + end + % In transparent mode, set the bgcolor to white + if options.transparent + % Note: tcol should already be [255,255,255] here, but just in case it's not... + tcol = uint8(254*[1,1,1]); %=off-white + end +end + +function A = make_cell(A) + if ~iscell(A) + A = {A}; + end +end + +function add_bookmark(fname, bookmark_text) + % Adds a bookmark to the temporary EPS file after %%EndPageSetup + % Read in the file + fh = fopen(fname, 'r'); + if fh == -1 + error('export_fig:bookmark:FileNotFound','File %s not found.', fname); + end + try + fstrm = fread(fh, '*char')'; + catch ex + fclose(fh); + rethrow(ex); + end + fclose(fh); + + % Include standard pdfmark prolog to maximize compatibility + fstrm = strrep(fstrm, '%%BeginProlog', sprintf('%%%%BeginProlog\n/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse')); + % Add page bookmark + fstrm = strrep(fstrm, '%%EndPageSetup', sprintf('%%%%EndPageSetup\n[ /Title (%s) /OUT pdfmark',bookmark_text)); + + % Write out the updated file + fh = fopen(fname, 'w'); + if fh == -1 + error('export_fig:bookmark:permission','Unable to open %s for writing.', fname); + end + try + fwrite(fh, fstrm, 'char*1'); + catch ex + fclose(fh); + rethrow(ex); + end + fclose(fh); +end + +function set_tick_mode(Hlims, ax) + % Set the tick mode of linear axes to manual + % Leave log axes alone as these are tricky + M = get(Hlims, [ax 'Scale']); + if ~iscell(M) + M = {M}; + end + %idx = cellfun(@(c) strcmp(c, 'linear'), M); + idx = find(strcmp(M,'linear')); + %set(Hlims(idx), [ax 'TickMode'], 'manual'); % issue #187 + %set(Hlims(idx), [ax 'TickLabelMode'], 'manual'); % this hides exponent label in HG2! + for idx2 = 1 : numel(idx) + try + % Fix for issue #187 - only set manual ticks when no exponent is present + hAxes = Hlims(idx(idx2)); + props = {[ax 'TickMode'],'manual', [ax 'TickLabelMode'],'manual'}; + tickVals = get(hAxes,[ax 'Tick']); + tickStrs = get(hAxes,[ax 'TickLabel']); + try % Fix issue #236 + exponents = [hAxes.([ax 'Axis']).SecondaryLabel]; + catch + exponents = [hAxes.([ax 'Ruler']).SecondaryLabel]; + end + if isempty([exponents.String]) + % Fix for issue #205 - only set manual ticks when the Ticks number match the TickLabels number + if numel(tickVals) == numel(tickStrs) + set(hAxes, props{:}); % no exponent and matching ticks, so update both ticks and tick labels to manual + end + end + catch % probably HG1 + % Fix for issue #220 - exponent is removed in HG1 when TickMode is 'manual' (internal Matlab bug) + if isequal(tickVals, str2num(tickStrs)') %#ok + set(hAxes, props{:}); % revert back to old behavior + end + end + end +end + +function change_rgb_to_cmyk(fname) % convert RGB => CMYK within an EPS file + % Do post-processing on the eps file + try + % Read the EPS file into memory + fstrm = read_write_entire_textfile(fname); + + % Replace all gray-scale colors + fstrm = regexprep(fstrm, '\n([\d.]+) +GC\n', '\n0 0 0 ${num2str(1-str2num($1))} CC\n'); + + % Replace all RGB colors + fstrm = regexprep(fstrm, '\n[0.]+ +[0.]+ +[0.]+ +RC\n', '\n0 0 0 1 CC\n'); % pure black + fstrm = regexprep(fstrm, '\n([\d.]+) +([\d.]+) +([\d.]+) +RC\n', '\n${sprintf(''%.4g '',[1-[str2num($1),str2num($2),str2num($3)]/max([str2num($1),str2num($2),str2num($3)]),1-max([str2num($1),str2num($2),str2num($3)])])} CC\n'); + + % Overwrite the file with the modified contents + read_write_entire_textfile(fname, fstrm); + catch + % never mind - leave as is... + end +end + +function [hBlackAxles, hBlackRulers] = fixBlackAxle(hAxes, axleName) + hBlackAxles = []; + hBlackRulers = []; + for idx = 1 : numel(hAxes) + ax = hAxes(idx); + axleColor = get(ax, axleName); + if isequal(axleColor,[0,0,0]) || isequal(axleColor,'k') + hBlackAxles(end+1) = ax; %#ok + try % Fix issue #306 - black yyaxis + if strcmpi(axleName,'Color'), continue, end %ruler, not axle + rulerName = strrep(axleName,'Color','Axis'); + hRulers = get(ax, rulerName); + newBlackRulers = fixBlackAxle(hRulers,'Color'); + hBlackRulers = [hBlackRulers newBlackRulers]; %#ok + catch + end + end + end + set(hBlackAxles, axleName, [0,0,0.01]); % off-black +end + +% Issue #269: format-specific options +function [optionsCells, bitDepth] = getFormatOptions(options, formatName) + bitDepth = []; + try + optionsStruct = options.format_options.(lower(formatName)); + catch + try + % Perhaps user specified the options in cell array format + optionsStruct = options.format_options.all; + catch + % User did not specify any extra parameters for this format + optionsCells = {}; + return + end + end + optionNames = fieldnames(optionsStruct); + optionVals = struct2cell(optionsStruct); + optionsCells = [optionNames, optionVals]'; + if nargout < 2, return, end % bail out if BitDepth is not required + try + idx = find(strcmpi(optionNames,'BitDepth'), 1, 'last'); + if ~isempty(idx) + bitDepth = optionVals{idx}; + end + catch + % never mind - ignore + end +end + +% Check for newer version (only once a day) +function isNewerVersionAvailable = checkForNewerVersion(currentVersion) + persistent lastCheckTime lastVersion + isNewerVersionAvailable = false; + if nargin < 1 || isempty(lastCheckTime) || now - lastCheckTime > 1 + url = 'https://raw.githubusercontent.com/altmany/export_fig/master/export_fig.m'; + try + str = readURL(url); + [unused,unused,unused,unused,latestVerStrs] = regexp(str, '\n[^:]+: \(([^)]+)\) ([^%]+)(?=\n)'); %#ok + latestVersion = str2double(latestVerStrs{end}{1}); + if nargin < 1 + currentVersion = lastVersion; + else + currentVersion = currentVersion + 1e3*eps; + end + isNewerVersionAvailable = latestVersion > currentVersion; + if isNewerVersionAvailable + try + verStrs = strtrim(reshape([latestVerStrs{:}],2,[])); + verNums = arrayfun(@(c)str2double(c{1}),verStrs(1,:)); + isValid = verNums > currentVersion; + versionDesc = strjoin(flip(verStrs(2,isValid)),';'); + catch + % Something bad happened - only display the latest version description + versionDesc = latestVerStrs{1}{2}; + end + try versionDesc = strjoin(strrep(strcat(' ***', strtrim(strsplit(versionDesc,';'))),'***','* '), char(10)); catch, end %#ok + msg = sprintf(['You are using version %.2f of export_fig. ' ... + 'A newer version (%g) is available, with the following improvements/fixes:\n' ... + '%s\n' ... + 'A change-log of recent releases is available here; the complete change-log is included at the top of the export_fig.m file.\n' ... % issue #322 + 'You can download the new version from GitHub or Matlab File Exchange, ' ... + 'or run export_fig(''-update'') to install it directly.' ... + ], currentVersion, latestVersion, versionDesc); + msg = hyperlink('https://github.com/altmany/export_fig', 'GitHub', msg); + msg = hyperlink('https://www.mathworks.com/matlabcentral/fileexchange/23629-export_fig', 'Matlab File Exchange', msg); + msg = hyperlink('matlab:export_fig(''-update'')', 'export_fig(''-update'')', msg); + msg = hyperlink('https://github.com/altmany/export_fig/releases', 'available here', msg); + msg = hyperlink('https://github.com/altmany/export_fig/blob/master/export_fig.m#L300', 'export_fig.m file', msg); + warning('export_fig:version',msg); + end + catch + % ignore + end + lastCheckTime = now; + lastVersion = currentVersion; + end +end + +% Update the installed version of export_fig from the latest version online +function updateInstalledVersion() + % Download the latest version of export_fig into the export_fig folder + zipFileName = 'https://github.com/altmany/export_fig/archive/master.zip'; + fprintf('Downloading latest version of %s from %s...\n', mfilename, zipFileName); + folderName = fileparts(which(mfilename('fullpath'))); + targetFileName = fullfile(folderName, datestr(now,'yyyy-mm-dd.zip')); + try + folder = hyperlink(['matlab:winopen(''' folderName ''')'], folderName); + catch % hyperlink.m is not properly installed + folder = folderName; + end + try + urlwrite(zipFileName,targetFileName); %#ok + catch err + error('export_fig:update:download','Error downloading %s into %s: %s\n',zipFileName,targetFileName,err.message); + end + + % Unzip the downloaded zip file in the export_fig folder + fprintf('Extracting %s...\n', targetFileName); + try + unzip(targetFileName,folderName); + % Fix issue #302 - zip file uses an internal folder export_fig-master + subFolder = fullfile(folderName,'export_fig-master'); + try movefile(fullfile(subFolder,'*.*'),folderName, 'f'); catch, end %All OSes + try movefile(fullfile(subFolder,'*'), folderName, 'f'); catch, end %MacOS/Unix + try movefile(fullfile(subFolder,'.*'), folderName, 'f'); catch, end %MacOS/Unix + try rmdir(subFolder); catch, end + catch err + error('export_fig:update:unzip','Error unzipping %s: %s\n',targetFileName,err.message); + end + + % Notify the user and rehash + fprintf('Successfully installed the latest %s version in %s\n', mfilename, folder); + clear functions %#ok + rehash +end + +% Read a file from the web +function str = readURL(url) + try + str = char(webread(url)); + catch err %if isempty(which('webread')) + if isempty(strfind(err.message,'404')) + v = version; % '9.6.0.1072779 (R2019a)' + if v(1) >= '8' % '8.0 (R2012b)' https://www.mathworks.com/help/matlab/release-notes.html?rntext=urlread&searchHighlight=urlread&startrelease=R2012b&endrelease=R2012b + str = urlread(url, 'Timeout',5); %#ok + else + str = urlread(url); %#ok % R2012a or older (no Timeout parameter) + end + else + rethrow(err) + end + end + if size(str,1) > 1 % ensure a row-wise string + str = str'; + end +end + +% Display a promo message in the Matlab console +function displayPromoMsg(msg, url) + %msg = [msg url]; + msg = strrep(msg,'<$>',url); + link = ['$0']); + %msg = regexprep(msg,{'consulting','training'},[link '/$0">$0']); + %warning('export_fig:promo',msg); + disp(['[' 8 msg ']' 8]); +end + +% Cross-check existance of other programs +function programsCrossCheck() + try + % IQ + hasTaskList = false; + if ispc && ~exist('IQML','file') + hasIQ = exist('C:/Progra~1/DTN/IQFeed','dir') || ... + exist('C:/Progra~2/DTN/IQFeed','dir'); + if ~hasIQ + [status,tasksStr] = system('tasklist'); %#ok + tasksStr = lower(tasksStr); + hasIQ = ~isempty(strfind(tasksStr,'iqconnect')) || ... + ~isempty(strfind(tasksStr,'iqlink')); %#ok + hasTaskList = true; + end + if hasIQ + displayPromoMsg('To connect Matlab to IQFeed, try the IQML connector <$>', 'https://UndocumentedMatlab.com/IQML'); + end + end + + % IB + if ~exist('IBMatlab','file') + hasIB = false; + possibleFolders = {'C:/Jts','C:/Programs/Jts','C:/Progra~1/Jts','C:/Progra~2/Jts','~/IBJts','~/IBJts/IBJts'}; + for folderIdx = 1 : length(possibleFolders) + if exist(possibleFolders{folderIdx},'dir') + hasIB = true; + break + end + end + if ~hasIB + if ~hasTaskList + if ispc % Windows + [status,tasksStr] = system('tasklist'); %#ok + else % Linux/MacOS + [status,tasksStr] = system('ps -e'); %#ok + end + tasksStr = lower(tasksStr); + end + hasIB = ~isempty(strfind(tasksStr,'tws')) || ... + ~isempty(strfind(tasksStr,'ibgateway')); %#ok + end + if hasIB + displayPromoMsg('To connect Matlab to IB try the IB-Matlab connector <$>', 'https://UndocumentedMatlab.com/IB-Matlab'); + end + end + catch + % never mind - ignore error + end +end + +% Hint to users to use exportgraphics/copygraphics in certain cases +function alertForExportOrCopygraphics(options) + %matlabVerNum = str2num(regexprep(version,'(\d+\.\d+).*','$1')); + try + % Bail out on R2019b- (copygraphics/exportgraphics not available/reliable) + if verLessThan('matlab','9.8') % 9.8 = R2020a + return + end + + isNoRendererSpecified = options.renderer == 0; + isPainters = options.renderer == 3; + noResolutionSpecified = isempty(options.resolution) || isequal(options.resolution,864); + + % First check for copygraphics compatibility (export to clipboard) + params = ','; + if options.clipboard + if options.transparent % -transparent was requested + if isPainters || isNoRendererSpecified % painters or default renderer + if noResolutionSpecified + params = '''BackgroundColor'',''none'',''ContentType'',''vector'','; + else % exception: no message + params = ','; + end + else % opengl/zbuffer renderer + if options.invert_hardcopy % default + params = '''BackgroundColor'',''white'','; + else % -noinvert was requested + params = '''BackgroundColor'',''current'','; % 'none' is 'white' when ContentType='image' + end + params = [params '''ContentType'',''image'',']; + if ~noResolutionSpecified + params = [params '''Resolution'',' num2str(options.resolution) ',']; + else + % don't add a resolution param + end + end + else % no -transparent + if options.invert_hardcopy % default + params = '''BackgroundColor'',''white'','; + else % -noinvert was requested + params = '''BackgroundColor'',''current'','; + end + if isPainters % painters (but not default!) renderer + if noResolutionSpecified + params = [params '''ContentType'',''vector'',']; + else % exception: no message + params = ','; + end + else % opengl/zbuffer/default renderer + params = [params '''ContentType'',''image'',']; + if ~noResolutionSpecified + params = [params '''Resolution'',' num2str(options.resolution) ',']; + else + % don't add a resolution param + end + end + end + + % If non-RGB colorspace was requested on R2021a+ + if ~verLessThan('matlab','9.10') % 9.10 = R2021a + if options.colourspace == 2 % gray + params = [params '''Colorspace'',''gray'',']; + end + end + end + displayMsg(params, 'copygraphics', 'clipboard', ''); + + % Next check for exportgraphics compatibility (export to file) + % Note: not , since -clipboard can be combined with file export + params = ','; + if ~options.clipboard + if options.transparent % -transparent was requested + if isvector(options) % vector output + if isPainters || isNoRendererSpecified % painters or default renderer + if noResolutionSpecified + params = '''BackgroundColor'',''none'',''ContentType'',''vector'','; + else % exception: no message + params = ','; + end + else % opengl/zbuffer renderer + params = '''BackgroundColor'',''none'',''ContentType'',''vector'','; + end + else % non-vector output + params = ','; + end + else % no -transparent + if options.invert_hardcopy % default + params = '''BackgroundColor'',''white'','; + else % -noinvert was requested + params = '''BackgroundColor'',''current'','; + end + if isvector(options) % vector output + if isPainters || isNoRendererSpecified % painters or default renderer + if noResolutionSpecified + params = [params '''ContentType'',''vector'',']; + else % exception: no message + params = ','; + end + else % opengl/zbuffer renderer + if noResolutionSpecified + params = [params '''ContentType'',''image'',']; + else % exception: no message + params = ','; + end + end + else % non-vector output + if isPainters % painters (but not default!) renderer + % exception: no message + params = ','; + else % opengl/zbuffer/default renderer + if ~noResolutionSpecified + params = [params '''Resolution'',' num2str(options.resolution) ',']; + end + end + end + end + + % If non-RGB colorspace was requested on R2021a+ + if ~verLessThan('matlab','9.10') % 9.10 = R2021a + if options.colourspace == 2 % gray + params = [params '''Colorspace'',''gray'',']; + elseif options.colourspace == 1 && options.eps % cmyk (eps only) + params = [params '''Colorspace'',''cmyk'',']; + end + end + end + filenameParam = 'filename,'; %=[options.name ',']; + displayMsg(params, 'exportgraphics', 'file', filenameParam); + catch + % Ignore errors - do not stop export_fig processing + end + + % Utility function to display an alert message + function displayMsg(params, funcName, type, filenameParam) + if length(params) > 1 + % strip default param values from the message + params = strrep(params, '''BackgroundColor'',''white'',', ''); + % strip the trailing , + if ~isempty(params) && params(end)==',', params(end)=''; end + % if this message was not already displayed + try prevParams = getpref('export_fig',funcName); catch, prevParams = ''; end + if ~strcmpi(params, prevParams) + % display the message (TODO: perhaps replace warning() with fprintf()?) + if ~isempty([filenameParam params]) + filenameParam = [',' filenameParam]; + end + if ~isempty(filenameParam) && filenameParam(end)==',' && isempty(params) + filenameParam(end) = ''; + end + handleName = options.handleName; + if isempty(options.handleName) % handle was either not specified, or via gca()/gcf() etc. [i.e. not by variable] + handleName = 'hFigure'; + end + msg = ['In Matlab R2020a+ you can also use ' funcName '(' handleName filenameParam params ') for simple ' type ' export']; + oldWarn = warning('on','verbose'); + warning(['export_fig:' funcName], msg); + warning(oldWarn); + setpref('export_fig',funcName,params); + end + end + end +end + +% Does a file exist? +function flag = existFile(filename) + try + % isfile() is faster than exist(), but does not report files on path + flag = isfile(filename); + catch + flag = exist(filename,'file') ~= 0; + end +end \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/fix_lines.m b/matlab/C2xyz_v2/export_fig/fix_lines.m new file mode 100644 index 0000000..b160fd8 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/fix_lines.m @@ -0,0 +1,151 @@ +%FIX_LINES Improves the line style of eps files generated by print +% +% Examples: +% fix_lines fname +% fix_lines fname fname2 +% fstrm_out = fixlines(fstrm_in) +% +% This function improves the style of lines in eps files generated by +% MATLAB's print function, making them more similar to those seen on +% screen. Grid lines are also changed from a dashed style to a dotted +% style, for greater differentiation from dashed lines. +% +% The function also places embedded fonts after the postscript header, in +% versions of MATLAB which place the fonts first (R2006b and earlier), in +% order to allow programs such as Ghostscript to find the bounding box +% information. +% +%IN: +% fname - Name or path of source eps file. +% fname2 - Name or path of destination eps file. Default: same as fname. +% fstrm_in - File contents of a MATLAB-generated eps file. +% +%OUT: +% fstrm_out - Contents of the eps file with line styles fixed. + +% Copyright: (C) Oliver Woodford, 2008-2014 + +% The idea of editing the EPS file to change line styles comes from Jiro +% Doke's FIXPSLINESTYLE (fex id: 17928) +% The idea of changing dash length with line width came from comments on +% fex id: 5743, but the implementation is mine :) + +% Thank you to Sylvain Favrot for bringing the embedded font/bounding box +% interaction in older versions of MATLAB to my attention. +% Thank you to D Ko for bringing an error with eps files with tiff previews +% to my attention. +% Thank you to Laurence K for suggesting the check to see if the file was +% opened. + +% 01/03/15: Issue #20: warn users if using this function in HG2 (R2014b+) +% 27/03/15: Fixed out of memory issue with enormous EPS files (generated by print() with OpenGL renderer), related to issue #39 + +function fstrm = fix_lines(fstrm, fname2) + +% Issue #20: warn users if using this function in HG2 (R2014b+) +if using_hg2 + warning('export_fig:hg2','The fix_lines function should not be used in this Matlab version.'); +end + +if nargout == 0 || nargin > 1 + if nargin < 2 + % Overwrite the input file + fname2 = fstrm; + end + % Read in the file + fstrm = read_write_entire_textfile(fstrm); +end + +% Move any embedded fonts after the postscript header +if strcmp(fstrm(1:15), '%!PS-AdobeFont-') + % Find the start and end of the header + ind = regexp(fstrm, '[\n\r]%!PS-Adobe-'); + [ind2, ind2] = regexp(fstrm, '[\n\r]%%EndComments[\n\r]+'); + % Put the header first + if ~isempty(ind) && ~isempty(ind2) && ind(1) < ind2(1) + fstrm = fstrm([ind(1)+1:ind2(1) 1:ind(1) ind2(1)+1:end]); + end +end + +% Make sure all line width commands come before the line style definitions, +% so that dash lengths can be based on the correct widths +% Find all line style sections +ind = [regexp(fstrm, '[\n\r]SO[\n\r]'),... % This needs to be here even though it doesn't have dots/dashes! + regexp(fstrm, '[\n\r]DO[\n\r]'),... + regexp(fstrm, '[\n\r]DA[\n\r]'),... + regexp(fstrm, '[\n\r]DD[\n\r]')]; +ind = sort(ind); +% Find line width commands +[ind2, ind3] = regexp(fstrm, '[\n\r]\d* w[\n\r]'); +% Go through each line style section and swap with any line width commands +% near by +b = 1; +m = numel(ind); +n = numel(ind2); +for a = 1:m + % Go forwards width commands until we pass the current line style + while b <= n && ind2(b) < ind(a) + b = b + 1; + end + if b > n + % No more width commands + break; + end + % Check we haven't gone past another line style (including SO!) + if a < m && ind2(b) > ind(a+1) + continue; + end + % Are the commands close enough to be confident we can swap them? + if (ind2(b) - ind(a)) > 8 + continue; + end + % Move the line style command below the line width command + fstrm(ind(a)+1:ind3(b)) = [fstrm(ind(a)+4:ind3(b)) fstrm(ind(a)+1:ind(a)+3)]; + b = b + 1; +end + +% Find any grid line definitions and change to GR format +% Find the DO sections again as they may have moved +ind = int32(regexp(fstrm, '[\n\r]DO[\n\r]')); +if ~isempty(ind) + % Find all occurrences of what are believed to be axes and grid lines + ind2 = int32(regexp(fstrm, '[\n\r] *\d* *\d* *mt *\d* *\d* *L[\n\r]')); + if ~isempty(ind2) + % Now see which DO sections come just before axes and grid lines + ind2 = repmat(ind2', [1 numel(ind)]) - repmat(ind, [numel(ind2) 1]); + ind2 = any(ind2 > 0 & ind2 < 12); % 12 chars seems about right + ind = ind(ind2); + % Change any regions we believe to be grid lines to GR + fstrm(ind+1) = 'G'; + fstrm(ind+2) = 'R'; + end +end + +% Define the new styles, including the new GR format +% Dot and dash lengths have two parts: a constant amount plus a line width +% variable amount. The constant amount comes after dpi2point, and the +% variable amount comes after currentlinewidth. If you want to change +% dot/dash lengths for a one particular line style only, edit the numbers +% in the /DO (dotted lines), /DA (dashed lines), /DD (dot dash lines) and +% /GR (grid lines) lines for the style you want to change. +new_style = {'/dom { dpi2point 1 currentlinewidth 0.08 mul add mul mul } bdef',... % Dot length macro based on line width + '/dam { dpi2point 2 currentlinewidth 0.04 mul add mul mul } bdef',... % Dash length macro based on line width + '/SO { [] 0 setdash 0 setlinecap } bdef',... % Solid lines + '/DO { [1 dom 1.2 dom] 0 setdash 0 setlinecap } bdef',... % Dotted lines + '/DA { [4 dam 1.5 dam] 0 setdash 0 setlinecap } bdef',... % Dashed lines + '/DD { [1 dom 1.2 dom 4 dam 1.2 dom] 0 setdash 0 setlinecap } bdef',... % Dot dash lines + '/GR { [0 dpi2point mul 4 dpi2point mul] 0 setdash 1 setlinecap } bdef'}; % Grid lines - dot spacing remains constant + +% Construct the output +% This is the original (memory-intensive) code: +%first_sec = strfind(fstrm, '% line types:'); % Isolate line style definition section +%[second_sec, remaining] = strtok(fstrm(first_sec+1:end), '/'); +%[remaining, remaining] = strtok(remaining, '%'); +%fstrm = [fstrm(1:first_sec) second_sec sprintf('%s\r', new_style{:}) remaining]; +fstrm = regexprep(fstrm,'(% line types:.+?)/.+?%',['$1',sprintf('%s\r',new_style{:}),'%']); + +% Write the output file +if nargout == 0 || nargin > 1 + read_write_entire_textfile(fname2, fstrm); +end +end diff --git a/matlab/C2xyz_v2/export_fig/ghostscript.m b/matlab/C2xyz_v2/export_fig/ghostscript.m new file mode 100644 index 0000000..d0200a7 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/ghostscript.m @@ -0,0 +1,208 @@ +function varargout = ghostscript(cmd) +%GHOSTSCRIPT Calls a local GhostScript executable with the input command +% +% Example: +% [status result] = ghostscript(cmd) +% +% Attempts to locate a ghostscript executable, finally asking the user to +% specify the directory ghostcript was installed into. The resulting path +% is stored for future reference. +% +% Once found, the executable is called with the input command string. +% +% This function requires a Ghostscript installation on your system. +% You can download Ghostscript from http://ghostscript.com (Windows/Linux) +% or http://pages.uoregon.edu/koch (MacOS). +% +% IN: +% cmd - Command string to be passed into ghostscript. +% +% OUT: +% status - 0 iff command ran without problem. +% result - Output from ghostscript. + +% Copyright: Oliver Woodford, 2009-2015, Yair Altman 2015- +%{ +% Thanks to Jonas Dorn for the fix for the title of the uigetdir window on Mac OS. +% Thanks to Nathan Childress for the fix to default location on 64-bit Windows systems. +% 27/04/11 - Find 64-bit Ghostscript on Windows. Thanks to Paul Durack and +% Shaun Kline for pointing out the issue +% 04/05/11 - Thanks to David Chorlian for pointing out an alternative +% location for gs on linux. +% 12/12/12 - Add extra executable name on Windows. Thanks to Ratish +% Punnoose for highlighting the issue. +% 28/06/13 - Fix error using GS 9.07 in Linux. Many thanks to Jannick +% Steinbring for proposing the fix. +% 24/10/13 - Fix error using GS 9.07 in Linux. Many thanks to Johannes +% for the fix. +% 23/01/14 - Add full path to ghostscript.txt in warning. Thanks to Koen +% Vermeer for raising the issue. +% 27/02/15 - If Ghostscript croaks, display suggested workarounds +% 30/03/15 - Improved performance by caching status of GS path check, if ok +% 14/05/15 - Clarified warning message in case GS path could not be saved +% 29/05/15 - Avoid cryptic error in case the ghostscipt path cannot be saved (issue #74) +% 10/11/15 - Custom GS installation webpage for MacOS. Thanks to Andy Hueni via FEX +% 15/01/20 - Various message cleanups/fixes in case of errors +%} + + try + % Call ghostscript + [varargout{1:nargout}] = system([gs_command(gs_path()) cmd]); + catch err + % Display possible workarounds for Ghostscript croaks + url1 = 'https://github.com/altmany/export_fig/issues/12#issuecomment-61467998'; % issue #12 + url2 = 'https://github.com/altmany/export_fig/issues/20#issuecomment-63826270'; % issue #20 + hg2_str = ''; if using_hg2, hg2_str = ' or Matlab R2014a'; end + fprintf(2, 'Ghostscript error. Rolling back to GS 9.10%s may possibly solve this:\n * %s ', hg2_str, hyperlink(url1)); + if using_hg2 + fprintf(2, '(GS 9.10)\n * %s (R2014a)', hyperlink(url2)); + end + fprintf('\n\n'); + if ismac || isunix + url3 = 'https://github.com/altmany/export_fig/issues/27'; % issue #27 + fprintf(2, 'Alternatively, this may possibly be due to a font path issue:\n * %s\n\n', hyperlink(url3)); + % issue #20 + % TODO: in Unix/Mac, find a way to automatically determine whether to use "export" (bash) or "setenv" (csh/tcsh) + if isdeployed + url = [mfilename '.m']; + else + fpath = which(mfilename); + if isempty(fpath), fpath = [mfilename('fullpath') '.m']; end + url = ['' fpath '']; + end + fprintf(2, 'Alternatively, if you are using csh, modify shell_cmd from "export ..." to "setenv ..."\nat the bottom of %s\n\n', url); + end + rethrow(err); + end +end + +function path_ = gs_path + % Return a valid path + % Start with the currently set path + path_ = user_string('ghostscript'); + % Check the path works + if check_gs_path(path_) + return + end + % Check whether the binary is on the path + if ispc + bin = {'gswin32c.exe', 'gswin64c.exe', 'gs'}; + else + bin = {'gs'}; + end + for a = 1:numel(bin) + path_ = bin{a}; + if check_store_gs_path(path_) + return + end + end + % Search the obvious places + if ispc + default_location = 'C:\Program Files\gs\'; + dir_list = dir(default_location); + if isempty(dir_list) + default_location = 'C:\Program Files (x86)\gs\'; % Possible location on 64-bit systems + dir_list = dir(default_location); + end + executable = {'\bin\gswin32c.exe', '\bin\gswin64c.exe'}; + ver_num = 0; + % If there are multiple versions, use the newest + for a = 1:numel(dir_list) + ver_num2 = sscanf(dir_list(a).name, 'gs%g'); + if ~isempty(ver_num2) && ver_num2 > ver_num + for b = 1:numel(executable) + path2 = [default_location dir_list(a).name executable{b}]; + if exist(path2, 'file') == 2 + path_ = path2; + ver_num = ver_num2; + end + end + end + end + if check_store_gs_path(path_) + return + end + else + executable = {'/usr/bin/gs', '/usr/local/bin/gs'}; + for a = 1:numel(executable) + path_ = executable{a}; + if check_store_gs_path(path_) + return + end + end + end + % Ask the user to enter the path + while true + if strncmp(computer, 'MAC', 3) % Is a Mac + % Give separate warning as the uigetdir dialogue box doesn't have a + % title on MacOS + uiwait(warndlg('Ghostscript installation not found - please locate the program.', 'Ghostscript')) + base = uigetdir('/', 'Ghostcript program location'); + else + base = uigetdir('/', 'Ghostcript program not found - please locate it'); + end + if isequal(base, 0) + % User hit cancel or closed window + break; + end + base = [base filesep]; %#ok + bin_dir = {'', ['bin' filesep], ['lib' filesep]}; + for a = 1:numel(bin_dir) + for b = 1:numel(bin) + path_ = [base bin_dir{a} bin{b}]; + if exist(path_, 'file') == 2 + if check_store_gs_path(path_) + return + end + end + end + end + end + if ismac + url = 'http://pages.uoregon.edu/koch'; + else + url = 'http://ghostscript.com'; + end + error('Ghostscript:NotFound', 'Ghostscript not found. Have you installed it from %s ?', hyperlink(url)); +end + +function good = check_store_gs_path(path_) + % Check the path is valid + good = check_gs_path(path_); + if ~good + return + end + % Update the current default path to the path found + if ~user_string('ghostscript', path_) + %filename = fullfile(fileparts(which('user_string.m')), '.ignore', 'ghostscript.txt'); + [unused, filename] = user_string('ghostscript'); %#ok + warning('Ghostscript:path', 'Path to ghostscript installation could not be saved in %s (perhaps a permissions issue). You can manually create this file and set its contents to %s, to improve performance in future invocations (this warning is safe to ignore).', filename, path_); + return + end +end + +function good = check_gs_path(path_) + persistent isOk + if isempty(path_) + isOk = false; + elseif ~isequal(isOk,true) + % Check whether the path is valid + [status, message] = system([gs_command(path_) '-h']); %#ok + isOk = status == 0; + end + good = isOk; +end + +function cmd = gs_command(path_) + % Initialize any required system calls before calling ghostscript + % TODO: in Unix/Mac, find a way to automatically determine whether to use "export" (bash) or "setenv" (csh/tcsh) + shell_cmd = ''; + if isunix + shell_cmd = 'export LD_LIBRARY_PATH=""; '; % Avoids an error on Linux with GS 9.07 + end + if ismac + shell_cmd = 'export DYLD_LIBRARY_PATH=""; '; % Avoids an error on Mac with GS 9.07 + end + % Construct the command string + cmd = sprintf('%s"%s" ', shell_cmd, path_); +end diff --git a/matlab/C2xyz_v2/export_fig/hyperlink.m b/matlab/C2xyz_v2/export_fig/hyperlink.m new file mode 100644 index 0000000..c89fa3d --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/hyperlink.m @@ -0,0 +1,53 @@ +function str = hyperlink(url, label, msg) +%HYPERLINK create a string that is displayable as hyperlink in Matlab console +% +% Usage examples: +% fprintf('Search on %s\n', hyperlink('http://google.com','Google')); +% fprintf(hyperlink('http://google.com','Google','Search on Google\n')); +% +% HYPERLINK converts the specified URL and text label into a string that is +% displayed as a hyperlink in the Matlab console (Command Window). +% In a deployed (compiled) program, the URL and text label (if different +% from the URL) are displayed in a non-hyperlinked plain-text manner. +% If the optional 3rd input argument (msg) is specified, then all instances of +% the specified label within msg will be handled as above (hyperlinked etc.) +% +% IN: +% url - (mandatory) URL of webpage or Matlab command (e.g., 'matlab:which(...') +% label - (optional) text label of the hyperlink. Default: url +% msg - (optional) string in which all label instances should be hyperlinked +% +% OUT: +% str - string output + +% Copyright: Yair Altman 2020- +%{ +% 15/01/20 - Initial version +%} + + error(nargchk(1,3,nargin)); %#ok narginchk is only available in R2011b+ + if nargin > 2 % msg was specified + % replace all instances of label within msg with corresponding hyperlink + str = strrep(msg, label, hyperlink(url,label)); + return + end + if nargin < 2, label = url; end + isWebpage = strncmpi(url,'http',4); + + % Only hyperlink in interactive Matlab sessions, not in a deployed program + if ~isdeployed % interactive Matlab session + if isWebpage % open in a web browser + str = ['' label '']; + else % Matlab command e.g. 'matlab:which(...' + str = ['' label '']; + end + else % deployed (compiled) + if isWebpage && ~strcmp(label,url) % display label next to url + str = [label ' (' url ')']; + elseif isWebpage % text==url - display only the url + str = url; + else % Matlab command (not a webpage) - just display the label + str = label; + end + end +end diff --git a/matlab/C2xyz_v2/export_fig/im2gif.m b/matlab/C2xyz_v2/export_fig/im2gif.m new file mode 100644 index 0000000..4c0ff3d --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/im2gif.m @@ -0,0 +1,205 @@ +%IM2GIF Convert a multiframe image to an animated GIF file +% +% Examples: +% im2gif infile +% im2gif infile outfile +% im2gif(A, outfile) +% im2gif(..., '-nocrop') +% im2gif(..., '-nodither') +% im2gif(..., '-ncolors', n) +% im2gif(..., '-loops', n) +% im2gif(..., '-delay', n) +% +% This function converts a multiframe image to an animated GIF. +% +% To create an animation from a series of figures, export to a multiframe +% TIFF file using export_fig, then convert to a GIF, as follows: +% +% for a = 2 .^ (3:6) +% peaks(a); +% export_fig test.tif -nocrop -append +% end +% im2gif('test.tif', '-delay', 0.5); +% +%IN: +% infile - string containing the name of the input image. +% outfile - string containing the name of the output image (must have the +% .gif extension). Default: infile, with .gif extension. +% A - HxWxCxN array of input images, stacked along fourth dimension, to +% be converted to gif. +% -nocrop - option indicating that the borders of the output are not to +% be cropped. +% -nodither - option indicating that dithering is not to be used when +% converting the image. +% -ncolors - option pair, the value of which indicates the maximum number +% of colors the GIF can have. This can also be a quantization +% tolerance, between 0 and 1. Default/maximum: 256. +% -loops - option pair, the value of which gives the number of times the +% animation is to be looped. Default: 65535. +% -delay - option pair, the value of which gives the time, in seconds, +% between frames. Default: 1/15. + +% Copyright (C) Oliver Woodford 2011 + +%{ +% 14/02/18: Merged issue #235: reduced memory usage, improved performance (thanks to @numb7rs) +% 30/11/19: Merged issue #288: Fix im2gif.m for greyscale TIFF images (thanks @Blackbelt1221) +%} + +function im2gif(A, varargin) + + % Parse the input arguments + [A, options] = parse_args(A, varargin{:}); + + if options.crop ~= 0 + % Crop + A = crop_borders(A, A(ceil(end/2),1,:,1)); + end + + % Convert to indexed image + [h, w, c, n] = size(A); + + % Issue #235: Using unique(A,'rows') on the whole image stack at once causes + % massive memory usage when dealing with large images (at least on Matlab 2017b). + % Running unique(...) on individual frames, then again on the results drastically + % reduces the memory usage & slightly improves the execution time (@numb7rs). + uns = cell(1,size(A,4)); + for nn=1:size(A,4) + uns{nn}=unique(reshape(A(:,:,:,nn), h*w, c),'rows'); + end + map=unique(cell2mat(uns'),'rows'); + + A = reshape(permute(A, [1 2 4 3]), h, w*n, c); + + if size(map, 1) > 256 + dither_str = {'dither', 'nodither'}; + dither_str = dither_str{1+(options.dither==0)}; + if options.ncolors <= 1 + [B, map] = rgb2ind(A, options.ncolors, dither_str); + if size(map, 1) > 256 + [B, map] = rgb2ind(A, 256, dither_str); + end + else + [B, map] = rgb2ind(A, min(round(options.ncolors), 256), dither_str); + end + else + if max(map(:)) > 1 + map = double(map) / 255; + A = double(A) / 255; + end + B = rgb2ind(im2double(A), map); + end + B = reshape(B, h, w, 1, n); + + % Bug fix to rgb2ind + map(B(1)+1,:) = im2double(A(1,1,:)); + + % Save as a gif + imwrite(B, map, options.outfile, 'LoopCount', round(options.loops(1)), 'DelayTime', options.delay); +end + +%% Parse the input arguments +function [A, options] = parse_args(A, varargin) + % Set the defaults + options = struct('outfile', '', ... + 'dither', true, ... + 'crop', true, ... + 'ncolors', 256, ... + 'loops', 65535, ... + 'delay', 1/15); + + % Go through the arguments + a = 0; + n = numel(varargin); + while a < n + a = a + 1; + if ischar(varargin{a}) && ~isempty(varargin{a}) + if varargin{a}(1) == '-' + opt = lower(varargin{a}(2:end)); + switch opt + case 'nocrop' + options.crop = false; + case 'nodither' + options.dither = false; + otherwise + if ~isfield(options, opt) + error('Option %s not recognized', varargin{a}); + end + a = a + 1; + if ischar(varargin{a}) && ~ischar(options.(opt)) + options.(opt) = str2double(varargin{a}); + else + options.(opt) = varargin{a}; + end + end + else + options.outfile = varargin{a}; + end + end + end + + if isempty(options.outfile) + if ~ischar(A) + error('No output filename given.'); + end + % Generate the output filename from the input filename + [path, outfile] = fileparts(A); + options.outfile = fullfile(path, [outfile '.gif']); + end + + if ischar(A) + % Read in the image + A = imread_rgb(A); + end +end + +%% Read image to uint8 rgb array +function [A, alpha] = imread_rgb(name) + % Get file info + info = imfinfo(name); + % Special case formats + switch lower(info(1).Format) + case 'gif' + [A, map] = imread(name, 'frames', 'all'); + if ~isempty(map) + map = uint8(map * 256 - 0.5); % Convert to uint8 for storage + A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0 + A = permute(A, [1 2 5 4 3]); + end + case {'tif', 'tiff'} + A = cell(numel(info), 1); + for a = 1:numel(A) + [A{a}, map] = imread(name, 'Index', a, 'Info', info); + if ~isempty(map) + map = uint8(map * 256 - 0.5); % Convert to uint8 for storage + A{a} = reshape(map(uint32(A{a})+1,:), [size(A) size(map, 2)]); % Assume indexed from 0 + end + if size(A{a}, 3) == 4 + % TIFF in CMYK colourspace - convert to RGB + if isfloat(A{a}) + A{a} = A{a} * 255; + else + A{a} = single(A{a}); + end + A{a} = 255 - A{a}; + A{a}(:,:,4) = A{a}(:,:,4) / 255; + A{a} = uint8(A(:,:,1:3) .* A{a}(:,:,[4 4 4])); + elseif size(A{a}, 3) < 3 %Check whether TIFF has been read in as greyscale + %Convert from greyscale to RGB colorspace (issue #288) + A{a} = cat(3, A{a}, A{a}, A{a}); + end + end + A = cat(4, A{:}); + otherwise + [A, map, alpha] = imread(name); + A = A(:,:,:,1); % Keep only first frame of multi-frame files + if ~isempty(map) + map = uint8(map * 256 - 0.5); % Convert to uint8 for storage + A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0 + elseif size(A, 3) == 4 + % Assume 4th channel is an alpha matte + alpha = A(:,:,4); + A = A(:,:,1:3); + end + end +end diff --git a/matlab/C2xyz_v2/export_fig/isolate_axes.m b/matlab/C2xyz_v2/export_fig/isolate_axes.m new file mode 100644 index 0000000..fe3ada3 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/isolate_axes.m @@ -0,0 +1,155 @@ +function fh = isolate_axes(ah, vis) +%ISOLATE_AXES Isolate the specified axes in a figure on their own +% +% Examples: +% fh = isolate_axes(ah) +% fh = isolate_axes(ah, vis) +% +% This function will create a new figure containing the axes/uipanels +% specified, and also their associated legends and colorbars. The objects +% specified must all be in the same figure, but they will generally only be +% a subset of the objects in the figure. +% +% IN: +% ah - An array of axes and uipanel handles, which must come from the +% same figure. +% vis - A boolean indicating whether the new figure should be visible. +% Default: false. +% +% OUT: +% fh - The handle of the created figure. + +% Copyright (C) Oliver Woodford 2011-2014, Yair Altman 2015- +%{ +% Thank you to Rosella Blatt for reporting a bug to do with axes in GUIs +% 16/03/12: Moved copyfig to its own function. Thanks to Bob Fratantonio +% for pointing out that the function is also used in export_fig.m +% 12/12/12: Add support for isolating uipanels. Thanks to michael for suggesting it +% 08/10/13: Bug fix to allchildren suggested by Will Grant (many thanks!) +% 05/12/13: Bug fix to axes having different units. Thanks to Remington Reid for reporting +% 21/04/15: Bug fix for exporting uipanels with legend/colorbar on HG1 (reported by Alvaro +% on FEX page as a comment on 24-Apr-2014); standardized indentation & help section +% 22/04/15: Bug fix: legends and colorbars were not exported when exporting axes handle in HG2 +% 02/02/21: Fix axes, figure size to preserve input axes image resolution (thanks @Optecks) +% 25/10/21: Bug fix: subplots were not isolated properly leading to print error (issue #347) +%} + + % Make sure we have an array of handles + if ~all(ishandle(ah)) + error('ah must be an array of handles'); + end + + % Check that the handles are all for axes or uipanels, and are all in the same figure + fh = ancestor(ah(1), 'figure'); + nAx = numel(ah); + for a = 1:nAx + if ~ismember(get(ah(a), 'Type'), {'axes', 'uipanel'}) + error('All handles must be axes or uipanel handles.'); + end + if ~isequal(ancestor(ah(a), 'figure'), fh) + error('Axes must all come from the same figure.'); + end + end + + % Tag the objects so we can find them in the copy + old_tag = get(ah, 'Tag'); + if nAx == 1 + old_tag = {old_tag}; + end + set(ah, 'Tag', 'ObjectToCopy'); + + % Create a new figure exactly the same as the old one + fh = copyfig(fh); %copyobj(fh, 0); + + % Fix Axes & Figure size for image catpuring to have almost exact resolution + % of the Input Axes (thanks @Optecks) + allaxes = findall(fh, 'type', 'axes'); + if ~isempty(ah) + sz = get(ah(1), 'OuterPosition'); + un = get(ah(1), 'Units'); + set(allaxes(1), 'Units',un, 'OuterPosition', [0 0 sz(3) sz(4)]); + set(allaxes(1), 'Units','pixels'); + sz = get(allaxes(1), 'OuterPosition'); + set(fh, 'Units','pixels', 'Position',[0 0 sz(3) sz(4)]+1); + end + + if nargin < 2 || ~vis + set(fh, 'Visible', 'off'); + end + + % Reset the object tags + for a = 1:nAx + set(ah(a), 'Tag', old_tag{a}); + end + + % Find the objects to save + ah = findall(fh, 'Tag', 'ObjectToCopy'); + if numel(ah) ~= nAx + close(fh); + error('Incorrect number of objects found.'); + end + + % Set the axes tags to what they should be + for a = 1:nAx + set(ah(a), 'Tag', old_tag{a}); + end + + % Keep any legends and colorbars which overlap the subplots + % Note: in HG1 these are axes objects; in HG2 they are separate objects, therefore we + % don't test for the type, only the tag (hopefully nobody but Matlab uses them!) + lh = findall(fh, 'Tag','legend', '-or', 'Tag','Colorbar'); + nLeg = numel(lh); + if nLeg > 0 + set([ah(:); lh(:)], 'Units', 'normalized'); + try + ax_pos = get(ah, 'OuterPosition'); % axes and figures have the OuterPosition property + catch + ax_pos = get(ah, 'Position'); % uipanels only have Position, not OuterPosition + end + if nAx > 1 + ax_pos = cell2mat(ax_pos(:)); + end + ax_pos(:,3:4) = ax_pos(:,3:4) + ax_pos(:,1:2); + try + leg_pos = get(lh, 'OuterPosition'); + catch + leg_pos = get(lh, 'Position'); % No OuterPosition in HG2, only in HG1 + end + if nLeg > 1 + leg_pos = cell2mat(leg_pos); + end + leg_pos(:,3:4) = leg_pos(:,3:4) + leg_pos(:,1:2); + ax_pos = shiftdim(ax_pos, -1); + % Overlap test + M = bsxfun(@lt, leg_pos(:,1), ax_pos(:,:,3)) & ... + bsxfun(@lt, leg_pos(:,2), ax_pos(:,:,4)) & ... + bsxfun(@gt, leg_pos(:,3), ax_pos(:,:,1)) & ... + bsxfun(@gt, leg_pos(:,4), ax_pos(:,:,2)); + ah = [ah; lh(any(M, 2))]; + end + + % Get all the objects in the figure + axs = findall(fh); + + % Delete everything except for the input objects and associated items + delete(axs(~ismember(axs, [ah; allchildren(ah); allancestors(ah)]))); +end + +function ah = allchildren(ah) + ah = findall(ah); + if iscell(ah) + ah = cell2mat(ah); + end + ah = ah(:); +end + +function ph = allancestors(ah) + ph = []; + for a = 1:numel(ah) + h = get(ah(a), 'parent'); + while h ~= 0 + ph = [ph; h]; %#ok + h = get(h, 'parent'); + end + end +end diff --git a/matlab/C2xyz_v2/export_fig/pdf2eps.m b/matlab/C2xyz_v2/export_fig/pdf2eps.m new file mode 100644 index 0000000..8010b2a --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/pdf2eps.m @@ -0,0 +1,55 @@ +%PDF2EPS Convert a pdf file to eps format using pdftops +% +% Examples: +% pdf2eps source dest +% +% This function converts a pdf file to eps format. +% +% This function requires that you have pdftops, from the Xpdf suite of +% functions, installed on your system. This can be downloaded from: +% http://xpdfreader.com +% +% Inputs: +% source - filename of the source pdf file to convert. The filename is +% assumed to already have the extension ".pdf". +% dest - filename of the destination eps file. The filename is assumed to +% already have the extension ".eps". + +% Copyright (C) Oliver Woodford 2009-2010, Yair Altman 2015- + +% Thanks to Aldebaro Klautau for reporting a bug when saving to +% non-existant directories. + +% 22/09/2018 - Xpdf website changed to xpdfreader.com + +function pdf2eps(source, dest) + % Construct the options string for pdftops + options = ['-q -paper match -eps -level2 "' source '" "' dest '"']; + + % Convert to eps using pdftops + [status, message] = pdftops(options); + + % Check for error + if status + % Report error + if isempty(message) + error('Unable to generate eps. Check destination directory is writable.'); + else + error(message); + end + end + + % Fix the DSC error created by pdftops + fid = fopen(dest, 'r+'); + if fid == -1 + % Cannot open the file + return + end + fgetl(fid); % Get the first line + str = fgetl(fid); % Get the second line + if strcmp(str(1:min(13, end)), '% Produced by') + fseek(fid, -numel(str)-1, 'cof'); + fwrite(fid, '%'); % Turn ' ' into '%' + end + fclose(fid); +end diff --git a/matlab/C2xyz_v2/export_fig/pdftops.m b/matlab/C2xyz_v2/export_fig/pdftops.m new file mode 100644 index 0000000..076dd75 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/pdftops.m @@ -0,0 +1,186 @@ +function varargout = pdftops(cmd) +%PDFTOPS Calls a local pdftops executable with the input command +% +% Example: +% [status result] = pdftops(cmd) +% +% Attempts to locate a pdftops executable, finally asking the user to +% specify the directory pdftops was installed into. The resulting path is +% stored for future reference. +% +% Once found, the executable is called with the input command string. +% +% This function requires that you have pdftops (from the Xpdf package) +% installed on your system. You can download this from: http://xpdfreader.com +% +% IN: +% cmd - Command string to be passed into pdftops (e.g. '-help'). +% +% OUT: +% status - 0 iff command ran without problem. +% result - Output from pdftops. + +% Copyright: Oliver Woodford, 2009-2010 + +% Thanks to Jonas Dorn for the fix for the title of the uigetdir window on Mac OS. +% Thanks to Christoph Hertel for pointing out a bug in check_xpdf_path under linux. +% 23/01/2014 - Add full path to pdftops.txt in warning. +% 27/05/2015 - Fixed alert in case of missing pdftops; fixed code indentation +% 02/05/2016 - Added possible error explanation suggested by Michael Pacer (issue #137) +% 02/05/2016 - Search additional possible paths suggested by Jonas Stein (issue #147) +% 03/05/2016 - Display the specific error message if pdftops fails for some reason (issue #148) +% 22/09/2018 - Xpdf website changed to xpdfreader.com; improved popup logic +% 03/02/2019 - Fixed one-off 'pdftops not found' error after install (Mac/Linux) (issue #266) +% 15/01/2020 - Fixed reported path of pdftops.txt file in case of error; added warning ID +% 23/07/2020 - Fixed issue #311 (confusion regarding Xpdf-tools download/installation); silent check of pdftops installation in case no input arg specified + + % If no command parameter specified, just check pdftops installation and bail out + if nargin < 1 + xpdf_path(); % this will error if pdftops is not found + return % silent bail-out if pdftops was successfully located + end + + % Call pdftops + [varargout{1:nargout}] = system([xpdf_command(xpdf_path()) cmd]); +end + +function path_ = xpdf_path + % Return a valid path + % Start with the currently set path + path_ = user_string('pdftops'); + % Check the path works + if check_xpdf_path(path_) + return + end + % Check whether the binary is on the path + if ispc + bin = 'pdftops.exe'; + else + bin = 'pdftops'; + end + if check_store_xpdf_path(bin) + path_ = bin; + return + end + % Search the obvious places + if ispc + paths = {'C:\Program Files\xpdf\pdftops.exe', 'C:\Program Files (x86)\xpdf\pdftops.exe'}; + else + paths = {'/usr/bin/pdftops', '/usr/local/bin/pdftops'}; + end + for a = 1:numel(paths) + path_ = paths{a}; + if check_store_xpdf_path(path_) + return + end + end + + % Ask the user to enter the path + errMsg1 = 'Pdftops utility not found. Please locate the program, or install xpdf-tools from '; + url1 = 'http://xpdfreader.com/download.html'; %='http://foolabs.com/xpdf'; + fprintf(2, '%s%s ("Xpdf command line tools" section)\n', errMsg1, hyperlink(url1)); + errMsg1 = [errMsg1 url1]; + %if strncmp(computer,'MAC',3) % Is a Mac + % % Give separate warning as the MacOS uigetdir dialogue box doesn't have a title + % uiwait(warndlg(errMsg1)) + %end + + % Provide an alternative possible explanation as per issue #137 + errMsg2 = 'If pdftops is installed, maybe Matlab is shaddowing it, as described in '; + url2 = 'https://github.com/altmany/export_fig/issues/137'; + fprintf(2, '%s%s\n', errMsg2, hyperlink(url2,'issue #137')); + errMsg2 = [errMsg2 url2]; + + % Provide an alternative possible explanation as per issue #311 + errMsg3 = 'Or perhaps you installed XpdfReader but not xpdf-tools, as described in '; + url3 = 'https://github.com/altmany/export_fig/issues/311'; + fprintf(2, '%s%s\n', errMsg3, hyperlink(url3,'issue #311')); + errMsg3 = [errMsg3 url3]; + + state = 1; + while 1 + if state + option1 = 'Install pdftops'; + else + option1 = 'Issue #137'; + end + answer = questdlg({errMsg1,'',errMsg2,'',errMsg3},'Pdftops error',option1,'Locate pdftops','Cancel','Cancel'); + drawnow; % prevent a Matlab hang: http://undocumentedmatlab.com/blog/solving-a-matlab-hang-problem + switch answer + case 'Install pdftops' + web('-browser',url1); + state = 0; + case 'Issue #137' + web('-browser',url2); + state = 1; + case 'Locate pdftops' + base = uigetdir('/', errMsg1); + if isequal(base, 0) + % User hit cancel or closed window + break + end + base = [base filesep]; %#ok + bin_dir = {'', ['bin' filesep], ['lib' filesep]}; + for a = 1:numel(bin_dir) + path_ = [base bin_dir{a} bin]; + if exist(path_, 'file') == 2 + break + end + end + if check_store_xpdf_path(path_) + return + end + + otherwise % User hit Cancel or closed window + break + end + end + error('pdftops executable not found.'); +end + +function good = check_store_xpdf_path(path_) + % Check the path is valid + good = check_xpdf_path(path_); + if ~good + return + end + % Update the current default path to the path found + if ~user_string('pdftops', path_) + %filename = fullfile(fileparts(which('user_string.m')), '.ignore', 'pdftops.txt'); + [unused, filename] = user_string('pdftops'); %#ok + warning('export_fig:pdftops','Path to pdftops executable could not be saved. Enter it manually in %s.', filename); + return + end +end + +function good = check_xpdf_path(path_) + % Check the path is valid + [good, message] = system([xpdf_command(path_) '-h']); %#ok + % system returns good = 1 even when the command runs + % Look for something distinct in the help text + good = ~isempty(strfind(message, 'PostScript')); %#ok + + % Display the error message if the pdftops executable exists but fails for some reason + % Note: on Mac/Linux, exist('pdftops','file') will always return 2 due to pdftops.m => check for '/','.' (issue #266) + if ~good && exist(path_,'file') && ~isempty(regexp(path_,'[/.]')) %#ok % file exists but generates an error + fprintf('Error running %s:\n', path_); + fprintf(2,'%s\n\n',message); + end +end + +function cmd = xpdf_command(path_) + % Initialize any required system calls before calling ghostscript + % TODO: in Unix/Mac, find a way to determine whether to use "export" (bash) or "setenv" (csh/tcsh) + shell_cmd = ''; + if isunix + % Avoids an error on Linux with outdated MATLAB lib files + % R20XXa/bin/glnxa64/libtiff.so.X + % R20XXa/sys/os/glnxa64/libstdc++.so.X + shell_cmd = 'export LD_LIBRARY_PATH=""; '; + end + if ismac + shell_cmd = 'export DYLD_LIBRARY_PATH=""; '; + end + % Construct the command string + cmd = sprintf('%s"%s" ', shell_cmd, path_); +end diff --git a/matlab/C2xyz_v2/export_fig/print2array.m b/matlab/C2xyz_v2/export_fig/print2array.m new file mode 100644 index 0000000..b5ce84a --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/print2array.m @@ -0,0 +1,376 @@ +function [A, bcol, alpha] = print2array(fig, res, renderer, gs_options) +%PRINT2ARRAY Exports a figure to a bitmap RGB image array +% +% Examples: +% A = print2array +% A = print2array(figure_handle) +% A = print2array(figure_handle, resolution) +% A = print2array(figure_handle, resolution, renderer) +% A = print2array(figure_handle, resolution, renderer, gs_options) +% [A, bcol, alpha] = print2array(...) +% +% This function outputs a bitmap image of a figure, at the desired resolution. +% +% When resolution==1, fast Java screen-capture is attempted first. +% If the Java screen-capture fails or if resolution~=1, the builtin print() +% function is used to create a temp TIF file, which is then loaded and reported. +% If this fails, print() is used to create a temp EPS file which is converted to +% a TIF file using Ghostcript (http://www.ghostscript.com), loaded and reported. +% +% Inputs: +% figure_handle - The handle of the figure to be exported. Default: gcf. +% resolution - Output resolution as a factor of screen resolution. Default: 1 +% Note: resolution ~= 1 uses a slow print to/from image file +% renderer - The renderer to be used by print() function. Default: '-opengl' +% Note: only used when resolution ~= 1 +% gs_options - optional ghostscript parameters (e.g.: '-dNoOutputFonts'). +% Enclose multiple options in a cell array, e.g. {'-a','-b'} +% Note: only used when resolution ~= 1 and basic print() fails +% +% Outputs: +% A - MxNx3 uint8 bitmap image of the figure (MxN pixels x 3 RGB values) +% bcol - 1x3 uint8 vector of the background RGB color +% alpha - MxN uint8 array of alpha values (between 0=transparent, 255=opaque) + +% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015- +%{ +% 05/09/11: Set EraseModes to normal when using opengl or zbuffer +% renderers. Thanks to Pawel Kocieniewski for reporting the issue. +% 21/09/11: Bug fix: unit8 -> uint8! Thanks to Tobias Lamour for reporting it. +% 14/11/11: Bug fix: stop using hardcopy(), as it interfered with figure size +% and erasemode settings. Makes it a bit slower, but more reliable. +% Thanks to Phil Trinh and Meelis Lootus for reporting the issues. +% 09/12/11: Pass font path to ghostscript. +% 27/01/12: Bug fix affecting painters rendering tall figures. Thanks to +% Ken Campbell for reporting it. +% 03/04/12: Bug fix to median input. Thanks to Andy Matthews for reporting it. +% 26/10/12: Set PaperOrientation to portrait. Thanks to Michael Watts for +% reporting the issue. +% 26/02/15: If temp dir is not writable, use the current folder for temp +% EPS/TIF files (Javier Paredes) +% 27/02/15: Display suggested workarounds to internal print() error (issue #16) +% 28/02/15: Enable users to specify optional ghostscript options (issue #36) +% 10/03/15: Fixed minor warning reported by Paul Soderlind; fixed code indentation +% 28/05/15: Fixed issue #69: patches with LineWidth==0.75 appear wide (internal bug in Matlab's print() func) +% 07/07/15: Fixed issue #83: use numeric handles in HG1 +% 11/12/16: Fixed cropping issue reported by Harry D. +% 29/09/18: Fixed issue #254: error in print2array>read_tif_img +% 22/03/20: Alert if ghostscript.m is required but not found on Matlab path +% 24/05/20: Significant performance speedup; added alpha values (where possible) +% 07/07/20: Fixed issue #308: bug in R2019a and earlier +% 07/10/20: Use JavaFrame_I where possible, to avoid evoking a JavaFrame warning +% 07/03/21: Fixed edge-case in case a non-figure handle was provided as input arg +% 10/03/21: Forced a repaint at top of function to ensure accurate image snapshot (issue #211) +% 26/08/21: Added a short pause to avoid unintended image cropping (issue #318) +% 25/10/21: Avoid duplicate error message when retrying print2array with different resolution; display internal print error message +% 19/12/21: Speedups; fixed exporting non-current figure (hopefully fixes issue #318) +%} + + % Generate default input arguments, if needed + if nargin < 1, fig = gcf; end + if nargin < 2, res = 1; end + + % Force a repaint to ensure we get an accurate snapshot image (issue #211) + drawnow + + % Get the figure size in pixels + old_mode = get(fig, 'Units'); + set(fig, 'Units', 'pixels'); + px = get(fig, 'Position'); + set(fig, 'Units', old_mode); + + pause(0.02); % add a short pause to avoid unintended cropping (issue #318) + + % Retrieve the background colour + bcol = get(fig, 'Color'); + try + % Try a direct Java screen-capture first - *MUCH* faster than print() to file + % Note: we could also use A=matlab.graphics.internal.getframeWithDecorations(fig,false) but it (1) returns no alpha and (2) does not exist in older Matlabs + if res == 1 + [A, alpha] = getJavaImage(fig); + else + error('magnify/downscale via print() to image file and then import'); + end + catch err %#ok + % Warn if output is large + npx = prod(px(3:4)*res)/1e6; + if npx > 30 + % 30M pixels or larger! + warning('MATLAB:LargeImage', 'print2array generating a %.1fM pixel image. This could be slow and might also cause memory problems.', npx); + end + % Set the resolution parameter + res_str = ['-r' num2str(ceil(get(0, 'ScreenPixelsPerInch')*res))]; + % Generate temporary file name + tmp_nam = [tempname '.tif']; + try + % Ensure that the temp dir is writable (Javier Paredes 26/2/15) + fid = fopen(tmp_nam,'w'); + fwrite(fid,1); + fclose(fid); + delete(tmp_nam); % cleanup + isTempDirOk = true; + catch + % Temp dir is not writable, so use the current folder + [dummy,fname,fext] = fileparts(tmp_nam); %#ok + fpath = pwd; + tmp_nam = fullfile(fpath,[fname fext]); + isTempDirOk = false; + end + % Enable users to specify optional ghostscript options (issue #36) + isRetry = false; + if nargin > 3 && ~isempty(gs_options) + if isequal(gs_options,'retry') + isRetry = true; + gs_options = ''; + elseif iscell(gs_options) + gs_options = sprintf(' %s',gs_options{:}); + elseif ~ischar(gs_options) + error('gs_options input argument must be a string or cell-array of strings'); + else + gs_options = [' ' gs_options]; + end + else + gs_options = ''; + end + if nargin > 2 && strcmp(renderer, '-painters') + % First try to print directly to image file + try + % Print the file into a temporary image file and read it into array A + [A, alpha, err, ex] = getPrintImage(fig, res_str, renderer, tmp_nam); + if err, rethrow(ex); end + catch % error - try to print to EPS and then using Ghostscript to TIF + % Ensure that ghostscript() exists on the Matlab path + if ~exist('ghostscript','file') && isempty(which('ghostscript')) + error('export_fig:print2array:ghostscript', 'The ghostscript.m function is required by print2array.m. Install the complete export_fig package from https://www.mathworks.com/matlabcentral/fileexchange/23629-export_fig or https://github.com/altmany/export_fig') + end + % Print to eps file + if isTempDirOk + tmp_eps = [tempname '.eps']; + else + tmp_eps = fullfile(fpath,[fname '.eps']); + end + print2eps(tmp_eps, fig, 0, renderer, '-loose'); + try + % Initialize the command to export to tiff using ghostscript + cmd_str = ['-dEPSCrop -q -dNOPAUSE -dBATCH ' res_str ' -sDEVICE=tiff24nc']; + % Set the font path + fp = font_path(); + if ~isempty(fp) + cmd_str = [cmd_str ' -sFONTPATH="' fp '"']; + end + % Add the filenames + cmd_str = [cmd_str ' -sOutputFile="' tmp_nam '" "' tmp_eps '"' gs_options]; + % Execute the ghostscript command + ghostscript(cmd_str); + catch me + % Delete the intermediate file + delete(tmp_eps); + rethrow(me); + end + % Delete the intermediate file + delete(tmp_eps); + % Read in the generated bitmap + A = imread(tmp_nam); + % Delete the temporary bitmap file + delete(tmp_nam); + end + else + if nargin < 3 + renderer = '-opengl'; + end + % Print the file into a temporary image file and read it into array A + [A, alpha, err, ex] = getPrintImage(fig, res_str, renderer, tmp_nam); + % Throw any error that occurred + if err + % Display suggested workarounds to internal print() error (issue #16) + if ~isRetry + fprintf(2, 'An error occurred in Matlab''s builtin print function:\n%s\nTry setting the figure Renderer to ''painters'' or use opengl(''software'').\n\n', ex.message); + end + rethrow(ex); + end + end + end + + % Set the background color + if isequal(bcol, 'none') + bcol = squeeze(A(1,1,:)); + if ~all(bcol==0) %if not black + bcol = [255,255,255]; %=white %=[]; + end + else + if all(bcol <= 1) + bcol = bcol * 255; + end + if ~isequal(bcol, round(bcol)) + bcol = squeeze(A(1,1,:)); + %{ + % Set border pixels to the correct colour + for l = 1:size(A, 2) + if ~all(reshape(A(:,l,:) == 255, [], 1)) + break; + end + end + for r = size(A, 2):-1:l + if ~all(reshape(A(:,r,:) == 255, [], 1)) + break; + end + end + for t = 1:size(A, 1) + if ~all(reshape(A(t,:,:) == 255, [], 1)) + break; + end + end + for b = size(A, 1):-1:t + if ~all(reshape(A(b,:,:) == 255, [], 1)) + break; + end + end + bcol = median(single([reshape(A(:,[l r],:), [], size(A, 3)); ... + reshape(A([t b],:,:), [], size(A, 3))]), 1)); + for c = 1:size(A, 3) + A(:,[1:l-1, r+1:end],c) = bcol(c); + A([1:t-1, b+1:end],:,c) = bcol(c); + end + %} + end + end + bcol = uint8(bcol); + + % Ensure that the output size is correct + if isequal(res, round(res)) + px = round([px([4 3])*res 3]); % round() to avoid an indexing warning below + if any(size(A) > px) %~isequal(size(A), px) + A = A(1:min(end,px(1)),1:min(end,px(2)),:); + end + if any(size(alpha) > px(1:2)) + alpha = alpha(1:min(end,px(1)),1:min(end,px(2))); + end + end +end + +% Get the Java-based screen-capture of the figure's JFrame content-panel +function [imgData, alpha] = getJavaImage(hFig) + % Get the figure's underlying Java frame + oldWarn = warning('off','MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame'); + warning('off','MATLAB:ui:javaframe:PropertyToBeRemoved'); + try + jf = get(handle(hFig),'JavaFrame_I'); + catch + jf = get(handle(hFig),'JavaFrame'); %#ok + end + warning(oldWarn); + + % Get the Java frame's root frame handle + %jframe = jf.getFigurePanelContainer.getComponent(0).getRootPane.getParent; + try + jClient = jf.fHG2Client; % This works from R2014b and up + catch + try + jClient = jf.fHG1Client; % This works from R2008b-R2014a + catch + jClient = jf.fFigureClient; % This works up to R2011a + end + end + + % Get the content-pane + try + jPanel = jClient.getContentPane; + catch + jPanel = jClient.getFigurePanelContainer; + end + jPanel.repaint; + w = jPanel.getWidth; + h = jPanel.getHeight; + + % Create a BufferedImage and paint the content-pane into it + % (https://coderanch.com/t/470601/java/screenshot-JPanel) + % Note: contrary to documentation and common-sense, it turns out that TYPE_INT_RGB + % ^^^^ returns non-opaque alpha, while TYPE_INT_ARGB only returns 255s in the alpha channel + jOriginalGraphics = jPanel.getGraphics; + import java.awt.image.BufferedImage + try TYPE_INT_RGB = BufferedImage.TYPE_INT_RGB; catch, TYPE_INT_RGB = 1; end + jImage = BufferedImage(w, h, TYPE_INT_RGB); + jPanel.paint(jImage.createGraphics); + jPanel.paint(jOriginalGraphics); % repaint original figure to avoid a blank window + + % Extract the RGB pixels from the BufferedImage (see screencapture.m) + pixelsData = reshape(typecast(jImage.getData.getDataStorage, 'uint8'), 4, w, h); + imgData = cat(3, ... + transpose(reshape(pixelsData(3, :, :), w, h)), ... + transpose(reshape(pixelsData(2, :, :), w, h)), ... + transpose(reshape(pixelsData(1, :, :), w, h))); + + % And now also the alpha channel (if available) + alpha = transpose(reshape(pixelsData(4, :, :), w, h)); + + % Ensure that the results are the expected size, otherwise raise an error + figSize = getpixelposition(hFig); + expectedSize = [figSize(4), figSize(3), 3]; + if ~isequal(expectedSize, size(imgData)) + error('bad Java screen-capture size!') + end +end + +% Export an image file of the figure using print() and then read it into an array +function [imgData, alpha, err, ex] = getPrintImage(fig, res_str, renderer, tmp_nam) + imgData = []; % fix for issue #254 + err = false; + ex = []; + alpha = []; + % Temporarily set the paper size + fig = ancestor(fig, 'figure'); % just in case it's not a figure... + old_pos_mode = get(fig, 'PaperPositionMode'); + old_orientation = get(fig, 'PaperOrientation'); + set(fig, 'PaperPositionMode','auto', 'PaperOrientation','portrait'); + try + % Workaround for issue #69: patches with LineWidth==0.75 appear wide (internal bug in Matlab's print() function) + fp = []; % in case we get an error below + fp = findall(fig, 'Type','patch', 'LineWidth',0.75); + set(fp, 'LineWidth',0.5); + try %if using_hg2(fig) % HG2 (R2014b or newer) + % Use print('-RGBImage') directly (a bit faster than via temp image file) + imgData = print(fig, renderer, res_str, '-RGBImage'); + catch %else % HG1 (R2014a or older) + % Fix issue #83: use numeric handles in HG1 + fig = double(fig); + % Print to image file + print(fig, renderer, res_str, '-dtiff', tmp_nam); + imgData = imread(tmp_nam); + % Delete the temporary file + delete(tmp_nam); + end + imgSize = size(imgData); imgSize = imgSize([1,2]); % Fix issue #308 + alpha = 255 * ones(imgSize, 'uint8'); % =all pixels opaque + catch ex + err = true; + end + if ~isempty(fp) % this check is not really needed, but makes the code cleaner + set(fp, 'LineWidth',0.75); % restore original figure appearance + end + % Reset the paper size + set(fig, 'PaperPositionMode',old_pos_mode, 'PaperOrientation',old_orientation); +end + +% Return (and create, where necessary) the font path (for use by ghostscript) +function fp = font_path() + fp = user_string('gs_font_path'); + if ~isempty(fp) + return + end + % Create the path + % Start with the default path + fp = getenv('GS_FONTPATH'); + % Add on the typical directories for a given OS + if ispc + if ~isempty(fp) + fp = [fp ';']; + end + fp = [fp getenv('WINDIR') filesep 'Fonts']; + else + if ~isempty(fp) + fp = [fp ':']; + end + fp = [fp '/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype']; + end + user_string('gs_font_path', fp); +end diff --git a/matlab/C2xyz_v2/export_fig/print2eps.m b/matlab/C2xyz_v2/export_fig/print2eps.m new file mode 100644 index 0000000..9aba92e --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/print2eps.m @@ -0,0 +1,663 @@ +function print2eps(name, fig, export_options, varargin) +%PRINT2EPS Prints figures to eps with improved line styles +% +% Examples: +% print2eps filename +% print2eps(filename, fig_handle) +% print2eps(filename, fig_handle, export_options) +% print2eps(filename, fig_handle, export_options, print_options) +% +% This function saves a figure as an eps file, with two improvements over +% MATLAB's print command. First, it improves the line style, making dashed +% lines more like those on screen and giving grid lines a dotted line style. +% Secondly, it substitutes original font names back into the eps file, +% where these have been changed by MATLAB, for up to 11 different fonts. +% +% Inputs: +% filename - string containing the name (optionally including full or +% relative path) of the file the figure is to be saved as. A +% ".eps" extension is added if not there already. If a path is +% not specified, the figure is saved in the current directory. +% fig_handle - The handle of the figure to be saved. Default: gcf(). +% export_options - array or struct of optional values: +% bb_padding - Scalar value of amount of padding to add to border around +% the cropped image, in points (if >1) or percent (if <1). +% Can be negative as well as positive; Default: 0 +% crop - Cropping flag. Deafult: 0 +% fontswap - Whether to swap non-default fonts in figure. Default: true +% preserve_size - Whether to preserve the figure's PaperSize. Default: false +% font_space - Character used to separate font-name terms in the EPS output +% e.g. "Courier New" => "Courier-New". Default: '' +% (available only via the struct alternative) +% renderer - Renderer used to generate bounding-box. Default: 'opengl' +% (available only via the struct alternative) +% crop_amounts - 4-element vector of crop amounts: [top,right,bottom,left] +% (available only via the struct alternative) +% regexprep - 2-element cell-array of regular-expression replacement in the +% generated EPS. 1st element is the replaced string(s), 2nd is +% the replacement(s) (available only via the struct alternative) +% print_options - Additional parameter strings to be passed to the print command + +%{ +% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015- + +% The idea of editing the EPS file to change line styles comes from Jiro +% Doke's FIXPSLINESTYLE (fex id: 17928) +% The idea of changing dash length with line width came from comments on +% fex id: 5743, but the implementation is mine :) +%} +%{ +% 14/11/11: Fix a MATLAB bug rendering black or white text incorrectly. +% Thanks to Mathieu Morlighem for reporting the issue and +% obtaining a fix from TMW. +% 08/12/11: Added ability to correct fonts. Several people have requested +% this at one time or another, and also pointed me to printeps +% (fex id: 7501), so thank you to them. My implementation (which +% was not inspired by printeps - I'd already had the idea for my +% approach) goes slightly further in that it allows multiple +% fonts to be swapped. +% 14/12/11: Fix bug affecting font names containing spaces. Thanks to David +% Szwer for reporting the issue. +% 25/01/12: Add a font not to be swapped. Thanks to Anna Rafferty and Adam +% Jackson for reporting the issue. Also fix a bug whereby using a +% font alias can lead to another font being swapped in. +% 10/04/12: Make the font swapping case insensitive. +% 26/10/12: Set PaperOrientation to portrait. Thanks to Michael Watts for +% reporting the issue. +% 26/10/12: Fix issue to do with swapping fonts changing other fonts and +% sizes we don't want, due to listeners. Thanks to Malcolm Hudson +% for reporting the issue. +% 22/03/13: Extend font swapping to axes labels. Thanks to Rasmus Ischebeck +% for reporting the issue. +% 23/07/13: Bug fix to font swapping. Thanks to George for reporting the +% issue. +% 13/08/13: Fix MATLAB feature of not exporting white lines correctly. +% Thanks to Sebastian Hesslinger for reporting it. +% 24/02/15: Fix for Matlab R2014b bug (issue #31): LineWidths<0.75 are not +% set in the EPS (default line width is used) +% 25/02/15: Fixed issue #32: BoundingBox problem caused uncropped EPS/PDF files +% 05/03/15: Fixed issue #43: Inability to perform EPS file post-processing +% 06/03/15: Improved image padding & cropping thanks to Oscar Hartogensis +% 21/03/15: Fixed edge-case of missing handles having a 'FontName' property +% 26/03/15: Attempt to fix issue #45: white lines in subplots do not print correctly +% 27/03/15: Attempt to fix issue #44: white artifact lines appearing in patch exports +% 30/03/15: Fixed issue #52: improved performance on HG2 (R2014b+) +% 09/04/15: Comment blocks consolidation and minor code cleanup (no real code change) +% 12/04/15: Fixed issue #56: bad cropping +% 14/04/15: Workaround for issue #45: lines in image subplots are exported in invalid color +% 07/07/15: Added option to avoid font-swapping in EPS/PDF +% 07/07/15: Fixed issue #83: use numeric handles in HG1 +% 22/07/15: Fixed issue #91 (thanks to Carlos Moffat) +% 28/09/15: Fixed issue #108 (thanks to JacobD10) +% 01/11/15: Fixed issue #112: optional renderer for bounding-box computation (thanks to Jesús Pestana Puerta) +% 21/02/16: Enabled specifying non-automated crop amounts +% 22/02/16: Better support + backward compatibility for transparency (issue #108) +% 10/06/16: Fixed issue #159: text handles get cleared by Matlab in the print() command +% 12/06/16: Improved the fix for issue #159 (in the previous commit) +% 12/06/16: Fixed issue #158: transparent patch color in PDF/EPS +% 18/09/17: Fixed issue #194: incorrect fonts in EPS/PDF output +% 18/09/17: Fixed issue #195: relaxed too-tight cropping in EPS/PDF +% 14/11/17: Workaround for issue #211: dashed/dotted lines in 3D axes appear solid +% 15/11/17: Updated issue #211: only set SortMethod='ChildOrder' in HG2, and when it looks the same onscreen; support multiple figure axes +% 18/11/17: Fixed issue #225: transparent/translucent dashed/dotted lines appear solid in EPS/PDF +% 24/03/18: Fixed issue #239: black title meshes with temporary black background figure bgcolor, causing bad cropping +% 21/03/19: Improvement for issue #258: missing fonts in output EPS/PDF (still *NOT* fully solved) +% 21/03/19: Fixed issues #166,#251: Arial font is no longer replaced with Helvetica but rather treated as a non-standard user font +% 14/05/19: Made Helvetica the top default font-swap, replacing Courier +% 12/06/19: Issue #277: Enabled preservation of figure's PaperSize in output PDF/EPS file +% 06/08/19: Issue #281: only fix patch/textbox color if it's not opaque +% 15/01/20: Added warning ID for easier suppression by users +% 20/01/20: Added comment about unsupported patch transparency in some Ghostscript versions (issue #285) +% 10/12/20: Enabled user-specified regexp replacements in the generated EPS file (issue #324) +% 11/03/21: Added documentation about export_options.regexprep; added sanity check (issue #324) +% 21/07/21: Fixed misleading warning message about regexprep field when it's empty (issue #338) +% 26/08/21: Added a short pause to avoid unintended image cropping (issue #318) +%} + + options = {'-loose'}; + if nargin > 3 + options = [options varargin]; + elseif nargin < 3 + export_options = 0; + if nargin < 2 + fig = gcf(); + end + end + + % Retrieve padding, crop & font-swap values + crop_amounts = nan(1,4); % auto-crop all 4 sides by default + if isstruct(export_options) + try preserve_size = export_options.preserve_size; catch, preserve_size = false; end + try fontswap = export_options.fontswap; catch, fontswap = true; end + try font_space = export_options.font_space; catch, font_space = ''; end + font_space(2:end) = ''; + try bb_crop = export_options.crop; catch, bb_crop = 0; end + try crop_amounts = export_options.crop_amounts; catch, end + try bb_padding = export_options.bb_padding; catch, bb_padding = 0; end + try renderer = export_options.rendererStr; catch, renderer = 'opengl'; end % fix for issue #110 + if renderer(1)~='-', renderer = ['-' renderer]; end + else + if numel(export_options) > 3 % preserve_size + preserve_size = export_options(4); + else + preserve_size = false; + end + if numel(export_options) > 2 % font-swapping + fontswap = export_options(3); + else + fontswap = true; + end + if numel(export_options) > 1 % cropping + bb_crop = export_options(2); + else + bb_crop = 0; % scalar value, so use default bb_crop value of 0 + end + if numel(export_options) > 0 % padding + bb_padding = export_options(1); + else + bb_padding = 0; + end + renderer = '-opengl'; + font_space = ''; + end + + % Construct the filename + if numel(name) < 5 || ~strcmpi(name(end-3:end), '.eps') + name = [name '.eps']; % Add the missing extension + end + + % Set paper size + old_pos_mode = get(fig, 'PaperPositionMode'); + old_orientation = get(fig, 'PaperOrientation'); + old_paper_units = get(fig, 'PaperUnits'); + set(fig, 'PaperPositionMode','auto', 'PaperOrientation','portrait', 'PaperUnits','points'); + + % Find all the used fonts in the figure + font_handles = findall(fig, '-property', 'FontName'); + fonts = get(font_handles, 'FontName'); + if isempty(fonts) + fonts = {}; + elseif ~iscell(fonts) + fonts = {fonts}; + end + + % Map supported font aliases onto the correct name + fontsl = lower(fonts); + for a = 1:numel(fonts) + f = fontsl{a}; + f(f==' ') = []; + switch f + case {'times', 'timesnewroman', 'times-roman'} + fontsl{a} = 'times'; + %case {'arial', 'helvetica'} % issues #166, #251 + % fontsl{a} = 'helvetica'; + case {'newcenturyschoolbook', 'newcenturyschlbk'} + fontsl{a} = 'newcenturyschlbk'; + otherwise + end + end + fontslu = unique(fontsl); + + % Determine the font swap table + if fontswap + % Issue #258: Rearrange standard fonts list based on decending "problematicness" + % The issue is still *NOT* fully solved because I cannot figure out how to force + % the EPS postscript engine to look for the user's font on disk + % Also see: https://stat.ethz.ch/pipermail/r-help/2005-January/064374.html + matlab_fonts = {'Helvetica', 'Times', 'Courier', 'Symbol', 'ZapfDingbats', ... + 'Palatino', 'Bookman', 'ZapfChancery', 'AvantGarde', ... + 'NewCenturySchlbk', 'Helvetica-Narrow'}; + matlab_fontsl = lower(matlab_fonts); + require_swap = find(~ismember(fontslu, matlab_fontsl)); + unused_fonts = find(~ismember(matlab_fontsl, fontslu)); + font_swap = cell(3, min(numel(require_swap), numel(unused_fonts))); + fonts_new = fonts; + for a = 1:size(font_swap, 2) + font_swap{1,a} = find(strcmp(fontslu{require_swap(a)}, fontsl)); + font_swap{2,a} = matlab_fonts{unused_fonts(a)}; + font_swap{3,a} = fonts{font_swap{1,a}(1)}; + fonts_new(font_swap{1,a}) = font_swap(2,a); + end + else + font_swap = []; + end + + % Swap the fonts + if ~isempty(font_swap) + fonts_size = get(font_handles, 'FontSize'); + if iscell(fonts_size) + fonts_size = cell2mat(fonts_size); + end + M = false(size(font_handles)); + + % Loop because some changes may not stick first time, due to listeners + c = 0; + update = zeros(1000, 1); + for b = 1:10 % Limit number of loops to avoid infinite loop case + for a = 1:numel(M) + M(a) = ~isequal(get(font_handles(a), 'FontName'), fonts_new{a}) || ~isequal(get(font_handles(a), 'FontSize'), fonts_size(a)); + if M(a) + set(font_handles(a), 'FontName', fonts_new{a}, 'FontSize', fonts_size(a)); + c = c + 1; + update(c) = a; + end + end + if ~any(M) + break; + end + end + + % Compute the order to revert fonts later, without the need of a loop + [update, M] = unique(update(1:c)); + [dummy, M] = sort(M); %#ok + update = reshape(update(M), 1, []); + end + + % MATLAB bug fix - black and white text can come out inverted sometimes + % Find the white and black text + black_text_handles = findall(fig, 'Type', 'text', 'Color', [0 0 0]); + white_text_handles = findall(fig, 'Type', 'text', 'Color', [1 1 1]); + % Set the font colors slightly off their correct values + set(black_text_handles, 'Color', [0 0 0] + eps); + set(white_text_handles, 'Color', [1 1 1] - eps); + + % MATLAB bug fix - white lines can come out funny sometimes + % Find the white lines + white_line_handles = findall(fig, 'Type', 'line', 'Color', [1 1 1]); + % Set the line color slightly off white + set(white_line_handles, 'Color', [1 1 1] - 0.00001); + + % MATLAB bug fix (issue #211): dashed/dotted lines in 3D axes appear solid + % Note: this "may limit other functionality in plotting such as hidden line/surface removal" + % reference: Technical Support Case #02838114, https://mail.google.com/mail/u/0/#inbox/15fb7659f70e7bd8 + hAxes = findall(fig, 'Type', 'axes'); + if using_hg2 && ~isempty(hAxes) % issue #211 presumably happens only in HG2, not HG1 + try + % If there are any axes using SortMethod~='ChildOrder' + oldSortMethods = get(hAxes,{'SortMethod'}); % use {'SortMethod'} to ensure we get a cell array, even for single axes + if any(~strcmpi('ChildOrder',oldSortMethods)) % i.e., any oldSortMethods=='depth' + % Check if the axes look visually different onscreen when SortMethod='ChildOrder' + imgBefore = print2array(fig); + set(hAxes,'SortMethod','ChildOrder'); + imgAfter = print2array(fig); + if isequal(imgBefore, imgAfter) + % They look the same, so use SortMethod='ChildOrder' when generating the EPS + else + % They look different, so revert SortMethod and issue a warning message + warning('YMA:export_fig:issue211', ... + ['You seem to be using axes that have overlapping/hidden graphic elements. ' 10 ... + 'Setting axes.SortMethod=''ChildOrder'' may solve potential problems in EPS/PDF export. ' 10 ... + 'Additional info: https://github.com/altmany/export_fig/issues/211']) + set(hAxes,{'SortMethod'},oldSortMethods); + end + end + catch err + % ignore + a=err; %#ok % debug breakpoint + end + end + + % Workaround for issue #45: lines in image subplots are exported in invalid color + % In this case the -depsc driver solves the problem, but then all the other workarounds + % below (for all the other issues) will fail, so it's better to let the user decide by + % just issuing a warning and accepting the '-depsc' input parameter + epsLevel2 = ~any(strcmpi(options,'-depsc')); + if epsLevel2 + % Use -depsc2 (EPS color level-2) if -depsc (EPS color level-3) was not specifically requested + options{end+1} = '-depsc2'; + % Issue a warning if multiple images & lines were found in the figure, and HG1 with painters renderer is used + isPainters = any(strcmpi(options,'-painters')); + if isPainters && ~using_hg2 && numel(findall(fig,'Type','image'))>1 && ~isempty(findall(fig,'Type','line')) + warning('YMA:export_fig:issue45', ... + ['Multiple images & lines detected. In such cases, the lines might \n' ... + 'appear with an invalid color due to an internal MATLAB bug (fixed in R2014b). \n' ... + 'Possible workaround: add a ''-depsc'' or ''-opengl'' parameter to the export_fig command.']); + end + end + + % Fix issue #83: use numeric handles in HG1 + if ~using_hg2(fig), fig = double(fig); end + + % Workaround for when transparency is lost through conversion fig>EPS>PDF (issue #108) + % Replace transparent patch RGB values with an ID value (rare chance that ID color is being used already) + if using_hg2 + origAlphaColors = eps_maintainAlpha(fig); + end + + % Ensure that everything is fully rendered, to avoid cropping (issue #318) + drawnow; pause(0.01); + + % Print to eps file + print(fig, options{:}, name); + + % Restore the original axes SortMethods (if updated) + try set(hAxes,{'SortMethod'},oldSortMethods); catch, end + + % Do post-processing on the eps file + try + % Read the EPS file into memory + fstrm = read_write_entire_textfile(name); + catch + fstrm = ''; + end + + % Restore colors for transparent patches/lines and apply the + % setopacityalpha setting in the EPS file (issue #108) + if using_hg2 + [~,fstrm,foundFlags] = eps_maintainAlpha(fig, fstrm, origAlphaColors); + + % If some of the transparencies were not found in the EPS file, then rerun the + % export with only the found transparencies modified (backward compatibility) + if ~isempty(fstrm) && ~all(foundFlags) + foundIdx = find(foundFlags); + for objIdx = 1 : sum(foundFlags) + colorsIdx = foundIdx(objIdx); + colorsData = origAlphaColors{colorsIdx}; + hObj = colorsData{1}; + propName = colorsData{2}; + newColor = colorsData{4}; + hObj.(propName).ColorData = newColor; + end + delete(name); + print(fig, options{:}, name); + fstrm = read_write_entire_textfile(name); + [~,fstrm] = eps_maintainAlpha(fig, fstrm, origAlphaColors(foundFlags)); + end + end + + % Bail out if EPS post-processing is not possible + if isempty(fstrm) + warning('YMA:export_fig:EPS','Loading EPS file failed, so unable to perform post-processing. This is usually because the figure contains a large number of patch objects. Consider exporting to a bitmap format in this case.'); + return + end + + % Fix for Matlab R2014b bug (issue #31): LineWidths<0.75 are not set in the EPS (default line width is used) + try + if using_hg2(fig) + % Convert miter joins to line joins + %fstrm = regexprep(fstrm, '\n10.0 ML\n', '\n1 LJ\n'); + % This is faster (the original regexprep could take many seconds when the axes contains many lines): + fstrm = strrep(fstrm, sprintf('\n10.0 ML\n'), sprintf('\n1 LJ\n')); + + % In HG2, grid lines and axes Ruler Axles have a default LineWidth of 0.5 => replace en-bulk (assume that 1.0 LineWidth = 1.333 LW) + % hAxes=gca; hAxes.YGridHandle.LineWidth, hAxes.YRuler.Axle.LineWidth + %fstrm = regexprep(fstrm, '(GC\n2 setlinecap\n1 LJ)\nN', '$1\n0.667 LW\nN'); + % This is faster: + fstrm = strrep(fstrm, sprintf('GC\n2 setlinecap\n1 LJ\nN'), sprintf('GC\n2 setlinecap\n1 LJ\n0.667 LW\nN')); + + % This is more accurate but *MUCH* slower (issue #52) + %{ + % Modify all thin lines in the figure to have 10x LineWidths + hLines = findall(fig,'Type','line'); + hThinLines = []; + for lineIdx = 1 : numel(hLines) + thisLine = hLines(lineIdx); + if thisLine.LineWidth < 0.75 && strcmpi(thisLine.Visible,'on') + hThinLines(end+1) = thisLine; %#ok + thisLine.LineWidth = thisLine.LineWidth * 10; + end + end + + % If any thin lines were found + if ~isempty(hThinLines) + % Prepare an EPS with large-enough line widths + print(fig, options{:}, name); + % Restore the original LineWidths in the figure + for lineIdx = 1 : numel(hThinLines) + thisLine = handle(hThinLines(lineIdx)); + thisLine.LineWidth = thisLine.LineWidth / 10; + end + + % Compare the original and the new EPS files and correct the original stream's LineWidths + fstrm_new = read_write_entire_textfile(name); + idx = 500; % skip heading with its possibly-different timestamp + markerStr = sprintf('10.0 ML\nN'); + markerLen = length(markerStr); + while ~isempty(idx) && idx < length(fstrm) + lastIdx = min(length(fstrm), length(fstrm_new)); + delta = fstrm(idx+1:lastIdx) - fstrm_new(idx+1:lastIdx); + idx = idx + find(delta,1); + if ~isempty(idx) && ... + isequal(fstrm(idx-markerLen+1:idx), markerStr) && ... + ~isempty(regexp(fstrm_new(idx-markerLen+1:idx+12),'10.0 ML\n[\d\.]+ LW\nN')) %#ok + value = str2double(regexprep(fstrm_new(idx:idx+12),' .*','')); + if isnan(value), break; end % something's wrong... - bail out + newStr = sprintf('%0.3f LW\n',value/10); + fstrm = [fstrm(1:idx-1) newStr fstrm(idx:end)]; + idx = idx + 12; + else + break; + end + end + end + %} + + % This is much faster although less accurate: fix all non-gray lines to have a LineWidth of 0.75 (=1 LW) + % Note: This will give incorrect LineWidth of 075 for lines having LineWidth<0.75, as well as for non-gray grid-lines (if present) + % However, in practice these edge-cases are very rare indeed, and the difference in LineWidth should not be noticeable + %fstrm = regexprep(fstrm, '([CR]C\n2 setlinecap\n1 LJ)\nN', '$1\n1 LW\nN'); + % This is faster (the original regexprep could take many seconds when the axes contains many lines): + fstrm = strrep(fstrm, sprintf('\n2 setlinecap\n1 LJ\nN'), sprintf('\n2 setlinecap\n1 LJ\n1 LW\nN')); + end + catch err + fprintf(2, 'Error fixing LineWidths in EPS file: %s\n at %s:%d\n', err.message, err.stack(1).file, err.stack(1).line); + end + + % Reset the font and line colors + try + set(black_text_handles, 'Color', [0 0 0]); + set(white_text_handles, 'Color', [1 1 1]); + catch + % Fix issue #159: redo findall() '*text_handles' + black_text_handles = findall(fig, 'Type', 'text', 'Color', [0 0 0]+eps); + white_text_handles = findall(fig, 'Type', 'text', 'Color', [1 1 1]-eps); + set(black_text_handles, 'Color', [0 0 0]); + set(white_text_handles, 'Color', [1 1 1]); + end + set(white_line_handles, 'Color', [1 1 1]); + + % Preserve the figure's PaperSize in the output file, if requested (issue #277) + if preserve_size + % https://stackoverflow.com/questions/19646329/postscript-document-size + paper_size = get(fig, 'PaperSize'); % in [points] + fstrm = sprintf('<< /PageSize [%d %d] >> setpagedevice\n%s', paper_size, fstrm); + end + + % Reset paper size + set(fig, 'PaperPositionMode',old_pos_mode, 'PaperOrientation',old_orientation, 'PaperUnits',old_paper_units); + + % Reset the font names in the figure + if ~isempty(font_swap) + for a = update + set(font_handles(a), 'FontName', fonts{a}, 'FontSize', fonts_size(a)); + end + + for a = 1:size(font_swap, 2) + fontName = font_swap{3,a}; + %fontName = fontName(~isspace(font_swap{3,a})); + if length(fontName) > 29 + warning('YMA:export_fig:font_name','Font name ''%s'' is longer than 29 characters. This might cause problems in some EPS/PDF readers. Consider using a different font.',fontName); + end + if isempty(font_space) + fontName(fontName==' ') = ''; + else + fontName(fontName==' ') = char(font_space); + end + + % Replace all instances of the standard Matlab fonts with the original user's font names + %fstrm = regexprep(fstrm, [font_swap{1,a} '-?[a-zA-Z]*\>'], fontName); + %fstrm = regexprep(fstrm, [font_swap{2,a} '([ \n])'], [fontName '$1']); + %fstrm = regexprep(fstrm, font_swap{2,a}, fontName); % also replace -Bold, -Italic, -BoldItalic + + % Times-Roman's Bold/Italic fontnames don't include '-Roman' + fstrm = regexprep(fstrm, [font_swap{2,a} '(\-Roman)?'], fontName); + end + end + + % Move the bounding box to the top of the file (HG2 only), or fix the line styles (HG1 only) + if using_hg2(fig) + % Move the bounding box to the top of the file (HG2 only) + [s, e] = regexp(fstrm, '%%BoundingBox: [^%]*%%'); + if numel(s) == 2 + fstrm = fstrm([1:s(1)-1 s(2):e(2)-2 e(1)-1:s(2)-1 e(2)-1:end]); + end + else + % Fix the line styles (HG1 only) + fstrm = fix_lines(fstrm); + end + + % Apply the bounding box padding & cropping, replacing Matlab's print()'s bounding box + if bb_crop + % Calculate a new bounding box based on a bitmap print using crop_border.m + % 1. Determine the Matlab BoundingBox and PageBoundingBox + [s,e] = regexp(fstrm, '%%BoundingBox: [^%]*%%'); % location BB in eps file + if numel(s)==2, s=s(2); e=e(2); end + aa = fstrm(s+15:e-3); % dimensions bb - STEP1 + bb_matlab = cell2mat(textscan(aa,'%f32%f32%f32%f32')); % dimensions bb - STEP2 + + [s,e] = regexp(fstrm, '%%PageBoundingBox: [^%]*%%'); % location bb in eps file + if numel(s)==2, s=s(2); e=e(2); end + aa = fstrm(s+19:e-3); % dimensions bb - STEP1 + pagebb_matlab = cell2mat(textscan(aa,'%f32%f32%f32%f32')); % dimensions bb - STEP2 + + % 1b. Fix issue #239: black title meshes with temporary black background figure bgcolor, causing bad cropping + hTitles = []; + if isequal(get(fig,'Color'),'none') + hAxes = findall(fig,'type','axes'); + for idx = 1 : numel(hAxes) + hAx = hAxes(idx); + try + hTitle = hAx.Title; + oldColor = hTitle.Color; + if all(oldColor < 5*eps) || (ischar(oldColor) && lower(oldColor(1))=='k') + hTitles(end+1) = hTitle; %#ok + hTitle.Color = [0,0,.01]; + end + catch + end + end + end + + % 2. Create a bitmap image and use crop_borders to create the relative + % bb with respect to the PageBoundingBox + drawnow; pause(0.02); % avoid unintended cropping (issue #318) + [A, bcol] = print2array(fig, 1, renderer); + [aa, aa, aa, bb_rel] = crop_borders(A, bcol, bb_padding, crop_amounts); %#ok + + try set(hTitles,'Color','k'); catch, end + + % 3. Calculate the new Bounding Box + pagew = pagebb_matlab(3)-pagebb_matlab(1); + pageh = pagebb_matlab(4)-pagebb_matlab(2); + %bb_new = [pagebb_matlab(1)+pagew*bb_rel(1) pagebb_matlab(2)+pageh*bb_rel(2) ... + % pagebb_matlab(1)+pagew*bb_rel(3) pagebb_matlab(2)+pageh*bb_rel(4)]; + bb_new = pagebb_matlab([1,2,1,2]) + [pagew,pageh,pagew,pageh].*bb_rel; % clearer + bb_offset = (bb_new-bb_matlab) + [-2,-2,2,2]; % 2px margin so that cropping is not TOO tight (issue #195) + + % Apply the bounding box padding + if bb_padding + if abs(bb_padding)<1 + bb_padding = round((mean([bb_new(3)-bb_new(1) bb_new(4)-bb_new(2)])*bb_padding)/0.5)*0.5; % ADJUST BB_PADDING + end + add_padding = @(n1, n2, n3, n4) sprintf(' %.0f', str2double({n1, n2, n3, n4}) + bb_offset + bb_padding*[-1,-1,1,1]); %#ok + else + add_padding = @(n1, n2, n3, n4) sprintf(' %.0f', str2double({n1, n2, n3, n4}) + bb_offset); %#ok % fix small but noticeable bounding box shift + end + fstrm = regexprep(fstrm, '%%BoundingBox:[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)', '%%BoundingBox:${add_padding($1, $2, $3, $4)}'); + end + + % Fix issue #44: white artifact lines appearing in patch exports + % Note: the problem is due to the fact that Matlab's print() function exports patches + % as a combination of filled triangles, and a white line appears where the triangles touch + % In the workaround below, we will modify such dual-triangles into a filled rectangle. + % We are careful to only modify regexps that exactly match specific patterns - it's better to not + % correct some white-line artifacts than to change the geometry of a patch, or to corrupt the EPS. + % e.g.: '0 -450 937 0 0 450 3 MP PP 937 0 0 -450 0 450 3 MP PP' => '0 -450 937 0 0 450 0 0 4 MP' + fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\2 \1 \3 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n'); + fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\2 \3 \1 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n'); + fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\3 \1 \2 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n'); + fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\3 \2 \1 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n'); + + % If user requested a regexprep replacement of string(s), do this now (issue #324) + if isstruct(export_options) && isfield(export_options,'regexprep') && ~isempty(export_options.regexprep) %issue #338 + try + oldStrOrRegexp = export_options.regexprep{1}; + newStrOrRegexp = export_options.regexprep{2}; + fstrm = regexprep(fstrm, oldStrOrRegexp, newStrOrRegexp); + catch err + warning('YMA:export_fig:regexprep', 'Error parsing regexprep: %s', err.message); + end + end + + % Write out the fixed eps file + read_write_entire_textfile(name, fstrm); + + drawnow; pause(0.01); +end + +function [StoredColors, fstrm, foundFlags] = eps_maintainAlpha(fig, fstrm, StoredColors) + if nargin == 1 % in: convert transparency in Matlab figure into unique RGB colors + hObjs = findall(fig); %findobj(fig,'Type','Area'); + StoredColors = {}; + propNames = {'Face','Edge'}; + for objIdx = 1:length(hObjs) + hObj = hObjs(objIdx); + for propIdx = 1 : numel(propNames) + try + propName = propNames{propIdx}; + if strcmp(hObj.(propName).ColorType, 'truecoloralpha') + oldColor = hObj.(propName).ColorData; + if numel(oldColor)>3 && oldColor(4)~=255 % issue #281: only fix patch/textbox color if it's not opaque + nColors = length(StoredColors); + newColor = uint8([101; 102+floor(nColors/255); mod(nColors,255); 255]); + StoredColors{end+1} = {hObj, propName, oldColor, newColor}; %#ok + hObj.(propName).ColorData = newColor; + end + end + catch + % Never mind - ignore (either doesn't have the property or cannot change it) + end + end + end + else % restore transparency in Matlab figure by converting back from the unique RGBs + %Find the transparent patches + wasError = false; + nColors = length(StoredColors); + foundFlags = false(1,nColors); + for objIdx = 1 : nColors + colorsData = StoredColors{objIdx}; + hObj = colorsData{1}; + propName = colorsData{2}; + origColor = colorsData{3}; + newColor = colorsData{4}; + try + %Restore the EPS files patch color + colorID = num2str(round(double(newColor(1:3)') /255,3),'%.3g %.3g %.3g'); %ID for searching + origRGB = num2str(round(double(origColor(1:3)')/255,3),'%.3g %.3g %.3g'); %Replace with original color + origAlpha = num2str(round(double(origColor(end)) /255,3),'%.3g'); %Convert alpha value for EPS + + %Find and replace the RGBA values within the EPS text fstrm + %Note: .setopacityalpha is an unsupported PS extension that croaks in some GS versions (issue #285, https://bugzilla.redhat.com/show_bug.cgi?id=1632030) + % (such cases are caught in eps2pdf.m and corrected by adding the -dNOSAFER Ghosscript option or by removing the .setopacityalpha line) + if strcmpi(propName,'Face') + oldStr = sprintf(['\n' colorID ' RC\n']); % ...N\n (removed to fix issue #225) + newStr = sprintf(['\n' origRGB ' RC\n' origAlpha ' .setopacityalpha true\n']); % ...N\n + else %'Edge' + oldStr = sprintf(['\n' colorID ' RC\n']); % ...1 LJ\n (removed to fix issue #225) + newStr = sprintf(['\n' origRGB ' RC\n' origAlpha ' .setopacityalpha true\n']); + end + foundFlags(objIdx) = ~isempty(strfind(fstrm, oldStr)); %#ok + fstrm = strrep(fstrm, oldStr, newStr); + + %Restore the figure object's original color + hObj.(propName).ColorData = origColor; + catch err + % something is wrong - cannot restore transparent color... + if ~wasError + fprintf(2, 'Error maintaining transparency in EPS file: %s\n at %s:%d\n', err.message, err.stack(1).file, err.stack(1).line); + wasError = true; + end + end + end + end +end diff --git a/matlab/C2xyz_v2/export_fig/read_write_entire_textfile.m b/matlab/C2xyz_v2/export_fig/read_write_entire_textfile.m new file mode 100644 index 0000000..9fabb22 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/read_write_entire_textfile.m @@ -0,0 +1,37 @@ +%READ_WRITE_ENTIRE_TEXTFILE Read or write a whole text file to/from memory +% +% Read or write an entire text file to/from memory, without leaving the +% file open if an error occurs. +% +% Reading: +% fstrm = read_write_entire_textfile(fname) +% Writing: +% read_write_entire_textfile(fname, fstrm) +% +%IN: +% fname - Pathname of text file to be read in. +% fstrm - String to be written to the file, including carriage returns. +% +%OUT: +% fstrm - String read from the file. If an fstrm input is given the +% output is the same as that input. + +function fstrm = read_write_entire_textfile(fname, fstrm) +modes = {'rt', 'wt'}; +writing = nargin > 1; +fh = fopen(fname, modes{1+writing}); +if fh == -1 + error('Unable to open file %s.', fname); +end +try + if writing + fwrite(fh, fstrm, 'char*1'); + else + fstrm = fread(fh, '*char')'; + end +catch ex + fclose(fh); + rethrow(ex); +end +fclose(fh); +end diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Extensions.type.Root/DependencyAnalysis.type.Extension/ExternalFiles.type.Extension.xml b/matlab/C2xyz_v2/export_fig/resources/project/Extensions.type.Root/DependencyAnalysis.type.Extension/ExternalFiles.type.Extension.xml new file mode 100644 index 0000000..91869b6 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Extensions.type.Root/DependencyAnalysis.type.Extension/ExternalFiles.type.Extension.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Project.xml b/matlab/C2xyz_v2/export_fig/resources/project/Project.xml new file mode 100644 index 0000000..4a9e34e --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Project.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/ProjectData.type.Info.xml b/matlab/C2xyz_v2/export_fig/resources/project/ProjectData.type.Info.xml new file mode 100644 index 0000000..de0b14e --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/ProjectData.type.Info.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category.xml new file mode 100644 index 0000000..ef38945 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/artifact.type.Label.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/artifact.type.Label.xml new file mode 100644 index 0000000..b56f659 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/artifact.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/convenience.type.Label.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/convenience.type.Label.xml new file mode 100644 index 0000000..5272801 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/convenience.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/derived.type.Label.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/derived.type.Label.xml new file mode 100644 index 0000000..5a873c8 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/derived.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/design.type.Label.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/design.type.Label.xml new file mode 100644 index 0000000..59cb0be --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/design.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/none.type.Label.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/none.type.Label.xml new file mode 100644 index 0000000..27ca3e7 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/none.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/other.type.Label.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/other.type.Label.xml new file mode 100644 index 0000000..14d104f --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/other.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/test.type.Label.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/test.type.Label.xml new file mode 100644 index 0000000..5a6f802 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/test.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/.gitignore.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/.gitignore.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/.gitignore.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/ImageSelection.class.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/ImageSelection.class.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/ImageSelection.class.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/ImageSelection.java.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/ImageSelection.java.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/ImageSelection.java.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/LICENSE.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/LICENSE.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/LICENSE.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/README.md.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/README.md.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/README.md.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/append_pdfs.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/append_pdfs.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/append_pdfs.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/copyfig.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/copyfig.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/copyfig.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/crop_borders.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/crop_borders.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/crop_borders.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/eps2pdf.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/eps2pdf.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/eps2pdf.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/export_fig.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/export_fig.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/export_fig.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/fix_lines.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/fix_lines.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/fix_lines.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/ghostscript.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/ghostscript.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/ghostscript.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/im2gif.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/im2gif.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/im2gif.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/isolate_axes.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/isolate_axes.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/isolate_axes.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/pdf2eps.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/pdf2eps.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/pdf2eps.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/pdftops.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/pdftops.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/pdftops.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/print2array.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/print2array.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/print2array.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/print2eps.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/print2eps.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/print2eps.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/read_write_entire_textfile.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/read_write_entire_textfile.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/read_write_entire_textfile.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/user_string.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/user_string.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/user_string.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/using_hg2.m.type.File.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/using_hg2.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.Files/using_hg2.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/Root.type.ProjectPath/a533e478-c90b-4a1f-a45b-f8877af57bee.type.Reference.xml b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.ProjectPath/a533e478-c90b-4a1f-a45b-f8877af57bee.type.Reference.xml new file mode 100644 index 0000000..59b7a5d --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/Root.type.ProjectPath/a533e478-c90b-4a1f-a45b-f8877af57bee.type.Reference.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/resources/project/uuid-cc21a9b0-026d-4b70-9821-3eb23d2abf81.xml b/matlab/C2xyz_v2/export_fig/resources/project/uuid-cc21a9b0-026d-4b70-9821-3eb23d2abf81.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/resources/project/uuid-cc21a9b0-026d-4b70-9821-3eb23d2abf81.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/C2xyz_v2/export_fig/user_string.m b/matlab/C2xyz_v2/export_fig/user_string.m new file mode 100644 index 0000000..315a675 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/user_string.m @@ -0,0 +1,117 @@ +function [string, file_name] = user_string(string_name, string) +%USER_STRING Get/set a user specific string +% +% Examples: +% string = user_string(string_name) +% isSaved = user_string(string_name, new_string) +% [value, file_name] = user_string(...) +% +% Function to get and set a string in a system or user specific file. This +% enables, for example, system specific paths to binaries to be saved. +% +% The specified string will be saved in a file named .txt, +% either in a subfolder named .ignore under this file's folder, or in the +% user's prefdir folder (in case this file's folder is non-writable). +% +% IN: +% string_name - String containing the name of the string required, which +% sets the filename storing the string: .txt +% new_string - The new string to be saved in the .txt file +% +% OUT: +% string - The currently saved string. Default: '' +% isSaved - Boolean indicating whether the save was succesful +% file_name - path of the .txt file used to contain the requested string + +% Copyright (C) Oliver Woodford 2011-2014, Yair Altman 2015- + +% This method of saving paths avoids changing .m files which might be in a +% version control system. Instead it saves the user dependent paths in +% separate files with a .txt extension, which need not be checked in to +% the version control system. Thank you to Jonas Dorn for suggesting this +% approach. + +% 10/01/2013 - Access files in text, not binary mode, as latter can cause +% errors. Thanks to Christian for pointing this out. +% 29/05/2015 - Save file in prefdir if current folder is non-writable (issue #74) +% 09/01/2018 - Fix issue #232: if the string looks like a file/folder path, ensure it actually exists +% 15/01/2020 - Added file_name output argument + + if ~ischar(string_name) + error('string_name must be a string.'); + end + % Create the full filename + fname = [string_name '.txt']; + dname = fullfile(fileparts(mfilename('fullpath')), '.ignore'); + file_name = fullfile(dname, fname); + default_file_name = file_name; + if nargin > 1 + % Set string + if ~ischar(string) + error('new_string must be a string.'); + end + % Make sure the save directory exists + %dname = fileparts(file_name); + if ~exist(dname, 'dir') + % Create the directory + try + if ~mkdir(dname) + string = false; + return + end + catch + string = false; + return + end + % Make it hidden + try + fileattrib(dname, '+h'); + catch + end + end + % Write the file + fid = fopen(file_name, 'wt'); + if fid == -1 + % file cannot be created/updated - use prefdir if file does not already exist + % (if file exists but is simply not writable, don't create a duplicate in prefdir) + if ~exist(file_name,'file') + file_name = fullfile(prefdir, fname); + fid = fopen(file_name, 'wt'); + end + if fid == -1 + string = false; + file_name = default_file_name; + return + end + end + try + fprintf(fid, '%s', string); + catch + fclose(fid); + string = false; + return + end + fclose(fid); + string = true; + else + % Get string + fid = fopen(file_name, 'rt'); + if fid == -1 + % file cannot be read, try to read the file in prefdir + file_name = fullfile(prefdir, fname); + fid = fopen(file_name, 'rt'); + if fid == -1 + string = ''; + file_name = default_file_name; + return + end + end + string = fgetl(fid); + fclose(fid); + + % Fix issue #232: if the string looks like a file/folder path, ensure it actually exists + if ~isempty(string) && any(string=='\' | string=='/') && ~exist(string) %#ok + string = ''; + end + end +end diff --git a/matlab/C2xyz_v2/export_fig/using_hg2.m b/matlab/C2xyz_v2/export_fig/using_hg2.m new file mode 100644 index 0000000..ba72228 --- /dev/null +++ b/matlab/C2xyz_v2/export_fig/using_hg2.m @@ -0,0 +1,36 @@ +%USING_HG2 Determine if the HG2 graphics engine is used +% +% tf = using_hg2(fig) +% +%IN: +% fig - handle to the figure in question. +% +%OUT: +% tf - boolean indicating whether the HG2 graphics engine is being used +% (true) or not (false). + +% 19/06/2015 - Suppress warning in R2015b; cache result for improved performance +% 06/06/2016 - Fixed issue #156 (bad return value in R2016b) + +function tf = using_hg2(fig) + persistent tf_cached + if isempty(tf_cached) + try + if nargin < 1, fig = figure('visible','off'); end + oldWarn = warning('off','MATLAB:graphicsversion:GraphicsVersionRemoval'); + try + % This generates a [supressed] warning in R2015b: + tf = ~graphicsversion(fig, 'handlegraphics'); + catch + tf = ~verLessThan('matlab','8.4'); % =R2014b + end + warning(oldWarn); + catch + tf = false; + end + if nargin < 1, delete(fig); end + tf_cached = tf; + else + tf = tf_cached; + end +end diff --git a/matlab/C2xyz_v2/html/C2xyz_documentation.html b/matlab/C2xyz_v2/html/C2xyz_documentation.html new file mode 100644 index 0000000..2c297bd --- /dev/null +++ b/matlab/C2xyz_v2/html/C2xyz_documentation.html @@ -0,0 +1,129 @@ + + + + + C2xyz

C2xyz

C2XYZ returns the x and y coordinates of contours in a contour matrix and their corresponding z values. C is the contour matrix given by the contour function.

Contents

Syntax

[x,y] = C2xyz(C)
+[x,y,z] = C2xyz(C)

Description

[x,y] = C2xyz(C) returns x and y cell arrays of coordinates of contours in a contour matrix C.

[x,y,z] = C2xyz(C) also returns corresponding z values as double.

Example

Given a contour plot, you want to know the (x,y) coordinates of the contours, as well as the z value corresponding to each contour line.

C = contour(peaks);
+[x,y,z] = C2xyz(C);
+

This returns 1 x numberOfContourLines cells of x values and y values, and their corresponding z values are given in a 1 x numberOfContourLines array. Let's pick out all the x, y locations where z = 0, and make that contour line a heavy black line:

hold on; % Allows plotting atop the preexisting peaks plot.
+
+for n = find(z==0); % only loop through the z = 0 values.
+    plot(x{n},y{n},'k','linewidth',2)
+end
+

And let's make all the z = -2 lines red and dotted:

for n = find(z==-2) % now loop through the z = -2 values.
+    plot(x{n},y{n},'r:','linewidth',2)
+end
+

Author Info

Created by Chad Greene, of the University of Texas Institute for Geophysics, August 2013. Updated August 2014.

\ No newline at end of file diff --git a/matlab/C2xyz_v2/html/C2xyz_documentation.png b/matlab/C2xyz_v2/html/C2xyz_documentation.png new file mode 100644 index 0000000..be13a9f Binary files /dev/null and b/matlab/C2xyz_v2/html/C2xyz_documentation.png differ diff --git a/matlab/C2xyz_v2/html/C2xyz_documentation_01.png b/matlab/C2xyz_v2/html/C2xyz_documentation_01.png new file mode 100644 index 0000000..55ef7ed Binary files /dev/null and b/matlab/C2xyz_v2/html/C2xyz_documentation_01.png differ diff --git a/matlab/C2xyz_v2/html/C2xyz_documentation_02.png b/matlab/C2xyz_v2/html/C2xyz_documentation_02.png new file mode 100644 index 0000000..67480e4 Binary files /dev/null and b/matlab/C2xyz_v2/html/C2xyz_documentation_02.png differ diff --git a/matlab/C2xyz_v2/html/C2xyz_documentation_03.png b/matlab/C2xyz_v2/html/C2xyz_documentation_03.png new file mode 100644 index 0000000..94202a4 Binary files /dev/null and b/matlab/C2xyz_v2/html/C2xyz_documentation_03.png differ diff --git a/matlab/CheckAxialConfinement.m b/matlab/CheckAxialConfinement.m index 448cd07..43e0b27 100644 --- a/matlab/CheckAxialConfinement.m +++ b/matlab/CheckAxialConfinement.m @@ -1,113 +1,121 @@ t2dlength=size(M.t2d,1); tstep=t2dlength-1; model=M.potentialwellmodel(tstep); model2=M.potentialwellmodel(0); N=M.N(:,:,tstep); N(M.geomweight(:,:,1)<0)=0; -% figure -% contourf(M.zgrid,M.rgrid,N); -% xlabel('z [m]') -% ylabel('r [m]') -% [x,y]=ginput(1); -% zpos=find(x>M.zgrid,1,'last'); -% rpos=find(y>M.rgrid,1,'last'); -rpos=68; -zpos=285; +figure +contourf(M.zgrid,M.rgrid,N); +hold on +contour(M.zgrid,M.rgrid,M.geomweight(:,:,1),[0 0], 'r') +xlabel('z [m]') +ylabel('r [m]') +[x,y]=ginput(1); +zpos=find(x>M.zgrid,1,'last'); +rpos=find(y>M.rgrid,1,'last'); +% rpos=68; +% zpos=285; + rAthet_pos=M.rAthet(rpos,zpos); %% Psieval=rAthet_pos*ones(M.nz+1,1); Zeval=M.zgrid; +%Thermal velocity of creation %vpar0=sqrt(M.kb*22000/M.msim*M.weight); +%fluid %vpar0=M.fluidUZ(rpos,zpos,t2dlength); + vpar0=sqrt(2/M.me*M.fluidEkin(3,rpos,zpos,tstep)); -vperp0=sqrt(2/M.me*M.fluidEkin(2,rpos,zpos,tstep)); +%% average kinetic energy +%vperp0=sqrt(2/M.me*M.fluidEkin(2,rpos,zpos,tstep)); +%% ExB energy +vperp0=(M.Ez(rpos,zpos,tstep)*M.Br(zpos,rpos)-M.Er(rpos,zpos,tstep)*M.Bz(zpos,rpos))/M.B(zpos,rpos)^2; %rdisp=sort(unique([M.rAthet(:,end);M.rAthet(end,:)])); [Zmesh,Rmesh]=meshgrid(M.zgrid,M.rgrid); pot=griddata(model.z,model.rathet,model.pot,Zeval,Psieval); potxt=griddata(model2.z,model2.rathet,model2.pot,Zeval,Psieval); [Zinit,~]=meshgrid(M.zgrid,M.rAthet(:,1)); N0=griddata(Zinit,M.rAthet,N,Zeval,Psieval); -pot=pot;%+min(pot); -potxt=potxt;%+min(pot); + % Magnetic field mirror ratio at each grid position % compared to local position R=griddata(Zmesh,M.rAthet,M.B',Zeval,Psieval,'natural')/M.B(zpos,rpos); R=(R-1)*3+1; % Electrostatic potential on magnetic field line % coordinates phis=griddata(Zmesh,M.rAthet,M.pot(:,:,tstep),Zeval,Psieval,'natural')-M.pot(rpos,zpos,tstep); rposline=griddata(Zmesh,M.rAthet,Rmesh,Zeval,Psieval,'natural'); %% f=figure('Name','Axial conf'); subplot(2,1,1) contourf(M.zgrid*1e3,M.rgrid*1e3,N,'edgecolor','none') hold on plot(M.zgrid(zpos)*1e3,M.rgrid(rpos)*1e3,'rx') plot(Zeval*1e3,rposline*1e3,'r--') contour(M.zgrid*1e3,M.rgrid*1e3,M.geomweight(:,:,1),[0 0],'w-.','linewidth',1.5,'Displayname','Vessel Boundaries'); totpot=M.pot(:,:,tstep); totpot(M.geomweight(:,:,1)<0)=0; [c1,h2]=contour(M.zgrid*1e3,M.rgrid*1e3,totpot./1e3,'m--','ShowText','On','linewidth',1.2,'Displayname','Equipotentials [kV]'); %clabel(c1,h2,'Color','white'); clabel(c1,h2,'Color','white'); %ylim([0.077 0.081]) xlabel('z [m]') ylabel('r [m]') c=colorbar; c.Label.String='n [m^{-3}]'; set(gca,'fontsize',12); drawnow; texth=h2.TextPrims; for i=1:length(texth) a=texth(i).String; y=char(sprintf('%1.2fkV',str2double(a))); h2.TextPrims(i).String=y; end % subplot(3,1,2) % plot(M.zgrid*1e3,pot-pot(zpos),'displayname','total well') % hold on % plot(M.zgrid*1e3,potxt-potxt(zpos),'displayname','external well') % ylabel('-e\Delta\phi [eV]') % yyaxis right % plot(M.zgrid,N0,'displayname','density') % ylabel('n [m^{-3}]') % xlabel('z [m]') % grid on % set(gca,'fontsize',12); % legend('location','northwest') subplot(2,1,2) %EparB=0.5*M.msim/M.weight*((M.Ez(rpos,zpos,tstep)*M.Br(zpos,rpos)-M.Er(rpos,zpos,tstep)*M.Bz(zpos,rpos))/M.B(zpos,rpos)^2)^2*(1-R)/M.qe; EparB=0.5*M.msim/M.weight*(vperp0)^2*(1-R)/M.qe; Eparphi=-M.qsim/M.weight*phis/M.qe; Epar=EparB+Eparphi+0.5*M.msim/M.weight/M.qe*vpar0^2; plot(M.zgrid,Epar,'displayname','E_{par,tot}') hold on plot(M.zgrid,EparB,'displayname','\DeltaE_{par,mag}') plot(M.zgrid,Eparphi,'displayname','\DeltaE_{par,elec}') plot(M.zgrid,0.5*M.msim/M.weight*(vpar0^2)/M.qe*ones(size(M.zgrid)),':','displayname','E_{par,0}') grid on xlabel('z [m]') ylabel('E_{par} [eV]') legend('location','north','NumColumns',3) yyaxis right plot(M.zgrid,R,'displayname','R') ylabel('R=B(s)/B(0)') %ylim(1000*[-1 1]) set(gca,'fontsize',12); M.savegraph(f,sprintf('%s/%s_Ax_confR%dZ%d_tweaked',M.folder,M.name,rpos,zpos),[12,20]) \ No newline at end of file diff --git a/matlab/DensityVideosaving.m b/matlab/DensityVideosaving.m index 3c37950..0e284b0 100644 --- a/matlab/DensityVideosaving.m +++ b/matlab/DensityVideosaving.m @@ -1,114 +1,161 @@ +% Create a video showing the time evolution of the electron cloud density +% and the equipotential lines +% Draws on top the metallic geometry and the magnetic field lines +% Set the starting and ending time frames initfieldstep=1; +tend=length(M.t2d);%1000;%length(M.t2d);%min(60000,length(M.t2d)); +% set the timestep of drawing +step=2; -maxN=3e17; -tend=4700;%length(M.t2d);%min(60000,length(M.t2d)); -%tend=length(M.t2d); +% defines the upper limit of the color scale +maxN=2.5e17; +minN=5e12; -filename=[M.name,'_dens_log.avi']; +%prepare the video writer parameters +filename=[M.name,'_dens_log_presentation.avi']; videowriterobj=VideoWriter([M.folder,'/',filename]); -videowriterobj.FrameRate=20; +videowriterobj.FrameRate=50; videowriterobj.Quality=90; open(videowriterobj); -step=5; +tsize=20; + +if M.neutcol.present + vexb0=(M.Ez(:,:,1).*M.Br'-M.Er(:,:,1).*M.Bz')./(M.B'.^2); + vexb0(M.geomweight(:,:,1)<=0)=0; + E=0.5*M.msim/M.weight*mean(abs(vexb0(:)))^2/M.qe; + taucol=1/(M.neutcol.neutdens*mean(abs(vexb0(:)))*(M.sigio(E)+M.sigmela(E)+M.sigmio(E))); + try + Sio_S=1e17*(M.neutcol.neutdens*mean(abs(vexb0(:)))*M.sigio(E))/(M.maxwellsrce.frequency*M.weight/(pi*(M.maxwellsrce.rlim(2)^2-M.maxwellsrce.rlim(1)^2)*diff(M.maxwellsrce.zlim))) + catch + end + tlabel='\tau_d'; +else + taucol=2*pi/M.omece; + tlabel='\tau_ce'; +end + + %% Fields f=figure('Name', sprintf('%s fields',M.name),'Position',[0 0 1600 900]); ax1=gca; +% extract and plot the initial density dens=M.N(:,:,initfieldstep); dispdens=dens; colormap(flipud(hot)); geomw=M.geomweight(:,:,1); -%geomw(geomw>0)=1; -%geomw(geomw<=0)=0; dispdens(geomw<=0)=0; -Nlvls=logspace( log10(1e12), log10(maxN),50); +Nlvls=logspace( log10(minN), log10(maxN),50); +%Nlvls=linspace(1e12,maxN,50); [h,curve]=contourf(ax1,M.zgrid*1000,M.rgrid*1000,dispdens,Nlvls,'Displayname','n_e [m^{-3}]'); set(curve,'linecolor','none'); colormap(flipud(hot)); hold on; -pot=M.pot(:,:,initfieldstep); -pot(geomw<1e-4)=NaN; + +% Draws the magnetic field lines Blines=M.rAthet; levels=linspace(min(Blines(M.geomweight(:,:,1)>0)),max(Blines(M.geomweight(:,:,1)>0)),20); Blines(M.geomweight(:,:,1)<0)=NaN; [~,h1]=contour(ax1,M.zgrid*1000,M.rgrid*1000,Blines,real(levels),'-.','color','k','linewidth',1.5,'Displayname','Magnetic field lines'); + +% extract and draw the equipotentials +pot=M.pot(:,:,initfieldstep); +pot(geomw<1e-4)=NaN; pot(geomw<0)=NaN; potcolor='b'; -[c1,h2]=contour(ax1,M.zgrid*1000,M.rgrid*1000,pot/1e3,0:-5:-20,'--','color',potcolor,'ShowText','on','linewidth',1.2,'Displayname','Equipotentials [kV]'); -clabel(c1,h2,'Color',potcolor,'fontsize',14) - -%contour(ax1,M.zgrid*1000,M.rgrid*1000,M.geomweight(:,:,1),[0 0],'w-','linewidth',1.5); +[c1,h2]=contour(ax1,M.zgrid*1000,M.rgrid*1000,pot/1e3,'--','color',potcolor,'ShowText','on','linewidth',1.2,'Displayname','Equipotentials [kV]'); +clabel(c1,h2,'Color',potcolor,'fontsize',tsize,'LabelSpacing',800) +% Draw the metallic boundaries and the geometry itself [c1,hContour]=contourf(ax1,M.zgrid*1000,M.rgrid*1000,-geomw,[0,0],'linewidth',1.5); drawnow; xlim(ax1,[M.zgrid(1)*1000 M.zgrid(end)*1000]) if(M.conformgeom) ylim(ax1,[M.rgrid(1)*1000 M.rgrid(rgridend)*1000]) else ylim(ax1,[M.rgrid(1)*1000 M.rgrid(end)*1000]) end + +% Add the legend and labels legend([h1,h2],{'Magnetic field lines','Equipotentials [kV]'},'location','southwest') xlabel(ax1,'z [mm]') ylabel(ax1,'r [mm]') -%title(ax1,sprintf('Density t=[%1.2g-%1.2g]s n_e=%1.2gm^{-3}',M.t2d(fieldstart),M.t2d(fieldend),double(maxdens))) c = colorbar(ax1); -c.Label.String= 'n[m^{-3}]'; +c.Label.String= 'Electron density [m^{-3}]'; view(ax1,2) -%set(h,'edgecolor','none'); grid on; -set(ax1,'fontsize',14); +set(ax1,'fontsize',tsize); + +% Change the color of the metallic boundaries to grey hFills=hContour.FacePrims; [hFills.ColorType] = deal('truecoloralpha'); % default = 'truecolor' try hFills(end).ColorData = uint8([150;150;150;255]); for idx = 1 : numel(hFills)-1 hFills(idx).ColorData(4) = 0; % default=255 end catch end -%rectangle('Position',[M.zgrid(1) M.rgrid(1)-2e-4 M.zgrid(end)-M.zgrid(1) 2e-4]*1000,'FaceColor',[150 150 150]/255) -%rectangle('Position',[M.zgrid(1) M.rgrid(end) M.zgrid(end)-M.zgrid(1) 2e-4]*1000,'FaceColor',[150 150 150]/255) -sgtitle(f,sprintf('t= %1.2f [ns]',M.t2d(initfieldstep)*1e9)) + +% if necessary extend the display of the inner and outer cylinders +if(M.walltype~=9) +rectangle('Position',[M.zgrid(1)-2e-4 M.rgrid(1)-3e-4 M.zgrid(end)-M.zgrid(1)+4e-4 3e-4]*1000,'FaceColor',[150 150 150]/255,'linewidth',1.5) +rectangle('Position',[M.zgrid(1) M.rgrid(end) M.zgrid(end)-M.zgrid(1) 2e-4]*1000,'FaceColor',[150 150 150]/255,'EdgeColor','none') +ylim([M.rgrid(1)-2e-4 M.rgrid(end)+2e-4]*1000) +end +%rectangle('Position',[M.zgrid(1) M.rgrid(1) 0.06-M.zgrid(1) 0.06-M.rgrid(1)]*1000,'FaceColor',[150 150 150]/255,'EdgeColor','none') + +% give the time in the title +title(sprintf('t= %1.2f [ns]',M.t2d(initfieldstep)*1e9)) + + % if isfield(M.maxwellsrce,'time_start') && M.maxwellsrce.time_start<=M.t2d(1) % rectangle('Position',[M.maxwellsrce.zlim(1) M.maxwellsrce.rlim(1) diff(M.maxwellsrce.zlim) diff(M.maxwellsrce.rlim)]*1000,'linestyle','--') % end +%Adapt the color axis limits and set log scale set(ax1,'ColorScale','log') -ylim([M.rgrid(1)-2e-4 M.rgrid(end)+2e-4]*1000) - caxis([Nlvls(1) Nlvls(end)]); + + + +% Run the loop to update the electric potential and electron density for i=initfieldstep:step:tend - sgtitle(f,sprintf('t= %1.2f [ns]',M.t2d(i)*1e9)) + title(ax1,sprintf('t= %1.2f %s',M.t2d(i)/taucol,tlabel),'fontsize',tsize-2) dens=M.N(:,:,i); dispdens=dens; dispdens(geomw<=0)=0; pot=M.pot(:,:,i)./1e3; pot(geomw<1e-4)=NaN; curve.ZData=dispdens; h2.ZData=pot; caxis(ax1,[Nlvls(1) Nlvls(end)]); %Curve2.YData=pot(rAthetpos,1:end); + + drawnow; hFills=hContour.FacePrims; [hFills.ColorType] = deal('truecoloralpha'); % default = 'truecolor' try hFills(1).ColorData = uint8([150;150;150;255]); for idx = 2 : numel(hFills) hFills(idx).ColorData(4) = 0; % default=255 end catch end writeVideo(videowriterobj,getframe(f)); end + + close(videowriterobj); \ No newline at end of file diff --git a/matlab/DiocotronStability.m b/matlab/DiocotronStability.m index b936cbe..fcd054c 100644 --- a/matlab/DiocotronStability.m +++ b/matlab/DiocotronStability.m @@ -1,45 +1,41 @@ rbm=0.005; rbp=0.0128; -rbm=0.09; -rbp=0.011; -rbm=0.09; -rbp=0.11; -% b=0.16; -% a=0.001; +%rbm=0.09; +%rbp=0.113; +%b=0.16; +%a=0.001; a=M.rgrid(1); b=M.rgrid(end); Q=mean(M.Er(1,floor(length(M.zgrid)/2),end-30:end),3)/2*a; %Q=mean(M.Er(1,100,end-30:end),3)/2*a; -Q=-(M.potout-M.potinn)*M.phinorm/(2*log(a/b)); -omepe=sqrt(9.92e14*M.qe^2/M.eps_0/M.me); -omega_d=omepe^2/(2*M.omece); +omega_d=M.omepe^2/(2*M.omece); if( a~=0) - omega_q=-2*Q/(M.B0*(rbm^2)); + omega_q=2*Q/(M.B0*(rbm^2)); else omega_q=0; end Levaluated=10; stability=zeros(Levaluated,1); for l=1:Levaluated stability(l)=(-l*(1-omega_q/omega_d)*(1-(rbm/rbp)^2)*(1-(a/b)^(2*l))+ ... 2*(1+(a/b)^(2*l))-(1+(rbm/rbp)^(2*l))*((a/rbm)^(2*l)+(rbp/b)^(2*l)))^2 -... 4*(rbm/rbp)^(2*l)*(1-(rbp/b)^(2*l))^2*(1-(a/rbm)^(2*l))^2; if(stability(l) <0) fprintf(2,"Diocotron mode l=%d is potentially unstable\n",l); end end fig=figure; plot(1:Levaluated,stability) hold on plot([1 Levaluated],[0 0],'k') for l=1:Levaluated if stability(l)<0 plot(l,stability(l),'rx') end end xlabel('azimuthal mode number') ylabel('stability condition') title(sprintf('r_b^-=%1.2g [m] r_b^+=%1.2g [m] a=%1.2g [m] b=%1.2g [m]',rbm,rbp,a,b)) M.savegraph(fig,sprintf('%s/%s_diocstab',M.folder,M.name),[15,10]) \ No newline at end of file diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Mat88_Cryogenic_170.m b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Mat88_Cryogenic_170.m new file mode 100644 index 0000000..5adddf6 --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Mat88_Cryogenic_170.m @@ -0,0 +1,136 @@ + function [M,gamma,delta] = B_Mat88_Cryogenic_170(magnet) +% +% Call: [M,gamma,delta] = B_Mat88_Cryogenic_170(Magnet) +% Example: >> [M,gamma,delta] = B_Mat88_Cryogenic_170('toto'); +% +% Version : 1.0 J.-P. Hogge Aug. 3rd, 2017 +% largely based on B_Matrix_170.m +% +% Magnetic field matrix associated with GT170 GHz Cryogenic magnet. +% This a set of coefficient such that their scalar product with the +% currents provided by the power supplies should be < 0 to avoid +% interception. The gamma parameters correspond to the case where magnetici +% flux conservation is used, whereas the delty parameters are based on the +% vector potential A_phi. +% +% +% +% B_gun M(1,1) M(1,2) M(1,3) M(1,4) M(1,5) I1 +% = * +% B_cavity M(2,1) M(2,2) M(2,3) M(2,4) M(2,5) I2 +% +% dBz/dz_gun M(3,1) M(3,2) M(3,3) M(3,4) M(3,5) I3 +% +% B_launcher M(4,1) M(4,2) M(4,3) M(4,4) M(4,5) I4 +% +% +% with currents I1, I2, -I3, I4 flowing in the 4 power supplies +% + +% GT170 1MW first prototype (TH1509) geometry +% + z_shim = 0.00; + + z_cat_design = 0.1335; % corresponds to the LARGEST emitter radius, + % not the average one. + z_cav_design = 0.4995; % cavity center position + z_launcher_d = 0.78848; % launcher edge + + z_cat = z_cat_design + z_shim; + z_cav = z_cav_design + z_shim; + z_launcher = z_launcher_d + z_shim; + + r_cat = 0.05419; % largest emitter radius + r_launcher = 0.02068; % launcher radius + + + + +% r = [0 0 0 0] % If one decides to use on-axis values + r = [0 0 0 r_launcher] % If one decides to use more stringent values + + rphi = [r_cat 0 r_cat r_launcher] % check with vector potential + z = [z_cat z_cav z_cat z_launcher] + + +% this script is specially dedicated to the 170GHz Cryogenic magnet... + magnet = 'cryogenic' ; + disp(sprintf('Aimant : %s',magnet)) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% + [B] = B_Ellip_Cryogenic_170('bz' ,magnet,[1 0 0 0],r,z); + [DB] = B_Ellip_Cryogenic_170('dbzdz' ,magnet,[1 0 0 0],r,z); + [D2B] = B_Ellip_Cryogenic_170('d2bzdz2',magnet,[1 0 0 0],r,z); + [Aphi] = B_Ellip_Cryogenic_170('aphi', magnet,[1 0 0 0],rphi,z); + + column = 1; + M(1,column) = B(1) ; M(2,column) = B(2); M(3,column)=DB(1); M(4,column)=B(4); + + aphig(column) = Aphi(1); + aphil(column) = Aphi(4); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% + [B] = B_Ellip_Cryogenic_170('bz' ,magnet,[0 1 0 0],r,z); + [DB] = B_Ellip_Cryogenic_170('dbzdz' ,magnet,[0 1 0 0],r,z); + [D2B] = B_Ellip_Cryogenic_170('d2bzdz2',magnet,[0 1 0 0],r,z); + [Aphi] = B_Ellip_Cryogenic_170('aphi', magnet,[0 1 0 0],rphi,z); + + + column = 2; + M(1,column) = B(1) ; M(2,column) = B(2); M(3,column)=DB(1); M(4,column)=B(4); + + aphig(column) = Aphi(1); + aphil(column) = Aphi(4); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% + [B] = B_Ellip_Cryogenic_170('bz' ,magnet,[0 0 1 0],r,z); + [DB] = B_Ellip_Cryogenic_170('dbzdz' ,magnet,[0 0 1 0],r,z); + [D2B] = B_Ellip_Cryogenic_170('d2bzdz2',magnet,[0 0 1 0],r,z); + [Aphi] = B_Ellip_Cryogenic_170('aphi', magnet,[0 0 1 0],rphi,z); + + column = 3; + M(1,column) = B(1) ; M(2,column) = B(2); M(3,column)=DB(1); M(4,column)=B(4); + + aphig(column) = Aphi(1); + aphil(column) = Aphi(4); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% + [B] = B_Ellip_Cryogenic_170('bz' ,magnet,[0 0 0 1],r,z); + [DB] = B_Ellip_Cryogenic_170('dbzdz' ,magnet,[0 0 0 1],r,z); + [D2B] = B_Ellip_Cryogenic_170('d2bzdz2',magnet,[0 0 0 1],r,z); + [Aphi] = B_Ellip_Cryogenic_170('aphi', magnet,[0 0 0 1],rphi,z); + + column = 4; + M(1,column) = B(1) ; M(2,column) = B(2); M(3,column)=DB(1); M(4,column)=B(4); + + aphig(column) = Aphi(1); + aphil(column) = Aphi(4); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + disp(sprintf(' Bz_gun %f %f %f %f I1 ', M(1,1), M(1,2), M(1,3), M(1,4))) + disp(sprintf(' Bz_cav %f %f %f %f I2 ', M(2,1), M(2,2), M(2,3), M(2,4))) + disp(sprintf(' dBzdz_gun %f %f %f %f I3 ', M(3,1), M(3,2), M(3,3), M(3,4))) + disp(sprintf(' Bz_launcher %f %f %f %f I4 ', M(4,1), M(4,2), M(4,3), M(4,4))) + + gamma = [0 0 0 0]; + delta = [0 0 0 0]; + + for i=1:4 + gamma(i) = M(1,i) - (r_launcher/r_cat)^2 * M(4,i); + delta(i) = aphig(i) - (r_launcher/r_cat) * aphil(i) + end + disp(' ') + format long + disp(sprintf(' gamma %f %f %f %f ',gamma(1), gamma(2), gamma(3), gamma(4))) + disp(sprintf(' delta %f %f %f %f ',delta(1), delta(2), delta(3), delta(4))) + + + return diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Mat88_Cryogenic_170_test.m b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Mat88_Cryogenic_170_test.m new file mode 100644 index 0000000..c63b9fc --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Mat88_Cryogenic_170_test.m @@ -0,0 +1,72 @@ +% This script tests the coefficients of the matrix found by +% 'B_Mat88_Cryogenic_170 +% +% JHE, July 31st, 2017 +% + + I= 100*[0.57712 , 0.68596 , 1.07780 , 1.07780] ; % Nominal currents used on MAy 29th, 2017 to apply first SP pulses + + +% r_cat_min = 0.05419; % largest emitter radius of first prototype 170GHz 1MW +% r_launcher = 0.02068; % launcher radius +% +% z_cat_min = 0.1335; +% z_launcher = 0.78848; + + +% Include GT170 Geometry + + GT170_1MW_Geometry + +% +% Taking parameters defined with on-axis fields + %gamma = [0.002933681588584, -0.006273546452915, -0.007626766134967, 0.009858220586519]; + +% Taking more stringent condition (on axis field at gun, off-axis field at launcher +% gamma = [ 0.00293370270241, -0.00627361773021, -0.00762699351991 , 0.00987214759867]; + +% Taking parameters defined with potential vector (defined as delta in +% B_Matrix_Cryogenic_170, with another factor 1000 omitted + gamma = [0.081474637274171, -0.174106309671082, -0.203575059328030, 0.260894824884893]; + + + z = linspace(z_launcher-0.01,z_launcher+0.01,41); + r = linspace(0.015, 0.030,16); + [Z,R] = meshgrid(z,r); + + [aphi_cat] = B_Ellip_Cryogenic_170('aphi','cryogenic',I,r_cat_min,z_cat_min); + raphi_cat = r_cat_min * aphi_cat; + + [Aphi] = B_Ellip_Cryogenic_170('aphi','cryogenic',I,R,Z); + RAphi = R.*Aphi; + + figure(1) + contour(Z,R,RAphi,[raphi_cat raphi_cat],'--','LineWidth',2) + + + hold on + + I(4) = I(4) + 10; + [aphi_cat] = B_Ellip_Cryogenic_170('aphi','cryogenic',I,r_cat_min,z_cat_min); + raphi_cat = r_cat_min * aphi_cat; + + [Aphi] = B_Ellip_Cryogenic_170('aphi','cryogenic',I,R,Z); + RAphi = R.*Aphi; + + figure(1) + contour(Z,R,RAphi,[raphi_cat raphi_cat],'-.','LineWidth',2) + + + I4lim = - (gamma(1) * I(1) +gamma(2)*I(2) +gamma(3)*I(3)) / gamma(4) + + I(4) = I4lim; + [aphi_cat] = B_Ellip_Cryogenic_170('aphi','cryogenic',I,r_cat_min,z_cat_min); + raphi_cat = r_cat_min * aphi_cat; + + [Aphi] = B_Ellip_Cryogenic_170('aphi','cryogenic',I,R,Z); + RAphi = R.*Aphi; + + figure(1) + contour(Z,R,RAphi,[raphi_cat raphi_cat],'LineWidth',2) + plot(z_launcher,r_launcher,'r*') + \ No newline at end of file diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Matrix_Cryogenic_170.m b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Matrix_Cryogenic_170.m new file mode 100644 index 0000000..e9722bf --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Matrix_Cryogenic_170.m @@ -0,0 +1,111 @@ + function [M] = B_Matrix_Cryogenic_170(magnet) +% +% Call: [M] = B_Matrix_Cryogenic_170(Magnet) +% Example: >> [M] = B_Matrix_Cryogenic_170('asg_modified_201206'); +% +% Version : 1.0 J.-P. Hogge Mar. 27, 2008 +% 1.1 J.-P. Hogge Nov. 23, 2011, Changet Cathode parameters to refurbished first prototype +% +% +% Magnetic field matrix associated with GT170 GHz magnet. +% This scripts determines quantities M(1,1)...M(4,4) such that +% +% +% B_gun M(1,1) M(1,2) M(1,3) M(1,4) M(1,5) I1 +% = * +% B_cavity M(2,1) M(2,2) M(2,3) M(2,4) M(2,5) I2 +% +% dBz/dz_gun M(3,1) M(3,2) M(3,3) M(3,4) M(3,5) I3 +% +% dBz/dz_cav M(4,1) M(4,2) M(4,3) M(4,4) M(4,5) I4 +% +% +% with currents I1, -I2, -I3, I4 flowing in the 4 power supplies +% + +% GT170 1MW first prototype (TH1509) geometry +% % +% z_shim = 0.00; +% +% z_cat_design = 0.136; % emitter radius AT CENTER +% z_cav_design = 0.4995; % cavity center position +% z_launcher_d = 0.78848; % launcher edge +% +% z_cat = z_cat_design + z_shim; +% z_cav = z_cav_design + z_shim; +% z_launcher = z_launcher_d + z_shim; +% +% r_cat = 0.053369; % emitter radius AT CENTER, WARM CONDITION +% r_launcher = 0.02068; % launcher radius + +% Include GT170 Geometry + + GT170_1MW_Geometry +% +% + r = [0 0 ] % + z = [z_cat z_cav ] + + +% this script is specially dedicated to the 170GHz Cryogenic magnet... +%%%% JHE 2018_11_27 magnet = 'cryogenic' + disp(sprintf('Aimant : %s',magnet)) + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% + [B] = B_Ellip_Cryogenic_170('bz' ,magnet,[1 0 0 0],r,z); + [DB] = B_Ellip_Cryogenic_170('dbzdz' ,magnet,[1 0 0 0],r,z); + [D2B] = B_Ellip_Cryogenic_170('d2bzdz2',magnet,[1 0 0 0],r,z); + + column = 1; + M(1,column) = B(1) ; M(2,column) = B(2); M(3,column)=DB(1); M(4,column)=DB(2); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% + [B] = B_Ellip_Cryogenic_170('bz' ,magnet,[0 1 0 0],r,z); + [DB] = B_Ellip_Cryogenic_170('dbzdz' ,magnet,[0 1 0 0],r,z); + [D2B] = B_Ellip_Cryogenic_170('d2bzdz2',magnet,[0 1 0 0],r,z); + + column = 2; + M(1,column) = B(1) ; M(2,column) = B(2); M(3,column)=DB(1); M(4,column)=DB(2); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% + [B] = B_Ellip_Cryogenic_170('bz' ,magnet,[0 0 1 0],r,z); + [DB] = B_Ellip_Cryogenic_170('dbzdz' ,magnet,[0 0 1 0],r,z); + [D2B] = B_Ellip_Cryogenic_170('d2bzdz2',magnet,[0 0 1 0],r,z); + + column = 3; + M(1,column) = B(1) ; M(2,column) = B(2); M(3,column)=DB(1); M(4,column)=DB(2); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% + [B] = B_Ellip_Cryogenic_170('bz' ,magnet,[0 0 0 1],r,z); + [DB] = B_Ellip_Cryogenic_170('dbzdz' ,magnet,[0 0 0 1],r,z); + [D2B] = B_Ellip_Cryogenic_170('d2bzdz2',magnet,[0 0 0 1],r,z); + + column = 4; + M(1,column) = B(1) ; M(2,column) = B(2); M(3,column)=DB(1); M(4,column)=DB(2); + + +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% [B] = B_Ellip_170('bz' ,magnet,[0 0 0 0 1],r,z); +% [DB] = B_Ellip_170('dbzdz' ,magnet,[0 0 0 0 1],r,z); +% [D2B] = B_Ellip_170('d2bzdz2',magnet,[0 0 0 0 1],r,z); +% +% column = 5; +% M(1,column) = B(1) ; M(2,column) = B(2); M(3,column)=DB(1); M(4,column)=DB(2); M(5,column)=D2B(1); +% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + disp(sprintf(' Bz_gun %f %f %f %f I1 ', M(1,1), M(1,2), M(1,3), M(1,4))) + disp(sprintf(' Bz_cav %f %f %f %f I2 ', M(2,1), M(2,2), M(2,3), M(2,4))) + disp(sprintf(' dBzdz_gun %f %f %f %f I3 ', M(3,1), M(3,2), M(3,3), M(3,4))) + disp(sprintf(' dBzdz_cav %f %f %f %f I4 ', M(4,1), M(4,2), M(4,3), M(4,4))) + + return diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Params_Cryogenic_170.m b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Params_Cryogenic_170.m new file mode 100644 index 0000000..7ceb830 --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Params_Cryogenic_170.m @@ -0,0 +1,73 @@ + function B_Params_Cryogenic_170(magnet,I) +% +% Call: B_Params_Cryogenic_170(magnet,I) +% Example: >> B_Params_Cryogenic_170('cryogenic',[61.56 66.45 113.43 108.09 ]); +% +% +% +% Returns magnetic field and beam parameters associated to the GT140 GHz magnet +% +% Version : 1.0 J.-P. Hogge Oct. 08, 2002 +% 1.1 J.-P. Hogge Feb 3, 2005 Changed Call (Current in array I) +% +% magnet : 'oxf_1' only so far +% I : Array of coil currents as read on power supply [A] + + +% z_shim = 0.00; +% % z_cat_design = 0.1185; % First prototype (2008) +% z_cat_design = 0.1225; % Refurbished First prototype (2011) +% +% z_cav_design = 0.4995; +% z_cat = z_cat_design + z_shim; +% z_cav = z_cav_design + z_shim; +% % r_cat = 0.057; % First prototype (2008) +% r_cat = 0.059; % Refurbished First prototype (2011) +% % Note Value given by C.Li?vin on 2011.11.23 +% % by e-mail: Mesure ? froid #20?C : 58,705mm +% % diam?tre ? chaud : 58,705*(1+5.10-6*930)=58,978mm + +% Include GT170 Geometry + + GT170_1MW_Geometry + + + r = [ 0 r_cat 0]; + z = [z_cat z_cat z_cav]; + +% 'bz','br','dbzbz','dbzdr','dbrdz','dbrdr', 'd2bzdz2' or 'aphi' + + Bz = B_Ellip_Cryogenic_170('bz', magnet,I,r,z); + dBzdz = B_Ellip_Cryogenic_170('dbzdz', magnet,I,r,z); + d2Bzdz = B_Ellip_Cryogenic_170('d2bzdz2', magnet,I,r,z); + Br = B_Ellip_Cryogenic_170('br', magnet,I,r,z); + aphi = B_Ellip_Cryogenic_170('aphi', magnet,I,r,z); + + r_beam = r_beam_Cryogenic_170(magnet,I); + + disp(' ') + disp(' ') + disp(sprintf('Cathode magnetic field on axis (r=0) : %2.5f [T]',Bz(1))) + disp(sprintf('Cathode magnetic field at r=r_cat : %2.5f [T]',Bz(2))) + disp(sprintf('Cavity magnetic field : %2.5f [T]',Bz(3))) + disp(' ') + disp(sprintf('Cathode magnetic field derivative on axis (r=0) : %2.5f [T/m]',dBzdz(1))) + disp(sprintf('Cathode magnetic field derivative at r=r_cat : %2.5f [T/m]',dBzdz(2))) + disp(sprintf('Cavity magnetic field derivative : %2.5f [T/m]',dBzdz(3))) + disp(' ') + disp(sprintf('Magnetic field compression (r=0) : %2.5f',Bz(3)/Bz(1))) + disp(sprintf('Magnetic field compression (r=rcat) : %2.5f',Bz(3)/Bz(2))) + disp(sprintf('Beam radius in cavity : %2.5f [mm]' ,r_beam*1000)) + disp(sprintf('Beam Compression (r_cat/r_beam)^2 : %2.5f' ,(r_cat/r_beam)^2)) + disp(' ') + disp(sprintf('Magnetic angle at emitter [deg] : %2.5f [deg]' ,atan2d(Br(2),Bz(2)) )) + disp(' ') + disp(' ') + disp(' ') + disp(' ') + disp(' ') + + + + + diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Params_Cryogenic_script.m b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Params_Cryogenic_script.m new file mode 100644 index 0000000..3cff93a --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Params_Cryogenic_script.m @@ -0,0 +1,18 @@ +function void = B_Params_script(magnet,Ips) +% +% Small script to run the more general B_Params_170 which returns beam +% parametersog the 170GHz gyrotron tube. +% The only difference is that the currents delivered by the power supplies +% are input here. They are rearranged to run B_Params_170. +% Ips = [Ig1, Ig2, Imain, Iadd1, Iadd2] +% +% Example: +% >> magnet = 'asg_modified_201206' +% >> Ips = [9.7, 7.7, 8.6, 3.54,87.47] +% >> B_Params_script(magnet,Ips) +% +% J.-P. Hogge, 12.003.2008 +% Version: 1.0 + + I = [Ips(1) Ips(2) (Ips(3)+Ips(5)) Ips(4)+Ips(5) Ips(5) ] + B_Params_170(magnet,I) \ No newline at end of file diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Profiles_Cryogenic_170.m b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Profiles_Cryogenic_170.m new file mode 100644 index 0000000..e0de91d --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/B_Profiles_Cryogenic_170.m @@ -0,0 +1,160 @@ + function B_Profiles_170(magnet,I) +% +% Call: B_Profiles_170(magnet,I) +% Example: >> I = [9.7000 7.7000 96.2499 91.0124 87.4723] +% >> B_Profiles_170('asg_modified_201206',I); +% +% >> I = [61.56 66.45 113.43 108.09]/3; +% >> B_Profiles_170('cryogenic',I); +% +% +% Returns magnetic field and beam parameters associated to the GT170 GHz magnet +% +% Version : 1.0 J.-P. Hogge Feb. 10, 2005 +% +% magnet : 'fzk_165ghz_oi' +% I : Array of currents, as read on PS +% Dimensions are in [m] + + +% z_shim = 0.000; +% z_cat_design = 0.08; +% z_cav_design = 0.434; +% z_cat = z_cat_design ; +% z_cav = z_cav_design ; +% r_cat = 0.05; + +% z_shim = 0.000; +% z_cat_design = 9999; +% z_cav_design = 0.394; +% z_cat = z_cat_design ; +% z_cav = z_cav_design ; +% r_cat = 0.05; + +% Cryogenic magnet for the EU 170GHz 1MW prototype + z_shim = 0.000; + z_cat_design = 0.136; + z_cav_design = 0.499665; + z_cat = z_cat_design ; + z_cav = z_cav_design ; + r_cat = 0.05318; + + +% z = linspace(0.00,0.900,91)-0.00012; % =.00012 is the difference between reading and actual + % position of the probe (due to the black ring curvature) + % JPH: 2012_01_12 + + z = linspace(0.00,0.900,901)-0.000; % + +% z_interest = [z_cat, z_cav, 0.228,0.296,0.358,0.512,0.572]; % A few points with particular interest + z_interest = []; + z = cat(2,z,z_interest); % Add those locations to the linspace + z = sort(z); % And finally sort + r = 0 * z; + +% 'bz','br','dbzbz','dbzdr','dbrdz','dbrdr', 'd2bzdz2' or 'aphi' + + Bz = B_Ellip_Cryogenic_170('bz', magnet,I,r,z); + dBzdz = B_Ellip_Cryogenic_170('dbzdz', magnet,I,r,z); + d2Bzdz = B_Ellip_Cryogenic_170('d2bzdz2',magnet,I,r,z); +% + r = r+0.025; + Bz_25 = B_Ellip_Cryogenic_170('bz', magnet,I,r,z); + Br_25 = B_Ellip_Cryogenic_170('br', magnet,I,r,z); + dBzdz_25 = B_Ellip_Cryogenic_170('dbzdz', magnet,I,r,z); + dBzdr_25 = B_Ellip_Cryogenic_170('dbzdr', magnet,I,r,z); + +% Br = B_Ellip_140('br',magnet,Igun,Icav,r,z) +% dBzdz = B_Ellip_140('dbzdz',magnet,Igun,Icav,r,z) +% dBzdr = B_Ellip_140('dbzdr',magnet,Igun,Icav,r,z) +% dBrdz = B_Ellip_140('dbrdz',magnet,Igun,Icav,r,z) +% dBrdr = B_Ellip_140('dbrdz',magnet,Igun,Icav,r,z) +% d2Bzdz = B_Ellip_140('d2bzdz2',magnet,Igun,Icav,r,z) +% aphi = B_Ellip_140('aphi',magnet,Igun,Icav,r,z) + +% r_beam = r_beam_140(magnet,Igun,Icav); + + disp(' ') +% disp(sprintf('Cathode magnetic field on axis (r=0) : %1.5f [T]',Bz(1))) +% disp(sprintf('Cathode magnetic field at r=r_cat : %1.5f [T]',Bz(2))) +% disp(sprintf('Cavity magnetic field : %1.5f [T]',Bz(3))) +% disp(sprintf('Magnetic field compression (r=0) : %2.5f',Bz(3)/Bz(1))) +% disp(sprintf('Magnetic field compression (r=rcat) : %2.5f',Bz(3)/Bz(2))) +% disp(sprintf('Beam radius in cavity : %2.5f [mm]' ,r_beam*1000)) +% disp(sprintf('Beam Compression (r_cat/r_beam)^2 : %1.5f' ,(r_cat/r_beam)^2)) + disp(' ') + + + + disp(' ') + disp(sprintf('GT170 GHz magnetic field and derivatives for I1,..,I5=%0.5g %0.5g %0.5g %0.5g [A]',I(1),I(2),I(3),I(4))) + disp('-------------------------------------------------------------------------------') + disp(' ') + disp(sprintf('Cathode is located in z_cat=%0.5g [m]',z_cat)) + disp(sprintf('Cavity is located in z_cav=%0.5g [m]',z_cav)) + disp(' ') + disp('z [m] Bz [T] dBz/dz [T/m] d2Bz/dz2 [T/m2] Bz(r=25mm) Br(r=25mm) dBz/dz(r=25mm) dBz/dr(r=25mm) ') + disp('----- ------ ------------ --------------- ---------- ---------- -------------- -------------- ') + + for i=1:length(z) + disp(sprintf('%8.5f %8.5f %9.5f %10.5f %8.5f %8.5f %9.5f %9.5f ',... + z(i), Bz(i), dBzdz(i), d2Bzdz(i), Bz_25(i), Br_25(i), dBzdz_25(i), dBzdr_25(i) )) + end + + disp(' ') + + +% +%-------------------------------------------------------------------------------------------------- +% +% + figure(1) + + subplot(3,1,1) + plot(z,Bz); + + title(sprintf('GT170: Magnetic field with I1,..,I4=%0.5g %0.5g %0.5g %0.5g [A]\n',I(1),I(2),I(3),I(4))) + xlabel('Position z [m]') + ylabel('B_z[T]') + grid on + + subplot(3,1,2) + plot(z,dBzdz); + + title(sprintf('GT170: Magnetic field derivative with I1,..,I4=%0.5g %0.5g %0.5g %0.5g [A]\n',I(1),I(2),I(3),I(4))) + xlabel('Position z [m]') + ylabel('dB_z/dz[T/m]') + grid on + + subplot(3,1,3) + plot(z,d2Bzdz); + + title(sprintf('GT170 Magnetic field second derivative with I1,..,I4=%0.5g %0.5g %0.5g %0.5g [A]\n',I(1),I(2),I(3),I(4))) + xlabel('Position z [m]') + ylabel('d2B_z/dz2[T/m2]') + grid on + +% +%-------------------------------------------------------------------------------------------------- +% + + filename = sprintf('b170profile_%s.txt',magnet) + + fid = fopen(filename,'w') + + fprintf(fid,'GT170 GHz magnetic field and derivatives for I1,..,I5=%0.5g %0.5g %0.5g %0.5g [A]\n',I(1),I(2),I(3),I(4)); + fprintf(fid,'------------------------------------------------------------- \n'); + fprintf(' \n'); + fprintf(fid,'Cathode is located in z_cat=%0.5g [m] \n',z_cat); + fprintf(fid,'Cavity is located in z_cav=%0.5g [m] \n',z_cav); + fprintf(' \n'); + fprintf(fid,' z [m] Bz [T] dBz/dz [T/m] d2Bz/dz2 [T/m2] Bz(r=25mm) Br(r=25mm) dBz/dz(r=25mm) dBz/dr(r=25mm) \n'); + fprintf(fid,' ----- ------ ------------ --------------- ---------- ---------- -------------- -------------- \n'); + + for i=1:length(z) + fprintf(fid,'%8.5f %8.5f %9.5f %10.5f %8.5f %8.5f %9.5f %9.5f \n',... + z(i), Bz(i), dBzdz(i), d2Bzdz(i), Bz_25(i), Br_25(i), dBzdz_25(i), dBzdr_25(i) ); + end + + fclose(fid) + diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/Cryogenic_limits.m b/matlab/Magnetic_Field_GLS_2020/Cryogenic/Cryogenic_limits.m new file mode 100644 index 0000000..fa068b5 --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/Cryogenic_limits.m @@ -0,0 +1,11 @@ +% Cryogenic_limits.m +% Defines the safe ranges of currents that can be used with Cryogenic +% magnet. +% + cryogenic_limits = zeros(4,2); + cryogenic_limits(:,1) = 0; + + cryogenic_limits(1,2) = 81.30; + cryogenic_limits(2,2) = 89.40; + cryogenic_limits(3,2) = 117.55; + cryogenic_limits(4,2) = 114.80; \ No newline at end of file diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/Define_Gamma_factors.m b/matlab/Magnetic_Field_GLS_2020/Cryogenic/Define_Gamma_factors.m new file mode 100644 index 0000000..0bc64ee --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/Define_Gamma_factors.m @@ -0,0 +1,4 @@ +% File +% Contains the MAT88 coefficients +% + gamma_fact = [0.002933702702413, -0.006273617730218, -0.007626993519919, 0.009872147598678] diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/Draw_B_Ellip_170_geom_proto.m b/matlab/Magnetic_Field_GLS_2020/Cryogenic/Draw_B_Ellip_170_geom_proto.m new file mode 100644 index 0000000..5145992 --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/Draw_B_Ellip_170_geom_proto.m @@ -0,0 +1,132 @@ + + +z=linspace(-0.05,0.2,100); +r=linspace(0.02,0.09,100); +[Z,R] = meshgrid(z,r); + +% I = [ 9.7 7.7 96.2499 91.0124 87.4723]; +% I = [0 0 6.79541 1.967 88.2799]; +% I = [0 0 5 1.967 88.2799]; +I = [61.56 66.45 113.43 108.09 ]; +res=zeros([size(Z),3]); +%Bz=zeros(size(Z)); +%Br=zeros(size(Z)); + +for i=1:size(R,1) +res(i,:,:) = B_Ellip_Cryogenic_170({'aphi','bz','br'},'cryogenic',I,R(i,:),Z(i,:)); +%Bz(i,:) = B_Ellip_Cryogenic_170('bz','asg_modified_201206',I,R(i,:),Z(i,:)); +%Br(i,:) = B_Ellip_Cryogenic_170('br','asg_modified_201206',I,R(i,:),Z(i,:)); +end +Aphi=res(:,:,1); +Bz=res(:,:,2); +Br=res(:,:,3); + + +% zphi=linspace(0.005,0.0195,100); +% rphi=linspace(0.06375,0.079,150); +% b=max(rphi); +% a=min(rphi); +% phib=0; +% phia=-30000; +% phi=((phib-phia)*log(rphi)+phia*log(b)-phib*log(a))/log(b/a); +% Er=((phib-phia)./rphi)/log(b/a); +% [Zphi,Rphi] = meshgrid(zphi,rphi); +% Phi=repmat(phi',1,length(zphi)); + + +%% Define the individual boundaries +geom=importproto('../geometry_proto.data',[2,Inf]); +geomcells={}; +j=1; +i=1; +n=1; +while i<=size(geom.Z,1) + if isnan(geom.Z(i)) + j=j+1; + while isnan(geom.Z(i)) + i=i+1; + end + n=1; + end + geomcells{j}.Z(n)=geom.Z(i); + geomcells{j}.R(n)=geom.R(i); + i=i+1; + n=n+1; +end +geomcells{1}.name='Cathode'; +geomcells{1}.Dval=-30000; +geomcells{2}.name='Body'; +geomcells{2}.Dval=0; +geomcells{3}.name='Coaxial insert'; +geomcells{3}.Dval=0; +geomcells{4}.name='insulator left'; +geomcells{4}.Dval=0; +geomcells{5}.name='insulator right'; +geomcells{5}.Dval=0; +for k=1:length(geomcells) +geomcells{k}.order=3; +geomcells{k}.dim=2; +geomcells{k}.epsce=1e-9; +geomcells{k}.epsge=1e-9; +geomcells{k}.type=0; +geomcells{k}.periodic=0; +end +geomcells{end-1}.type=2; +geomcells{end}.type=2; + +%% Plots +f=figure; +for k=1:length(geomcells) + plothandle=plot(geomcells{k}.Z, geomcells{k}.R,'k-','linewidth',1.5); + hold on + geomcells{k}.points=[geomcells{k}.Z; geomcells{k}.R]; + order=geomcells{k}.order; + knots=linspace(0,1,length(geomcells{k}.Z)-(order-2)); + knots=augknt(knots, order); + sizec=size(geomcells{k}.Z); + order=length(knots)-sizec(end); + coeffs=[geomcells{k}.Z; geomcells{k}.R]; + pp=spmak(knots,coeffs); + s=linspace(0,1,10000); + fittedpos=fnval(pp,s); + plot(fittedpos(1,:),fittedpos(2,:),'x-') +end +hold on +%end +%axis equal +[~,cont1]=contour(Z,R,R.*Aphi,15,'r:','linewidth',3); +%xlim([min(z) 0.04]) +%ylim([0.055 0.085]) +%[~,cont2]=contour(Zphi,Rphi,Phi,20,'b'); +%rectangle('Position',[-0.011, 0.06375, 0.032+0.011, 0.081-0.06375],'EdgeColor','magenta','Linestyle','--') + + + +legend([plothandle,cont1],{'Gun geometry', 'Magnetic field lines','Wall approximation'},'location','southwest') +f.PaperUnits='centimeters'; +f.PaperSize=[12,8]; +xlabel('z [m]') +ylabel('r [m]') +print(f,'phiBprofile_protoasg','-dpdf','-fillpage') +savefig(f,'phiBprofile_protoasg') +hold off + + +%% Save magnetic field and geometry to disk +save=true; +overwrite=true; +if save +% idr=1:1:length(magnet.r); +% idz=1:1:length(magnet.z); +% Aphi=zeros(length(idr),length(idz)); +% Bz=zeros(length(idr),length(idz)); +% Br=zeros(length(idr),length(idz)); +% +% for i=1:size(magnet.subcoils,1) +% Aphi=Aphi+Icoil(i)*magnet.subcoils{i,1}(idr,idz); +% Bz=Bz+Icoil(i)*magnet.subcoils{i,2}(idr,idz); +% Br=Br+Icoil(i)*magnet.subcoils{i,3}(idr,idz); +% end +% savemagtoh5([name,'.h5'],magnet.r,magnet.z,Aphi,Br,Bz,overwrite); + savegeomtoh5('proto_geom.h5',geomcells,1e-2,overwrite); +end diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/GT170_1MW_Geometry.m b/matlab/Magnetic_Field_GLS_2020/Cryogenic/GT170_1MW_Geometry.m new file mode 100644 index 0000000..0109364 --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/GT170_1MW_Geometry.m @@ -0,0 +1,22 @@ +% GT170 1MW geometry +% Contains the geometry of the first 1MW 170GHz CW TH1509 tube +% JPH : Aug. 4th, 2017 +% + z_shim = 0.00; % Shim that is possibly used to lift the gyrotron + + z_cat_min_design = 0.1335; % Coordinate of emitter at larger radius + z_cat_design = 0.136; % 1MW 170GHz first prototype (2017), cathode CENTER + z_cav_design = 0.4995; + z_launcher_design = 0.78848; % Launcher edge + + r_cat_min = 0.05419; % largest emitter radius of first prototype 170GHz 1MW + r_cat = 0.0533693; % 1MW 170GHz first prototype (2017) AVERAGE radius, WARM dimension + r_launcher = 0.02068; % launcher radius + +% Add shimming if necessary + + z_cat_min = z_cat_min_design + z_shim; + z_cat = z_cat_design + z_shim; + z_cav = z_cav_design + z_shim; + z_launcher = z_launcher_design + z_shim; + diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/b170profile_cryogenic.txt b/matlab/Magnetic_Field_GLS_2020/Cryogenic/b170profile_cryogenic.txt new file mode 100644 index 0000000..fdfe040 --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/b170profile_cryogenic.txt @@ -0,0 +1,907 @@ +GT170 GHz magnetic field and derivatives for I1,..,I5=61.56 66.45 113.43 108.09 [A] +------------------------------------------------------------- +Cathode is located in z_cat=0.136 [m] +Cavity is located in z_cav=0.49967 [m] + z [m] Bz [T] dBz/dz [T/m] d2Bz/dz2 [T/m2] Bz(r=25mm) Br(r=25mm) dBz/dz(r=25mm) dBz/dr(r=25mm) + ----- ------ ------------ --------------- ---------- ---------- -------------- -------------- + 0.00000 0.24297 0.36003 -7.59886 0.24416 -0.00464 0.38262 0.09481 + 0.00100 0.24333 0.35236 -7.73996 0.24454 -0.00454 0.37497 0.09666 + 0.00200 0.24368 0.34455 -7.88105 0.24491 -0.00445 0.36718 0.09851 + 0.00300 0.24402 0.33660 -8.02204 0.24527 -0.00435 0.35923 0.10037 + 0.00400 0.24435 0.32851 -8.16284 0.24563 -0.00425 0.35112 0.10223 + 0.00500 0.24467 0.32027 -8.30332 0.24597 -0.00414 0.34286 0.10409 + 0.00600 0.24499 0.31190 -8.44340 0.24631 -0.00404 0.33444 0.10595 + 0.00700 0.24530 0.30339 -8.58296 0.24664 -0.00393 0.32586 0.10780 + 0.00800 0.24560 0.29474 -8.72188 0.24696 -0.00382 0.31712 0.10965 + 0.00900 0.24589 0.28594 -8.86004 0.24728 -0.00371 0.30823 0.11150 + 0.01000 0.24617 0.27702 -8.99732 0.24758 -0.00360 0.29918 0.11334 + 0.01100 0.24644 0.26795 -9.13359 0.24787 -0.00349 0.28997 0.11517 + 0.01200 0.24670 0.25875 -9.26872 0.24816 -0.00337 0.28061 0.11699 + 0.01300 0.24696 0.24941 -9.40258 0.24844 -0.00325 0.27109 0.11880 + 0.01400 0.24720 0.23994 -9.53502 0.24870 -0.00313 0.26142 0.12060 + 0.01500 0.24744 0.23034 -9.66589 0.24896 -0.00301 0.25159 0.12238 + 0.01600 0.24766 0.22061 -9.79505 0.24921 -0.00289 0.24161 0.12414 + 0.01700 0.24788 0.21075 -9.92235 0.24944 -0.00276 0.23147 0.12589 + 0.01800 0.24809 0.20077 -10.04762 0.24967 -0.00264 0.22119 0.12762 + 0.01900 0.24828 0.19066 -10.17069 0.24988 -0.00251 0.21075 0.12932 + 0.02000 0.24847 0.18043 -10.29141 0.25009 -0.00238 0.20016 0.13099 + 0.02100 0.24864 0.17008 -10.40960 0.25028 -0.00224 0.18943 0.13264 + 0.02200 0.24881 0.15961 -10.52508 0.25047 -0.00211 0.17856 0.13427 + 0.02300 0.24896 0.14903 -10.63767 0.25064 -0.00198 0.16754 0.13586 + 0.02400 0.24910 0.13834 -10.74719 0.25080 -0.00184 0.15638 0.13741 + 0.02500 0.24924 0.12754 -10.85343 0.25095 -0.00170 0.14508 0.13893 + 0.02600 0.24936 0.11663 -10.95622 0.25109 -0.00156 0.13365 0.14041 + 0.02700 0.24947 0.10562 -11.05534 0.25122 -0.00142 0.12208 0.14185 + 0.02800 0.24957 0.09452 -11.15058 0.25134 -0.00128 0.11039 0.14325 + 0.02900 0.24966 0.08332 -11.24175 0.25144 -0.00113 0.09857 0.14460 + 0.03000 0.24974 0.07204 -11.32863 0.25153 -0.00099 0.08662 0.14590 + 0.03100 0.24980 0.06067 -11.41099 0.25162 -0.00084 0.07456 0.14715 + 0.03200 0.24986 0.04922 -11.48862 0.25168 -0.00069 0.06238 0.14834 + 0.03300 0.24990 0.03769 -11.56129 0.25174 -0.00055 0.05008 0.14948 + 0.03400 0.24993 0.02610 -11.62876 0.25178 -0.00040 0.03769 0.15055 + 0.03500 0.24995 0.01444 -11.69079 0.25182 -0.00024 0.02518 0.15157 + 0.03600 0.24996 0.00272 -11.74716 0.25183 -0.00009 0.01259 0.15251 + 0.03700 0.24996 -0.00905 -11.79761 0.25184 0.00006 -0.00011 0.15339 + 0.03800 0.24994 -0.02088 -11.84189 0.25183 0.00021 -0.01288 0.15419 + 0.03900 0.24992 -0.03274 -11.87975 0.25181 0.00037 -0.02574 0.15492 + 0.04000 0.24988 -0.04463 -11.91094 0.25178 0.00052 -0.03868 0.15556 + 0.04100 0.24983 -0.05656 -11.93519 0.25174 0.00068 -0.05168 0.15613 + 0.04200 0.24977 -0.06850 -11.95223 0.25168 0.00084 -0.06475 0.15661 + 0.04300 0.24969 -0.08046 -11.96181 0.25161 0.00099 -0.07788 0.15699 + 0.04400 0.24961 -0.09242 -11.96365 0.25152 0.00115 -0.09105 0.15729 + 0.04500 0.24951 -0.10438 -11.95747 0.25143 0.00131 -0.10427 0.15749 + 0.04600 0.24940 -0.11633 -11.94300 0.25131 0.00147 -0.11752 0.15758 + 0.04700 0.24927 -0.12827 -11.91995 0.25119 0.00162 -0.13079 0.15758 + 0.04800 0.24914 -0.14017 -11.88804 0.25105 0.00178 -0.14409 0.15746 + 0.04900 0.24899 -0.15204 -11.84699 0.25090 0.00194 -0.15739 0.15724 + 0.05000 0.24884 -0.16386 -11.79649 0.25074 0.00209 -0.17069 0.15690 + 0.05100 0.24867 -0.17563 -11.73627 0.25056 0.00225 -0.18399 0.15644 + 0.05200 0.24848 -0.18733 -11.66603 0.25037 0.00241 -0.19727 0.15585 + 0.05300 0.24829 -0.19896 -11.58547 0.25017 0.00256 -0.21052 0.15514 + 0.05400 0.24809 -0.21050 -11.49429 0.24995 0.00272 -0.22373 0.15430 + 0.05500 0.24787 -0.22194 -11.39219 0.24972 0.00287 -0.23690 0.15332 + 0.05600 0.24764 -0.23328 -11.27887 0.24948 0.00302 -0.25000 0.15221 + 0.05700 0.24740 -0.24450 -11.15403 0.24922 0.00318 -0.26304 0.15095 + 0.05800 0.24715 -0.25558 -11.01736 0.24895 0.00333 -0.27599 0.14955 + 0.05900 0.24689 -0.26653 -10.86856 0.24867 0.00348 -0.28885 0.14799 + 0.06000 0.24662 -0.27732 -10.70732 0.24837 0.00362 -0.30160 0.14628 + 0.06100 0.24634 -0.28794 -10.53333 0.24806 0.00377 -0.31424 0.14441 + 0.06200 0.24605 -0.29838 -10.34630 0.24774 0.00391 -0.32674 0.14238 + 0.06300 0.24574 -0.30863 -10.14590 0.24741 0.00405 -0.33910 0.14018 + 0.06400 0.24543 -0.31867 -9.93184 0.24707 0.00419 -0.35130 0.13781 + 0.06500 0.24510 -0.32848 -9.70381 0.24671 0.00433 -0.36333 0.13526 + 0.06600 0.24477 -0.33807 -9.46151 0.24634 0.00446 -0.37518 0.13254 + 0.06700 0.24443 -0.34740 -9.20462 0.24596 0.00459 -0.38682 0.12963 + 0.06800 0.24408 -0.35647 -8.93286 0.24557 0.00472 -0.39825 0.12653 + 0.06900 0.24372 -0.36526 -8.64590 0.24516 0.00485 -0.40945 0.12324 + 0.07000 0.24335 -0.37376 -8.34346 0.24475 0.00497 -0.42040 0.11976 + 0.07100 0.24297 -0.38194 -8.02523 0.24432 0.00509 -0.43109 0.11608 + 0.07200 0.24258 -0.38980 -7.69093 0.24388 0.00520 -0.44150 0.11219 + 0.07300 0.24219 -0.39732 -7.34025 0.24344 0.00531 -0.45161 0.10810 + 0.07400 0.24179 -0.40448 -6.97290 0.24298 0.00542 -0.46142 0.10380 + 0.07500 0.24138 -0.41126 -6.58859 0.24251 0.00552 -0.47089 0.09928 + 0.07600 0.24097 -0.41765 -6.18705 0.24204 0.00561 -0.48002 0.09454 + 0.07700 0.24054 -0.42363 -5.76798 0.24155 0.00571 -0.48878 0.08958 + 0.07800 0.24012 -0.42918 -5.33112 0.24106 0.00579 -0.49716 0.08440 + 0.07900 0.23969 -0.43429 -4.87617 0.24056 0.00587 -0.50513 0.07898 + 0.08000 0.23925 -0.43893 -4.40288 0.24005 0.00595 -0.51269 0.07333 + 0.08100 0.23881 -0.44309 -3.91098 0.23954 0.00602 -0.51980 0.06744 + 0.08200 0.23836 -0.44674 -3.40020 0.23901 0.00609 -0.52646 0.06131 + 0.08300 0.23792 -0.44988 -2.87028 0.23848 0.00614 -0.53264 0.05494 + 0.08400 0.23746 -0.45248 -2.32098 0.23795 0.00620 -0.53832 0.04832 + 0.08500 0.23701 -0.45451 -1.75205 0.23741 0.00624 -0.54348 0.04145 + 0.08600 0.23656 -0.45597 -1.16325 0.23686 0.00628 -0.54809 0.03433 + 0.08700 0.23610 -0.45683 -0.55433 0.23631 0.00631 -0.55215 0.02695 + 0.08800 0.23564 -0.45708 0.07493 0.23576 0.00633 -0.55563 0.01931 + 0.08900 0.23518 -0.45668 0.72475 0.23520 0.00635 -0.55850 0.01140 + 0.09000 0.23473 -0.45562 1.39536 0.23464 0.00635 -0.56074 0.00323 + 0.09100 0.23427 -0.45388 2.08697 0.23408 0.00635 -0.56234 -0.00521 + 0.09200 0.23382 -0.45144 2.79978 0.23352 0.00634 -0.56327 -0.01392 + 0.09300 0.23337 -0.44827 3.53399 0.23295 0.00633 -0.56351 -0.02291 + 0.09400 0.23292 -0.44436 4.28980 0.23239 0.00630 -0.56303 -0.03217 + 0.09500 0.23248 -0.43969 5.06738 0.23183 0.00626 -0.56181 -0.04171 + 0.09600 0.23205 -0.43422 5.86693 0.23126 0.00622 -0.55984 -0.05154 + 0.09700 0.23161 -0.42795 6.68860 0.23071 0.00616 -0.55708 -0.06164 + 0.09800 0.23119 -0.42084 7.53257 0.23015 0.00609 -0.55351 -0.07204 + 0.09900 0.23077 -0.41287 8.39899 0.22960 0.00601 -0.54912 -0.08272 + 0.10000 0.23036 -0.40403 9.28801 0.22905 0.00593 -0.54387 -0.09369 + 0.10100 0.22997 -0.39429 10.19976 0.22851 0.00583 -0.53774 -0.10496 + 0.10200 0.22958 -0.38362 11.13439 0.22798 0.00572 -0.53070 -0.11651 + 0.10300 0.22920 -0.37201 12.09202 0.22745 0.00559 -0.52274 -0.12837 + 0.10400 0.22883 -0.35943 13.07277 0.22693 0.00546 -0.51383 -0.14052 + 0.10500 0.22848 -0.34586 14.07674 0.22642 0.00531 -0.50395 -0.15297 + 0.10600 0.22814 -0.33127 15.10404 0.22593 0.00515 -0.49306 -0.16572 + 0.10700 0.22782 -0.31564 16.15475 0.22544 0.00498 -0.48115 -0.17877 + 0.10800 0.22751 -0.29895 17.22897 0.22496 0.00480 -0.46819 -0.19212 + 0.10900 0.22722 -0.28118 18.32678 0.22450 0.00460 -0.45416 -0.20577 + 0.11000 0.22695 -0.26229 19.44823 0.22406 0.00438 -0.43903 -0.21973 + 0.11100 0.22670 -0.24227 20.59339 0.22362 0.00416 -0.42277 -0.23400 + 0.11200 0.22646 -0.22110 21.76231 0.22321 0.00392 -0.40536 -0.24856 + 0.11300 0.22625 -0.19874 22.95504 0.22281 0.00366 -0.38678 -0.26344 + 0.11400 0.22607 -0.17518 24.17160 0.22244 0.00339 -0.36700 -0.27862 + 0.11500 0.22590 -0.15039 25.41203 0.22208 0.00310 -0.34599 -0.29411 + 0.11600 0.22577 -0.12435 26.67633 0.22175 0.00280 -0.32373 -0.30990 + 0.11700 0.22566 -0.09703 27.96453 0.22143 0.00248 -0.30020 -0.32601 + 0.11800 0.22557 -0.06841 29.27661 0.22115 0.00215 -0.27537 -0.34242 + 0.11900 0.22552 -0.03847 30.61257 0.22088 0.00180 -0.24921 -0.35913 + 0.12000 0.22550 -0.00718 31.97240 0.22065 0.00143 -0.22170 -0.37615 + 0.12100 0.22551 0.02548 33.35605 0.22044 0.00105 -0.19281 -0.39348 + 0.12200 0.22555 0.05954 34.76351 0.22026 0.00064 -0.16252 -0.41112 + 0.12300 0.22563 0.09502 36.19472 0.22012 0.00022 -0.13081 -0.42906 + 0.12400 0.22574 0.13194 37.64964 0.22000 -0.00022 -0.09764 -0.44731 + 0.12500 0.22589 0.17033 39.12819 0.21992 -0.00067 -0.06300 -0.46586 + 0.12600 0.22608 0.21020 40.63031 0.21988 -0.00115 -0.02685 -0.48471 + 0.12700 0.22631 0.25160 42.15593 0.21987 -0.00164 0.01082 -0.50387 + 0.12800 0.22658 0.29452 43.70494 0.21990 -0.00215 0.05005 -0.52332 + 0.12900 0.22690 0.33901 45.27725 0.21997 -0.00269 0.09085 -0.54308 + 0.13000 0.22726 0.38509 46.87275 0.22008 -0.00324 0.13325 -0.56314 + 0.13100 0.22767 0.43277 48.49133 0.22024 -0.00381 0.17728 -0.58349 + 0.13200 0.22813 0.48208 50.13286 0.22044 -0.00441 0.22295 -0.60414 + 0.13300 0.22864 0.53304 51.79720 0.22068 -0.00502 0.27030 -0.62508 + 0.13400 0.22919 0.58568 53.48421 0.22098 -0.00566 0.31935 -0.64632 + 0.13500 0.22981 0.64002 55.19372 0.22132 -0.00632 0.37013 -0.66785 + 0.13600 0.23048 0.69607 56.92559 0.22172 -0.00699 0.42265 -0.68966 + 0.13700 0.23120 0.75387 58.67962 0.22217 -0.00769 0.47694 -0.71177 + 0.13800 0.23198 0.81344 60.45564 0.22267 -0.00842 0.53302 -0.73415 + 0.13900 0.23283 0.87479 62.25345 0.22323 -0.00916 0.59092 -0.75682 + 0.14000 0.23373 0.93795 64.07283 0.22385 -0.00993 0.65066 -0.77977 + 0.14100 0.23470 1.00295 65.91358 0.22454 -0.01072 0.71227 -0.80300 + 0.14200 0.23574 1.06979 67.77546 0.22528 -0.01154 0.77576 -0.82650 + 0.14300 0.23684 1.13850 69.65824 0.22609 -0.01238 0.84116 -0.85028 + 0.14400 0.23802 1.20911 71.56166 0.22696 -0.01324 0.90849 -0.87432 + 0.14500 0.23926 1.28163 73.48547 0.22791 -0.01412 0.97778 -0.89863 + 0.14600 0.24058 1.35609 75.42937 0.22892 -0.01504 1.04904 -0.92320 + 0.14700 0.24198 1.43250 77.39310 0.23000 -0.01597 1.12230 -0.94803 + 0.14800 0.24345 1.51088 79.37634 0.23116 -0.01693 1.19758 -0.97312 + 0.14900 0.24500 1.59126 81.37880 0.23240 -0.01792 1.27490 -0.99846 + 0.15000 0.24663 1.67365 83.40013 0.23371 -0.01893 1.35428 -1.02405 + 0.15100 0.24835 1.75806 85.44001 0.23511 -0.01997 1.43575 -1.04988 + 0.15200 0.25015 1.84453 87.49808 0.23659 -0.02103 1.51932 -1.07596 + 0.15300 0.25204 1.93307 89.57398 0.23815 -0.02212 1.60501 -1.10227 + 0.15400 0.25401 2.02369 91.66733 0.23980 -0.02323 1.69284 -1.12881 + 0.15500 0.25608 2.11641 93.77773 0.24153 -0.02438 1.78284 -1.15558 + 0.15600 0.25825 2.21125 95.90477 0.24336 -0.02554 1.87502 -1.18258 + 0.15700 0.26051 2.30822 98.04802 0.24529 -0.02674 1.96940 -1.20979 + 0.15800 0.26287 2.40735 100.20706 0.24730 -0.02796 2.06599 -1.23721 + 0.15900 0.26532 2.50864 102.38142 0.24942 -0.02922 2.16483 -1.26484 + 0.16000 0.26788 2.61212 104.57062 0.25163 -0.03049 2.26592 -1.29268 + 0.16100 0.27055 2.71779 106.77419 0.25395 -0.03180 2.36928 -1.32071 + 0.16200 0.27332 2.82567 108.99161 0.25637 -0.03314 2.47493 -1.34893 + 0.16300 0.27620 2.93577 111.22236 0.25890 -0.03450 2.58289 -1.37733 + 0.16400 0.27919 3.04812 113.46590 0.26154 -0.03589 2.69316 -1.40591 + 0.16500 0.28230 3.16271 115.72167 0.26429 -0.03731 2.80578 -1.43466 + 0.16600 0.28552 3.27957 117.98910 0.26715 -0.03876 2.92074 -1.46358 + 0.16700 0.28886 3.39869 120.26758 0.27013 -0.04024 3.03807 -1.49265 + 0.16800 0.29232 3.52010 122.55651 0.27323 -0.04174 3.15778 -1.52188 + 0.16900 0.29590 3.64381 124.85525 0.27645 -0.04328 3.27988 -1.55124 + 0.17000 0.29960 3.76982 127.16314 0.27979 -0.04485 3.40439 -1.58074 + 0.17100 0.30344 3.89814 129.47952 0.28326 -0.04644 3.53131 -1.61036 + 0.17200 0.30740 4.02878 131.80369 0.28685 -0.04807 3.66066 -1.64011 + 0.17300 0.31150 4.16175 134.13494 0.29058 -0.04972 3.79246 -1.66996 + 0.17400 0.31573 4.29705 136.47253 0.29444 -0.05141 3.92670 -1.69991 + 0.17500 0.32009 4.43469 138.81572 0.29843 -0.05312 4.06340 -1.72995 + 0.17600 0.32460 4.57468 141.16372 0.30257 -0.05487 4.20257 -1.76008 + 0.17700 0.32924 4.71702 143.51575 0.30684 -0.05664 4.34421 -1.79027 + 0.17800 0.33403 4.86172 145.87098 0.31126 -0.05845 4.48834 -1.82053 + 0.17900 0.33897 5.00877 148.22859 0.31582 -0.06028 4.63495 -1.85083 + 0.18000 0.34405 5.15817 150.58770 0.32053 -0.06215 4.78406 -1.88118 + 0.18100 0.34928 5.30994 152.94745 0.32539 -0.06405 4.93567 -1.91156 + 0.18200 0.35467 5.46407 155.30694 0.33040 -0.06597 5.08977 -1.94195 + 0.18300 0.36021 5.62056 157.66523 0.33557 -0.06793 5.24639 -1.97235 + 0.18400 0.36591 5.77940 160.02140 0.34089 -0.06992 5.40551 -2.00275 + 0.18500 0.37177 5.94060 162.37448 0.34638 -0.07194 5.56714 -2.03313 + 0.18600 0.37779 6.10415 164.72348 0.35203 -0.07398 5.73128 -2.06348 + 0.18700 0.38398 6.27004 167.06741 0.35784 -0.07606 5.89792 -2.09378 + 0.18800 0.39033 6.43828 169.40525 0.36382 -0.07817 6.06706 -2.12403 + 0.18900 0.39686 6.60885 171.73594 0.36998 -0.08031 6.23871 -2.15421 + 0.19000 0.40355 6.78175 174.05843 0.37630 -0.08248 6.41286 -2.18431 + 0.19100 0.41042 6.95696 176.37164 0.38280 -0.08468 6.58949 -2.21431 + 0.19200 0.41747 7.13449 178.67446 0.38948 -0.08691 6.76861 -2.24420 + 0.19300 0.42469 7.31431 180.96578 0.39634 -0.08917 6.95021 -2.27396 + 0.19400 0.43210 7.49642 183.24447 0.40338 -0.09146 7.13427 -2.30358 + 0.19500 0.43969 7.68079 185.50937 0.41061 -0.09378 7.32079 -2.33305 + 0.19600 0.44746 7.86743 187.75931 0.41803 -0.09612 7.50975 -2.36235 + 0.19700 0.45542 8.05631 189.99310 0.42563 -0.09850 7.70115 -2.39146 + 0.19800 0.46357 8.24741 192.20955 0.43343 -0.10091 7.89497 -2.42037 + 0.19900 0.47192 8.44072 194.40744 0.44142 -0.10334 8.09118 -2.44907 + 0.20000 0.48045 8.63622 196.58554 0.44961 -0.10580 8.28979 -2.47753 + 0.20100 0.48919 8.83388 198.74261 0.45800 -0.10830 8.49076 -2.50574 + 0.20200 0.49812 9.03370 200.87739 0.46659 -0.11082 8.69408 -2.53368 + 0.20300 0.50726 9.23563 202.98862 0.47539 -0.11336 8.89973 -2.56134 + 0.20400 0.51660 9.43966 205.07502 0.48439 -0.11594 9.10768 -2.58871 + 0.20500 0.52614 9.64577 207.13529 0.49361 -0.11854 9.31792 -2.61575 + 0.20600 0.53589 9.85393 209.16815 0.50303 -0.12117 9.53041 -2.64246 + 0.20700 0.54585 10.06410 211.17229 0.51267 -0.12382 9.74513 -2.66882 + 0.20800 0.55602 10.27626 213.14639 0.52252 -0.12651 9.96205 -2.69481 + 0.20900 0.56640 10.49038 215.08915 0.53259 -0.12921 10.18114 -2.72041 + 0.21000 0.57700 10.70643 216.99924 0.54288 -0.13195 10.40238 -2.74561 + 0.21100 0.58781 10.92437 218.87532 0.55340 -0.13471 10.62572 -2.77039 + 0.21200 0.59885 11.14417 220.71608 0.56414 -0.13749 10.85113 -2.79473 + 0.21300 0.61010 11.36579 222.52018 0.57510 -0.14029 11.07858 -2.81861 + 0.21400 0.62158 11.58919 224.28628 0.58629 -0.14312 11.30803 -2.84202 + 0.21500 0.63328 11.81435 226.01307 0.59772 -0.14598 11.53944 -2.86493 + 0.21600 0.64521 12.04121 227.69920 0.60937 -0.14885 11.77278 -2.88733 + 0.21700 0.65736 12.26973 229.34336 0.62126 -0.15175 12.00799 -2.90921 + 0.21800 0.66975 12.49988 230.94421 0.63339 -0.15467 12.24504 -2.93054 + 0.21900 0.68236 12.73161 232.50045 0.64576 -0.15761 12.48389 -2.95130 + 0.22000 0.69521 12.96487 234.01075 0.65836 -0.16058 12.72447 -2.97148 + 0.22100 0.70829 13.19961 235.47382 0.67120 -0.16356 12.96676 -2.99107 + 0.22200 0.72161 13.43580 236.88836 0.68429 -0.16656 13.21069 -3.01004 + 0.22300 0.73517 13.67337 238.25309 0.69763 -0.16958 13.45622 -3.02837 + 0.22400 0.74896 13.91229 239.56672 0.71121 -0.17261 13.70330 -3.04606 + 0.22500 0.76299 14.15249 240.82801 0.72503 -0.17567 13.95186 -3.06307 + 0.22600 0.77726 14.39392 242.03570 0.73911 -0.17874 14.20187 -3.07940 + 0.22700 0.79178 14.63654 243.18857 0.75344 -0.18183 14.45325 -3.09503 + 0.22800 0.80654 14.88028 244.28538 0.76802 -0.18493 14.70595 -3.10995 + 0.22900 0.82154 15.12509 245.32495 0.78285 -0.18805 14.95992 -3.12412 + 0.23000 0.83679 15.37091 246.30609 0.79794 -0.19118 15.21508 -3.13755 + 0.23100 0.85228 15.61768 247.22764 0.81328 -0.19432 15.47139 -3.15022 + 0.23200 0.86802 15.86535 248.08846 0.82888 -0.19748 15.72876 -3.16210 + 0.23300 0.88401 16.11384 248.88743 0.84474 -0.20065 15.98715 -3.17319 + 0.23400 0.90025 16.36310 249.62346 0.86086 -0.20382 16.24649 -3.18346 + 0.23500 0.91674 16.61307 250.29547 0.87723 -0.20701 16.50670 -3.19291 + 0.23600 0.93348 16.86367 250.90242 0.89387 -0.21021 16.76771 -3.20152 + 0.23700 0.95047 17.11485 251.44329 0.91077 -0.21341 17.02947 -3.20928 + 0.23800 0.96771 17.36654 251.91709 0.92793 -0.21663 17.29189 -3.21617 + 0.23900 0.98520 17.61866 252.32285 0.94535 -0.21985 17.55491 -3.22218 + 0.24000 1.00295 17.87116 252.65964 0.96304 -0.22307 17.81845 -3.22730 + 0.24100 1.02094 18.12396 252.92656 0.98099 -0.22630 18.08243 -3.23151 + 0.24200 1.03919 18.37699 253.12273 0.99920 -0.22953 18.34679 -3.23481 + 0.24300 1.05770 18.63018 253.24732 1.01768 -0.23277 18.61144 -3.23718 + 0.24400 1.07645 18.88346 253.29953 1.03643 -0.23601 18.87631 -3.23860 + 0.24500 1.09546 19.13675 253.27859 1.05543 -0.23925 19.14132 -3.23908 + 0.24600 1.11473 19.38999 253.18376 1.07471 -0.24249 19.40638 -3.23860 + 0.24700 1.13424 19.64310 253.01434 1.09425 -0.24572 19.67143 -3.23715 + 0.24800 1.15401 19.89599 252.76969 1.11405 -0.24896 19.93637 -3.23472 + 0.24900 1.17404 20.14861 252.44917 1.13412 -0.25219 20.20114 -3.23130 + 0.25000 1.19431 20.40087 252.05220 1.15445 -0.25542 20.46563 -3.22689 + 0.25100 1.21484 20.65269 251.57825 1.17505 -0.25865 20.72978 -3.22147 + 0.25200 1.23562 20.90400 251.02682 1.19591 -0.26187 20.99349 -3.21505 + 0.25300 1.25665 21.15472 250.39744 1.21704 -0.26508 21.25669 -3.20760 + 0.25400 1.27793 21.40477 249.68970 1.23843 -0.26828 21.51928 -3.19914 + 0.25500 1.29945 21.65407 248.90323 1.26008 -0.27147 21.78118 -3.18965 + 0.25600 1.32123 21.90255 248.03770 1.28199 -0.27466 22.04231 -3.17912 + 0.25700 1.34326 22.15012 247.09283 1.30416 -0.27783 22.30258 -3.16756 + 0.25800 1.36553 22.39671 246.06837 1.32659 -0.28099 22.56191 -3.15496 + 0.25900 1.38805 22.64223 244.96413 1.34928 -0.28414 22.82020 -3.14131 + 0.26000 1.41082 22.88661 243.77997 1.37223 -0.28728 23.07736 -3.12662 + 0.26100 1.43383 23.12976 242.51579 1.39544 -0.29039 23.33332 -3.11088 + 0.26200 1.45708 23.37161 241.17153 1.41890 -0.29350 23.58798 -3.09409 + 0.26300 1.48057 23.61208 239.74718 1.44261 -0.29658 23.84126 -3.07626 + 0.26400 1.50430 23.85108 238.24280 1.46658 -0.29965 24.09306 -3.05737 + 0.26500 1.52827 24.08854 236.65848 1.49080 -0.30270 24.34331 -3.03744 + 0.26600 1.55248 24.32437 234.99434 1.51527 -0.30572 24.59190 -3.01646 + 0.26700 1.57692 24.55850 233.25059 1.53998 -0.30873 24.83876 -2.99443 + 0.26800 1.60159 24.79084 231.42747 1.56494 -0.31171 25.08380 -2.97136 + 0.26900 1.62650 25.02133 229.52526 1.59015 -0.31467 25.32692 -2.94726 + 0.27000 1.65164 25.24987 227.54430 1.61560 -0.31761 25.56805 -2.92212 + 0.27100 1.67700 25.47639 225.48498 1.64129 -0.32052 25.80709 -2.89595 + 0.27200 1.70259 25.70081 223.34775 1.66721 -0.32340 26.04396 -2.86876 + 0.27300 1.72840 25.92306 221.13308 1.69337 -0.32625 26.27858 -2.84054 + 0.27400 1.75443 26.14305 218.84152 1.71977 -0.32908 26.51085 -2.81132 + 0.27500 1.78068 26.36072 216.47366 1.74639 -0.33188 26.74070 -2.78110 + 0.27600 1.80715 26.57598 214.03013 1.77325 -0.33464 26.96803 -2.74987 + 0.27700 1.83384 26.78875 211.51164 1.80033 -0.33737 27.19278 -2.71766 + 0.27800 1.86073 26.99897 208.91890 1.82763 -0.34008 27.41484 -2.68448 + 0.27900 1.88783 27.20657 206.25272 1.85516 -0.34274 27.63415 -2.65032 + 0.28000 1.91514 27.41146 203.51393 1.88290 -0.34538 27.85062 -2.61521 + 0.28100 1.94265 27.61357 200.70340 1.91086 -0.34797 28.06416 -2.57916 + 0.28200 1.97037 27.81284 197.82209 1.93903 -0.35053 28.27471 -2.54217 + 0.28300 1.99828 28.00919 194.87096 1.96741 -0.35306 28.48219 -2.50426 + 0.28400 2.02639 28.20256 191.85104 1.99599 -0.35554 28.68651 -2.46545 + 0.28500 2.05468 28.39287 188.76341 2.02478 -0.35799 28.88760 -2.42574 + 0.28600 2.08317 28.58006 185.60918 2.05376 -0.36039 29.08538 -2.38516 + 0.28700 2.11184 28.76407 182.38952 2.08295 -0.36276 29.27979 -2.34371 + 0.28800 2.14070 28.94482 179.10565 2.11232 -0.36508 29.47075 -2.30142 + 0.28900 2.16973 29.12226 175.75880 2.14189 -0.36736 29.65819 -2.25829 + 0.29000 2.19894 29.29632 172.35028 2.17164 -0.36960 29.84204 -2.21436 + 0.29100 2.22832 29.46694 168.88141 2.20157 -0.37179 30.02223 -2.16962 + 0.29200 2.25787 29.63406 165.35359 2.23168 -0.37394 30.19870 -2.12411 + 0.29300 2.28759 29.79763 161.76821 2.26197 -0.37604 30.37138 -2.07785 + 0.29400 2.31747 29.95758 158.12674 2.29242 -0.37809 30.54021 -2.03084 + 0.29500 2.34750 30.11386 154.43067 2.32305 -0.38010 30.70513 -1.98312 + 0.29600 2.37769 30.26642 150.68152 2.35383 -0.38206 30.86607 -1.93469 + 0.29700 2.40804 30.41521 146.88085 2.38478 -0.38397 31.02299 -1.88559 + 0.29800 2.43852 30.56017 143.03027 2.41588 -0.38583 31.17582 -1.83583 + 0.29900 2.46915 30.70125 139.13139 2.44713 -0.38764 31.32450 -1.78544 + 0.30000 2.49992 30.83841 135.18588 2.47852 -0.38940 31.46900 -1.73444 + 0.30100 2.53083 30.97161 131.19542 2.51006 -0.39111 31.60925 -1.68284 + 0.30200 2.56187 31.10079 127.16172 2.54174 -0.39276 31.74521 -1.63068 + 0.30300 2.59303 31.22592 123.08652 2.57355 -0.39437 31.87683 -1.57798 + 0.30400 2.62432 31.34695 118.97160 2.60549 -0.39592 32.00407 -1.52475 + 0.30500 2.65572 31.46385 114.81873 2.63756 -0.39742 32.12689 -1.47103 + 0.30600 2.68724 31.57658 110.62973 2.66975 -0.39886 32.24523 -1.41684 + 0.30700 2.71887 31.68510 106.40642 2.70205 -0.40025 32.35908 -1.36220 + 0.30800 2.75061 31.78938 102.15065 2.73446 -0.40159 32.46838 -1.30714 + 0.30900 2.78245 31.88939 97.86428 2.76698 -0.40287 32.57311 -1.25168 + 0.31000 2.81439 31.98510 93.54919 2.79961 -0.40409 32.67323 -1.19585 + 0.31100 2.84642 32.07648 89.20726 2.83233 -0.40526 32.76872 -1.13967 + 0.31200 2.87854 32.16350 84.84040 2.86514 -0.40637 32.85954 -1.08318 + 0.31300 2.91075 32.24615 80.45051 2.89805 -0.40742 32.94568 -1.02638 + 0.31400 2.94303 32.32440 76.03952 2.93103 -0.40842 33.02710 -0.96932 + 0.31500 2.97539 32.39822 71.60933 2.96410 -0.40936 33.10379 -0.91202 + 0.31600 3.00783 32.46761 67.16188 2.99724 -0.41025 33.17573 -0.85450 + 0.31700 3.04033 32.53254 62.69909 3.03045 -0.41107 33.24290 -0.79678 + 0.31800 3.07289 32.59300 58.22289 3.06372 -0.41184 33.30529 -0.73891 + 0.31900 3.10551 32.64898 53.73520 3.09706 -0.41255 33.36288 -0.68089 + 0.32000 3.13819 32.70047 49.23794 3.13045 -0.41320 33.41567 -0.62275 + 0.32100 3.17091 32.74746 44.73303 3.16389 -0.41379 33.46365 -0.56453 + 0.32200 3.20368 32.78993 40.22238 3.19737 -0.41433 33.50682 -0.50625 + 0.32300 3.23649 32.82790 35.70787 3.23090 -0.41481 33.54516 -0.44793 + 0.32400 3.26933 32.86135 31.19141 3.26446 -0.41523 33.57869 -0.38960 + 0.32500 3.30221 32.89028 26.67487 3.29805 -0.41559 33.60739 -0.33128 + 0.32600 3.33511 32.91470 22.16010 3.33167 -0.41589 33.63128 -0.27301 + 0.32700 3.36804 32.93460 17.64895 3.36532 -0.41613 33.65036 -0.21479 + 0.32800 3.40098 32.95000 13.14325 3.39897 -0.41632 33.66464 -0.15666 + 0.32900 3.43394 32.96089 8.64481 3.43264 -0.41645 33.67412 -0.09865 + 0.33000 3.46690 32.96729 4.15542 3.46632 -0.41652 33.67882 -0.04077 + 0.33100 3.49987 32.96921 -0.32316 3.50000 -0.41653 33.67876 0.01695 + 0.33200 3.53284 32.96665 -4.78920 3.53368 -0.41648 33.67394 0.07449 + 0.33300 3.56580 32.95963 -9.24096 3.56735 -0.41638 33.66439 0.13182 + 0.33400 3.59876 32.94817 -13.67676 3.60100 -0.41622 33.65013 0.18893 + 0.33500 3.63170 32.93229 -18.09494 3.63464 -0.41600 33.63117 0.24578 + 0.33600 3.66462 32.91199 -22.49387 3.66826 -0.41573 33.60755 0.30237 + 0.33700 3.69752 32.88731 -26.87194 3.70186 -0.41540 33.57928 0.35865 + 0.33800 3.73039 32.85825 -31.22758 3.73542 -0.41501 33.54639 0.41463 + 0.33900 3.76323 32.82486 -35.55925 3.76895 -0.41457 33.50892 0.47027 + 0.34000 3.79604 32.78714 -39.86545 3.80244 -0.41407 33.46689 0.52556 + 0.34100 3.82881 32.74514 -44.14471 3.83588 -0.41352 33.42033 0.58048 + 0.34200 3.86153 32.69886 -48.39559 3.86928 -0.41291 33.36928 0.63500 + 0.34300 3.89420 32.64836 -52.61669 3.90262 -0.41225 33.31377 0.68911 + 0.34400 3.92682 32.59364 -56.80666 3.93590 -0.41153 33.25385 0.74280 + 0.34500 3.95939 32.53475 -60.96417 3.96912 -0.41076 33.18954 0.79603 + 0.34600 3.99189 32.47172 -65.08794 4.00228 -0.40994 33.12089 0.84881 + 0.34700 4.02433 32.40459 -69.17673 4.03537 -0.40906 33.04794 0.90111 + 0.34800 4.05670 32.33338 -73.22932 4.06838 -0.40814 32.97073 0.95291 + 0.34900 4.08900 32.25814 -77.24457 4.10131 -0.40716 32.88931 1.00421 + 0.35000 4.12122 32.17891 -81.22134 4.13415 -0.40613 32.80371 1.05498 + 0.35100 4.15335 32.09571 -85.15856 4.16691 -0.40505 32.71399 1.10522 + 0.35200 4.18541 32.00860 -89.05520 4.19958 -0.40392 32.62020 1.15491 + 0.35300 4.21737 31.91762 -92.91025 4.23215 -0.40274 32.52237 1.20403 + 0.35400 4.24924 31.82280 -96.72276 4.26462 -0.40151 32.42056 1.25258 + 0.35500 4.28101 31.72419 -100.49182 4.29699 -0.40023 32.31483 1.30054 + 0.35600 4.31269 31.62183 -104.21657 4.32925 -0.39891 32.20521 1.34790 + 0.35700 4.34426 31.51577 -107.89619 4.36140 -0.39754 32.09177 1.39466 + 0.35800 4.37572 31.40605 -111.52988 4.39343 -0.39612 31.97455 1.44080 + 0.35900 4.40707 31.29272 -115.11692 4.42535 -0.39466 31.85361 1.48631 + 0.36000 4.43830 31.17583 -118.65660 4.45714 -0.39315 31.72900 1.53119 + 0.36100 4.46942 31.05543 -122.14828 4.48880 -0.39159 31.60078 1.57542 + 0.36200 4.50041 30.93155 -125.59135 4.52034 -0.39000 31.46900 1.61901 + 0.36300 4.53128 30.80426 -128.98524 4.55174 -0.38836 31.33372 1.66194 + 0.36400 4.56202 30.67360 -132.32942 4.58301 -0.38667 31.19500 1.70420 + 0.36500 4.59263 30.53962 -135.62341 4.61413 -0.38495 31.05288 1.74580 + 0.36600 4.62310 30.40237 -138.86677 4.64511 -0.38318 30.90744 1.78672 + 0.36700 4.65343 30.26190 -142.05909 4.67594 -0.38137 30.75872 1.82696 + 0.36800 4.68362 30.11827 -145.20002 4.70663 -0.37953 30.60678 1.86652 + 0.36900 4.71366 29.97152 -148.28924 4.73716 -0.37764 30.45169 1.90540 + 0.37000 4.74356 29.82171 -151.32646 4.76753 -0.37572 30.29349 1.94358 + 0.37100 4.77331 29.66888 -154.31144 4.79774 -0.37375 30.13225 1.98108 + 0.37200 4.80290 29.51310 -157.24398 4.82779 -0.37176 29.96803 2.01788 + 0.37300 4.83233 29.35441 -160.12391 4.85768 -0.36972 29.80088 2.05399 + 0.37400 4.86161 29.19287 -162.95110 4.88739 -0.36765 29.63087 2.08940 + 0.37500 4.89072 29.02853 -165.72547 4.91694 -0.36554 29.45805 2.12411 + 0.37600 4.91966 28.86144 -168.44694 4.94631 -0.36340 29.28248 2.15813 + 0.37700 4.94844 28.69165 -171.11551 4.97550 -0.36122 29.10422 2.19146 + 0.37800 4.97704 28.51922 -173.73118 5.00452 -0.35902 28.92333 2.22409 + 0.37900 5.00548 28.34421 -176.29400 5.03335 -0.35678 28.73986 2.25603 + 0.38000 5.03373 28.16665 -178.80404 5.06199 -0.35451 28.55387 2.28727 + 0.38100 5.06181 27.98662 -181.26142 5.09045 -0.35220 28.36543 2.31783 + 0.38200 5.08970 27.80415 -183.66628 5.11872 -0.34987 28.17459 2.34770 + 0.38300 5.11742 27.61930 -186.01878 5.14680 -0.34751 27.98140 2.37689 + 0.38400 5.14494 27.43213 -188.31913 5.17469 -0.34512 27.78592 2.40540 + 0.38500 5.17228 27.24268 -190.56755 5.20237 -0.34270 27.58821 2.43323 + 0.38600 5.19943 27.05101 -192.76431 5.22986 -0.34025 27.38833 2.46039 + 0.38700 5.22638 26.85717 -194.90968 5.25715 -0.33778 27.18633 2.48689 + 0.38800 5.25314 26.66121 -197.00396 5.28423 -0.33528 26.98226 2.51272 + 0.38900 5.27970 26.46318 -199.04750 5.31111 -0.33275 26.77619 2.53789 + 0.39000 5.30607 26.26313 -201.04065 5.33779 -0.33020 26.56816 2.56241 + 0.39100 5.33223 26.06111 -202.98379 5.36425 -0.32763 26.35823 2.58628 + 0.39200 5.35819 25.85718 -204.87732 5.39050 -0.32503 26.14645 2.60952 + 0.39300 5.38394 25.65137 -206.72167 5.41654 -0.32241 25.93287 2.63211 + 0.39400 5.40949 25.44375 -208.51726 5.44237 -0.31976 25.71755 2.65408 + 0.39500 5.43483 25.23436 -210.26458 5.46798 -0.31710 25.50054 2.67543 + 0.39600 5.45996 25.02324 -211.96410 5.49337 -0.31441 25.28189 2.69617 + 0.39700 5.48488 24.81044 -213.61631 5.51854 -0.31171 25.06165 2.71629 + 0.39800 5.50958 24.59602 -215.22173 5.54349 -0.30898 24.83986 2.73582 + 0.39900 5.53407 24.38002 -216.78089 5.56822 -0.30624 24.61658 2.75476 + 0.40000 5.55834 24.16247 -218.29434 5.59272 -0.30347 24.39186 2.77311 + 0.40100 5.58239 23.94344 -219.76264 5.61700 -0.30069 24.16574 2.79088 + 0.40200 5.60622 23.72296 -221.18636 5.64105 -0.29789 23.93827 2.80808 + 0.40300 5.62984 23.50108 -222.56607 5.66488 -0.29507 23.70950 2.82473 + 0.40400 5.65323 23.27785 -223.90239 5.68847 -0.29224 23.47947 2.84082 + 0.40500 5.67639 23.05329 -225.19592 5.71184 -0.28939 23.24822 2.85636 + 0.40600 5.69933 22.82747 -226.44726 5.73497 -0.28653 23.01580 2.87137 + 0.40700 5.72205 22.60041 -227.65706 5.75787 -0.28365 22.78226 2.88586 + 0.40800 5.74453 22.37217 -228.82593 5.78053 -0.28076 22.54763 2.89982 + 0.40900 5.76679 22.14277 -229.95454 5.80296 -0.27785 22.31195 2.91328 + 0.41000 5.78882 21.91227 -231.04351 5.82516 -0.27493 22.07528 2.92623 + 0.41100 5.81061 21.68070 -232.09351 5.84711 -0.27200 21.83764 2.93870 + 0.41200 5.83218 21.44810 -233.10519 5.86883 -0.26905 21.59908 2.95068 + 0.41300 5.85351 21.21450 -234.07922 5.89031 -0.26610 21.35963 2.96218 + 0.41400 5.87461 20.97995 -235.01627 5.91155 -0.26313 21.11934 2.97322 + 0.41500 5.89547 20.74448 -235.91701 5.93255 -0.26015 20.87824 2.98381 + 0.41600 5.91610 20.50813 -236.78210 5.95331 -0.25716 20.63636 2.99395 + 0.41700 5.93649 20.27093 -237.61224 5.97382 -0.25416 20.39375 3.00365 + 0.41800 5.95664 20.03292 -238.40808 5.99409 -0.25115 20.15043 3.01292 + 0.41900 5.97655 19.79412 -239.17032 6.01412 -0.24814 19.90644 3.02177 + 0.42000 5.99623 19.55459 -239.89962 6.03391 -0.24511 19.66182 3.03021 + 0.42100 6.01566 19.31434 -240.59666 6.05345 -0.24208 19.41659 3.03825 + 0.42200 6.03485 19.07340 -241.26213 6.07274 -0.23903 19.17079 3.04590 + 0.42300 6.05381 18.83182 -241.89668 6.09179 -0.23599 18.92445 3.05316 + 0.42400 6.07252 18.58962 -242.50100 6.11059 -0.23293 18.67759 3.06005 + 0.42500 6.09099 18.34683 -243.07575 6.12914 -0.22987 18.43026 3.06657 + 0.42600 6.10921 18.10348 -243.62160 6.14745 -0.22680 18.18247 3.07274 + 0.42700 6.12719 17.85960 -244.13921 6.16551 -0.22372 17.93425 3.07855 + 0.42800 6.14493 17.61521 -244.62924 6.18332 -0.22064 17.68564 3.08403 + 0.42900 6.16242 17.37035 -245.09234 6.20088 -0.21755 17.43665 3.08918 + 0.43000 6.17967 17.12503 -245.52916 6.21819 -0.21446 17.18732 3.09400 + 0.43100 6.19667 16.87930 -245.94035 6.23525 -0.21136 16.93766 3.09851 + 0.43200 6.21343 16.63316 -246.32653 6.25207 -0.20826 16.68771 3.10271 + 0.43300 6.22994 16.38665 -246.68835 6.26863 -0.20516 16.43749 3.10661 + 0.43400 6.24620 16.13979 -247.02642 6.28494 -0.20205 16.18701 3.11023 + 0.43500 6.26222 15.89261 -247.34137 6.30100 -0.19894 15.93631 3.11356 + 0.43600 6.27799 15.64512 -247.63380 6.31681 -0.19582 15.68539 3.11662 + 0.43700 6.29351 15.39735 -247.90431 6.33237 -0.19271 15.43430 3.11941 + 0.43800 6.30878 15.14932 -248.15351 6.34768 -0.18958 15.18303 3.12195 + 0.43900 6.32381 14.90105 -248.38198 6.36274 -0.18646 14.93162 3.12423 + 0.44000 6.33858 14.65256 -248.59029 6.37754 -0.18334 14.68009 3.12627 + 0.44100 6.35311 14.40387 -248.77902 6.39210 -0.18021 14.42844 3.12808 + 0.44200 6.36739 14.15501 -248.94873 6.40640 -0.17708 14.17670 3.12965 + 0.44300 6.38142 13.90598 -249.09997 6.42045 -0.17395 13.92489 3.13101 + 0.44400 6.39520 13.65681 -249.23328 6.43425 -0.17082 13.67303 3.13215 + 0.44500 6.40874 13.40752 -249.34919 6.44780 -0.16769 13.42112 3.13308 + 0.44600 6.42202 13.15812 -249.44823 6.46109 -0.16455 13.16919 3.13382 + 0.44700 6.43505 12.90863 -249.53091 6.47414 -0.16142 12.91724 3.13435 + 0.44800 6.44784 12.65906 -249.59773 6.48693 -0.15828 12.66530 3.13471 + 0.44900 6.46037 12.40944 -249.64919 6.49947 -0.15515 12.41338 3.13487 + 0.45000 6.47265 12.15977 -249.68576 6.51176 -0.15201 12.16149 3.13487 + 0.45100 6.48469 11.91007 -249.70792 6.52379 -0.14888 11.90964 3.13469 + 0.45200 6.49647 11.66036 -249.71613 6.53557 -0.14574 11.65785 3.13435 + 0.45300 6.50801 11.41064 -249.71084 6.54711 -0.14261 11.40613 3.13386 + 0.45400 6.51930 11.16094 -249.69248 6.55839 -0.13948 11.15449 3.13321 + 0.45500 6.53033 10.91126 -249.66149 6.56942 -0.13634 10.90294 3.13241 + 0.45600 6.54112 10.66162 -249.61827 6.58019 -0.13321 10.65149 3.13147 + 0.45700 6.55166 10.41203 -249.56324 6.59072 -0.13008 10.40016 3.13040 + 0.45800 6.56194 10.16250 -249.49678 6.60099 -0.12695 10.14894 3.12919 + 0.45900 6.57198 9.91304 -249.41929 6.61102 -0.12382 9.89786 3.12786 + 0.46000 6.58177 9.66366 -249.33112 6.62079 -0.12070 9.64692 3.12641 + 0.46100 6.59131 9.41438 -249.23264 6.63031 -0.11757 9.39612 3.12484 + 0.46200 6.60060 9.16520 -249.12419 6.63958 -0.11445 9.14548 3.12316 + 0.46300 6.60964 8.91614 -249.00611 6.64860 -0.11132 8.89501 3.12136 + 0.46400 6.61843 8.66719 -248.87872 6.65737 -0.10820 8.64471 3.11947 + 0.46500 6.62697 8.41838 -248.74234 6.66589 -0.10508 8.39459 3.11747 + 0.46600 6.63527 8.16971 -248.59726 6.67416 -0.10197 8.14466 3.11537 + 0.46700 6.64331 7.92119 -248.44376 6.68218 -0.09885 7.89492 3.11318 + 0.46800 6.65111 7.67283 -248.28214 6.68995 -0.09574 7.64538 3.11091 + 0.46900 6.65866 7.42463 -248.11264 6.69747 -0.09263 7.39604 3.10854 + 0.47000 6.66596 7.17660 -247.93553 6.70474 -0.08953 7.14692 3.10609 + 0.47100 6.67301 6.92876 -247.75103 6.71176 -0.08642 6.89802 3.10357 + 0.47200 6.67982 6.68110 -247.55939 6.71854 -0.08332 6.64933 3.10096 + 0.47300 6.68637 6.43364 -247.36081 6.72506 -0.08022 6.40088 3.09828 + 0.47400 6.69268 6.18639 -247.15550 6.73134 -0.07712 6.15266 3.09552 + 0.47500 6.69875 5.93934 -246.94365 6.73737 -0.07403 5.90467 3.09270 + 0.47600 6.70456 5.69250 -246.72544 6.74315 -0.07094 5.65693 3.08981 + 0.47700 6.71013 5.44589 -246.50104 6.74868 -0.06785 5.40943 3.08685 + 0.47800 6.71545 5.19950 -246.27061 6.75397 -0.06476 5.16219 3.08383 + 0.47900 6.72053 4.95335 -246.03429 6.75901 -0.06168 4.91520 3.08075 + 0.48000 6.72536 4.70743 -245.79222 6.76380 -0.05860 4.66847 3.07761 + 0.48100 6.72995 4.46176 -245.54451 6.76834 -0.05552 4.42200 3.07440 + 0.48200 6.73428 4.21635 -245.29128 6.77264 -0.05245 4.17580 3.07114 + 0.48300 6.73838 3.97118 -245.03262 6.77670 -0.04938 3.92986 3.06783 + 0.48400 6.74223 3.72628 -244.76862 6.78050 -0.04632 3.68420 3.06446 + 0.48500 6.74583 3.48165 -244.49936 6.78406 -0.04325 3.43882 3.06103 + 0.48600 6.74919 3.23729 -244.22489 6.78738 -0.04019 3.19372 3.05755 + 0.48700 6.75231 2.99320 -243.94527 6.79045 -0.03714 2.94890 3.05402 + 0.48800 6.75518 2.74940 -243.66055 6.79328 -0.03409 2.70437 3.05043 + 0.48900 6.75780 2.50588 -243.37074 6.79586 -0.03104 2.46014 3.04679 + 0.49000 6.76019 2.26266 -243.07587 6.79820 -0.02799 2.21619 3.04310 + 0.49100 6.76233 2.01973 -242.77594 6.80029 -0.02495 1.97254 3.03936 + 0.49200 6.76423 1.77711 -242.47096 6.80214 -0.02191 1.72919 3.03556 + 0.49300 6.76588 1.53479 -242.16090 6.80375 -0.01888 1.48615 3.03172 + 0.49400 6.76730 1.29279 -241.84573 6.80512 -0.01585 1.24341 3.02781 + 0.49500 6.76847 1.05110 -241.52543 6.80624 -0.01282 1.00099 3.02386 + 0.49600 6.76940 0.80974 -241.19994 6.80712 -0.00980 0.75887 3.01985 + 0.49700 6.77009 0.56870 -240.86921 6.80776 -0.00679 0.51708 3.01579 + 0.49800 6.77054 0.32800 -240.53316 6.80815 -0.00377 0.27560 3.01167 + 0.49900 6.77075 0.08764 -240.19171 6.80831 -0.00076 0.03445 3.00749 + 0.50000 6.77071 -0.15238 -239.84478 6.80822 0.00224 -0.20637 3.00325 + 0.50100 6.77044 -0.39205 -239.49227 6.80790 0.00524 -0.44685 2.99896 + 0.50200 6.76993 -0.63136 -239.13406 6.80733 0.00824 -0.68701 2.99460 + 0.50300 6.76918 -0.87032 -238.77003 6.80652 0.01123 -0.92682 2.99018 + 0.50400 6.76819 -1.10890 -238.40006 6.80547 0.01422 -1.16628 2.98570 + 0.50500 6.76696 -1.34711 -238.02400 6.80419 0.01721 -1.40540 2.98115 + 0.50600 6.76549 -1.58495 -237.64171 6.80266 0.02018 -1.64416 2.97653 + 0.50700 6.76379 -1.82239 -237.25301 6.80090 0.02316 -1.88256 2.97184 + 0.50800 6.76185 -2.05945 -236.85776 6.79890 0.02613 -2.12060 2.96707 + 0.50900 6.75967 -2.29611 -236.45575 6.79666 0.02909 -2.35827 2.96223 + 0.51000 6.75726 -2.53236 -236.04682 6.79418 0.03205 -2.59556 2.95732 + 0.51100 6.75461 -2.76820 -235.63076 6.79147 0.03501 -2.83248 2.95232 + 0.51200 6.75172 -3.00362 -235.20737 6.78852 0.03796 -3.06901 2.94724 + 0.51300 6.74860 -3.23861 -234.77643 6.78533 0.04090 -3.30515 2.94208 + 0.51400 6.74524 -3.47317 -234.33772 6.78191 0.04384 -3.54088 2.93682 + 0.51500 6.74165 -3.70728 -233.89101 6.77825 0.04678 -3.77622 2.93148 + 0.51600 6.73783 -3.94095 -233.43606 6.77436 0.04970 -4.01114 2.92604 + 0.51700 6.73377 -4.17415 -232.97263 6.77023 0.05263 -4.24564 2.92050 + 0.51800 6.72948 -4.40689 -232.50046 6.76586 0.05554 -4.47972 2.91486 + 0.51900 6.72496 -4.63915 -232.01928 6.76127 0.05846 -4.71336 2.90911 + 0.52000 6.72020 -4.87093 -231.52884 6.75644 0.06136 -4.94656 2.90326 + 0.52100 6.71522 -5.10221 -231.02884 6.75137 0.06426 -5.17931 2.89729 + 0.52200 6.71000 -5.33298 -230.51901 6.74608 0.06716 -5.41161 2.89120 + 0.52300 6.70455 -5.56324 -229.99906 6.74055 0.07005 -5.64343 2.88500 + 0.52400 6.69887 -5.79298 -229.46869 6.73479 0.07293 -5.87478 2.87867 + 0.52500 6.69297 -6.02217 -228.92760 6.72880 0.07580 -6.10564 2.87222 + 0.52600 6.68683 -6.25083 -228.37548 6.72258 0.07867 -6.33601 2.86563 + 0.52700 6.68046 -6.47892 -227.81200 6.71613 0.08153 -6.56587 2.85891 + 0.52800 6.67387 -6.70645 -227.23686 6.70945 0.08439 -6.79521 2.85204 + 0.52900 6.66705 -6.93339 -226.64973 6.70254 0.08724 -7.02402 2.84503 + 0.53000 6.66000 -7.15974 -226.05028 6.69540 0.09008 -7.25230 2.83788 + 0.53100 6.65273 -7.38549 -225.43816 6.68804 0.09291 -7.48002 2.83056 + 0.53200 6.64523 -7.61061 -224.81305 6.68044 0.09574 -7.70718 2.82309 + 0.53300 6.63751 -7.83511 -224.17459 6.67262 0.09856 -7.93376 2.81546 + 0.53400 6.62956 -8.05896 -223.52244 6.66457 0.10137 -8.15976 2.80766 + 0.53500 6.62139 -8.28215 -222.85625 6.65630 0.10418 -8.38515 2.79969 + 0.53600 6.61300 -8.50467 -222.17566 6.64780 0.10697 -8.60993 2.79154 + 0.53700 6.60438 -8.72650 -221.48032 6.63908 0.10976 -8.83408 2.78321 + 0.53800 6.59555 -8.94762 -220.76987 6.63014 0.11254 -9.05758 2.77469 + 0.53900 6.58649 -9.16803 -220.04395 6.62097 0.11531 -9.28042 2.76598 + 0.54000 6.57721 -9.38771 -219.30219 6.61158 0.11807 -9.50259 2.75707 + 0.54100 6.56771 -9.60663 -218.54422 6.60196 0.12082 -9.72407 2.74796 + 0.54200 6.55800 -9.82479 -217.76969 6.59213 0.12356 -9.94484 2.73865 + 0.54300 6.54806 -10.04216 -216.97822 6.58207 0.12630 -10.16489 2.72912 + 0.54400 6.53791 -10.25874 -216.16945 6.57180 0.12902 -10.38420 2.71938 + 0.54500 6.52755 -10.47450 -215.34301 6.56131 0.13174 -10.60275 2.70942 + 0.54600 6.51697 -10.68942 -214.49855 6.55059 0.13444 -10.82053 2.69923 + 0.54700 6.50617 -10.90349 -213.63568 6.53966 0.13714 -11.03751 2.68881 + 0.54800 6.49516 -11.11668 -212.75405 6.52852 0.13982 -11.25367 2.67816 + 0.54900 6.48394 -11.32899 -211.85330 6.51716 0.14249 -11.46901 2.66726 + 0.55000 6.47250 -11.54038 -210.93306 6.50558 0.14515 -11.68350 2.65612 + 0.55100 6.46086 -11.75085 -209.99299 6.49379 0.14780 -11.89711 2.64472 + 0.55200 6.44900 -11.96036 -209.03272 6.48179 0.15044 -12.10983 2.63307 + 0.55300 6.43694 -12.16891 -208.05191 6.46957 0.15307 -12.32163 2.62116 + 0.55400 6.42466 -12.37646 -207.05022 6.45714 0.15569 -12.53251 2.60899 + 0.55500 6.41218 -12.58300 -206.02729 6.44451 0.15829 -12.74242 2.59654 + 0.55600 6.39950 -12.78851 -204.98280 6.43166 0.16088 -12.95136 2.58382 + 0.55700 6.38661 -12.99296 -203.91642 6.41860 0.16346 -13.15930 2.57082 + 0.55800 6.37351 -13.19633 -202.82782 6.40534 0.16602 -13.36621 2.55753 + 0.55900 6.36021 -13.39861 -201.71668 6.39187 0.16857 -13.57207 2.54396 + 0.56000 6.34671 -13.59976 -200.58269 6.37820 0.17111 -13.77686 2.53010 + 0.56100 6.33301 -13.79976 -199.42556 6.36432 0.17363 -13.98056 2.51593 + 0.56200 6.31912 -13.99860 -198.24497 6.35024 0.17614 -14.18314 2.50147 + 0.56300 6.30502 -14.19625 -197.04066 6.33595 0.17863 -14.38457 2.48670 + 0.56400 6.29072 -14.39268 -195.81234 6.32147 0.18111 -14.58483 2.47162 + 0.56500 6.27623 -14.58786 -194.55975 6.30678 0.18358 -14.78390 2.45623 + 0.56600 6.26155 -14.78179 -193.28262 6.29190 0.18603 -14.98174 2.44052 + 0.56700 6.24667 -14.97442 -191.98071 6.27682 0.18846 -15.17833 2.42449 + 0.56800 6.23160 -15.16574 -190.65378 6.26154 0.19087 -15.37365 2.40813 + 0.56900 6.21634 -15.35572 -189.30161 6.24607 0.19327 -15.56767 2.39145 + 0.57000 6.20089 -15.54433 -187.92399 6.23041 0.19566 -15.76036 2.37444 + 0.57100 6.18525 -15.73156 -186.52072 6.21455 0.19802 -15.95169 2.35709 + 0.57200 6.16943 -15.91737 -185.09162 6.19851 0.20037 -16.14163 2.33941 + 0.57300 6.15342 -16.10173 -183.63650 6.18227 0.20270 -16.33016 2.32139 + 0.57400 6.13722 -16.28463 -182.15521 6.16585 0.20501 -16.51725 2.30302 + 0.57500 6.12085 -16.46603 -180.64762 6.14924 0.20731 -16.70287 2.28432 + 0.57600 6.10429 -16.64592 -179.11358 6.13244 0.20958 -16.88699 2.26526 + 0.57700 6.08756 -16.82425 -177.55299 6.11546 0.21184 -17.06959 2.24586 + 0.57800 6.07064 -17.00101 -175.96575 6.09830 0.21407 -17.25062 2.22611 + 0.57900 6.05355 -17.17618 -174.35178 6.08096 0.21629 -17.43007 2.20601 + 0.58000 6.03629 -17.34971 -172.71101 6.06344 0.21849 -17.60790 2.18556 + 0.58100 6.01886 -17.52159 -171.04341 6.04575 0.22066 -17.78409 2.16475 + 0.58200 6.00125 -17.69179 -169.34894 6.02788 0.22282 -17.95860 2.14359 + 0.58300 5.98347 -17.86028 -167.62759 6.00983 0.22495 -18.13141 2.12207 + 0.58400 5.96553 -18.02703 -165.87937 5.99161 0.22706 -18.30248 2.10020 + 0.58500 5.94742 -18.19203 -164.10431 5.97323 0.22915 -18.47178 2.07798 + 0.58600 5.92915 -18.35523 -162.30246 5.95467 0.23121 -18.63930 2.05540 + 0.58700 5.91071 -18.51662 -160.47387 5.93595 0.23326 -18.80498 2.03246 + 0.58800 5.89211 -18.67617 -158.61865 5.91706 0.23528 -18.96881 2.00918 + 0.58900 5.87336 -18.83385 -156.73688 5.89801 0.23728 -19.13076 1.98554 + 0.59000 5.85445 -18.98964 -154.82871 5.87880 0.23925 -19.29079 1.96155 + 0.59100 5.83538 -19.14350 -152.89428 5.85943 0.24120 -19.44887 1.93721 + 0.59200 5.81616 -19.29542 -150.93376 5.83990 0.24313 -19.60498 1.91252 + 0.59300 5.79679 -19.44536 -148.94733 5.82022 0.24503 -19.75909 1.88749 + 0.59400 5.77727 -19.59330 -146.93522 5.80039 0.24690 -19.91117 1.86211 + 0.59500 5.75760 -19.73922 -144.89764 5.78040 0.24875 -20.06118 1.83640 + 0.59600 5.73779 -19.88309 -142.83487 5.76026 0.25057 -20.20910 1.81035 + 0.59700 5.71784 -20.02488 -140.74717 5.73998 0.25237 -20.35490 1.78396 + 0.59800 5.69774 -20.16458 -138.63484 5.71955 0.25414 -20.49856 1.75724 + 0.59900 5.67751 -20.30214 -136.49820 5.69899 0.25588 -20.64003 1.73020 + 0.60000 5.65714 -20.43756 -134.33760 5.67828 0.25760 -20.77931 1.70284 + 0.60100 5.63663 -20.57081 -132.15339 5.65743 0.25929 -20.91635 1.67516 + 0.60200 5.61600 -20.70186 -129.94597 5.63644 0.26095 -21.05113 1.64716 + 0.60300 5.59523 -20.83070 -127.71574 5.61533 0.26258 -21.18363 1.61886 + 0.60400 5.57434 -20.95729 -125.46314 5.59408 0.26419 -21.31382 1.59026 + 0.60500 5.55332 -21.08162 -123.18860 5.57270 0.26576 -21.44167 1.56136 + 0.60600 5.53217 -21.20366 -120.89262 5.55119 0.26731 -21.56716 1.53217 + 0.60700 5.51091 -21.32339 -118.57567 5.52957 0.26883 -21.69026 1.50270 + 0.60800 5.48953 -21.44080 -116.23827 5.50781 0.27032 -21.81095 1.47296 + 0.60900 5.46803 -21.55586 -113.88097 5.48594 0.27177 -21.92921 1.44294 + 0.61000 5.44642 -21.66856 -111.50431 5.46396 0.27320 -22.04501 1.41266 + 0.61100 5.42469 -21.77887 -109.10888 5.44186 0.27460 -22.15833 1.38212 + 0.61200 5.40286 -21.88677 -106.69526 5.41964 0.27597 -22.26915 1.35134 + 0.61300 5.38092 -21.99225 -104.26407 5.39732 0.27730 -22.37744 1.32032 + 0.61400 5.35888 -22.09529 -101.81596 5.37489 0.27861 -22.48319 1.28907 + 0.61500 5.33673 -22.19588 -99.35156 5.35235 0.27988 -22.58638 1.25760 + 0.61600 5.31449 -22.29399 -96.87155 5.32972 0.28112 -22.68699 1.22591 + 0.61700 5.29214 -22.38962 -94.37663 5.30698 0.28233 -22.78500 1.19402 + 0.61800 5.26971 -22.48274 -91.86749 5.28415 0.28351 -22.88039 1.16193 + 0.61900 5.24718 -22.57335 -89.34486 5.26122 0.28466 -22.97314 1.12966 + 0.62000 5.22456 -22.66142 -86.80947 5.23820 0.28577 -23.06325 1.09722 + 0.62100 5.20186 -22.74696 -84.26209 5.21509 0.28685 -23.15069 1.06461 + 0.62200 5.17907 -22.82994 -81.70347 5.19190 0.28790 -23.23545 1.03185 + 0.62300 5.15620 -22.91036 -79.13440 5.16862 0.28891 -23.31753 0.99894 + 0.62400 5.13325 -22.98821 -76.55567 5.14527 0.28990 -23.39690 0.96590 + 0.62500 5.11022 -23.06347 -73.96809 5.12183 0.29085 -23.47355 0.93273 + 0.62600 5.08712 -23.13614 -71.37249 5.09832 0.29176 -23.54748 0.89945 + 0.62700 5.06395 -23.20621 -68.76968 5.07474 0.29264 -23.61867 0.86608 + 0.62800 5.04071 -23.27368 -66.16052 5.05108 0.29349 -23.68712 0.83261 + 0.62900 5.01741 -23.33853 -63.54584 5.02736 0.29431 -23.75282 0.79907 + 0.63000 4.99404 -23.40077 -60.92652 5.00358 0.29509 -23.81576 0.76546 + 0.63100 4.97060 -23.46039 -58.30341 4.97973 0.29584 -23.87594 0.73179 + 0.63200 4.94712 -23.51738 -55.67739 4.95583 0.29656 -23.93335 0.69809 + 0.63300 4.92357 -23.57174 -53.04934 4.93187 0.29724 -23.98799 0.66435 + 0.63400 4.89997 -23.62347 -50.42015 4.90785 0.29788 -24.03986 0.63059 + 0.63500 4.87632 -23.67258 -47.79069 4.88379 0.29850 -24.08896 0.59683 + 0.63600 4.85263 -23.71906 -45.16187 4.85968 0.29908 -24.13528 0.56307 + 0.63700 4.82889 -23.76290 -42.53458 4.83552 0.29962 -24.17883 0.52933 + 0.63800 4.80510 -23.80413 -39.90972 4.81132 0.30014 -24.21960 0.49562 + 0.63900 4.78128 -23.84272 -37.28818 4.78708 0.30062 -24.25761 0.46195 + 0.64000 4.75742 -23.87870 -34.67086 4.76281 0.30106 -24.29285 0.42834 + 0.64100 4.73352 -23.91207 -32.05865 4.73850 0.30147 -24.32533 0.39479 + 0.64200 4.70960 -23.94282 -29.45245 4.71416 0.30185 -24.35505 0.36132 + 0.64300 4.68564 -23.97098 -26.85316 4.68979 0.30219 -24.38203 0.32794 + 0.64400 4.66165 -23.99653 -24.26165 4.66539 0.30251 -24.40627 0.29466 + 0.64500 4.63765 -24.01950 -21.67882 4.64097 0.30278 -24.42778 0.26149 + 0.64600 4.61362 -24.03989 -19.10553 4.61654 0.30303 -24.44656 0.22845 + 0.64700 4.58957 -24.05772 -16.54267 4.59208 0.30324 -24.46264 0.19555 + 0.64800 4.56550 -24.07298 -13.99108 4.56761 0.30342 -24.47602 0.16280 + 0.64900 4.54142 -24.08570 -11.45164 4.54313 0.30357 -24.48672 0.13021 + 0.65000 4.51733 -24.09589 -8.92518 4.51864 0.30368 -24.49475 0.09779 + 0.65100 4.49323 -24.10356 -6.41254 4.49414 0.30376 -24.50013 0.06556 + 0.65200 4.46913 -24.10872 -3.91455 4.46964 0.30381 -24.50286 0.03352 + 0.65300 4.44501 -24.11139 -1.43202 4.44514 0.30383 -24.50298 0.00168 + 0.65400 4.42090 -24.11159 1.03424 4.42064 0.30382 -24.50049 -0.02994 + 0.65500 4.39679 -24.10933 3.48344 4.39614 0.30377 -24.49541 -0.06133 + 0.65600 4.37269 -24.10463 5.91481 4.37165 0.30369 -24.48778 -0.09248 + 0.65700 4.34858 -24.09751 8.32759 4.34716 0.30358 -24.47759 -0.12339 + 0.65800 4.32449 -24.08798 10.72102 4.32269 0.30345 -24.46489 -0.15404 + 0.65900 4.30041 -24.07607 13.09438 4.29823 0.30328 -24.44968 -0.18442 + 0.66000 4.27634 -24.06180 15.44695 4.27379 0.30308 -24.43200 -0.21452 + 0.66100 4.25229 -24.04518 17.77802 4.24937 0.30285 -24.41186 -0.24434 + 0.66200 4.22825 -24.02625 20.08692 4.22497 0.30259 -24.38930 -0.27386 + 0.66300 4.20423 -24.00502 22.37298 4.20059 0.30230 -24.36433 -0.30308 + 0.66400 4.18024 -23.98151 24.63556 4.17624 0.30198 -24.33699 -0.33199 + 0.66500 4.15627 -23.95575 26.87403 4.15192 0.30164 -24.30730 -0.36058 + 0.66600 4.13233 -23.92777 29.08778 4.12763 0.30126 -24.27528 -0.38883 + 0.66700 4.10842 -23.89759 31.27622 4.10337 0.30086 -24.24097 -0.41675 + 0.66800 4.08454 -23.86523 33.43878 4.07915 0.30043 -24.20439 -0.44433 + 0.66900 4.06069 -23.83072 35.57491 4.05496 0.29997 -24.16558 -0.47155 + 0.67000 4.03688 -23.79409 37.68409 4.03082 0.29949 -24.12457 -0.49842 + 0.67100 4.01310 -23.75536 39.76581 4.00671 0.29897 -24.08138 -0.52492 + 0.67200 3.98937 -23.71456 41.81958 3.98265 0.29844 -24.03605 -0.55105 + 0.67300 3.96567 -23.67173 43.84493 3.95864 0.29787 -23.98860 -0.57680 + 0.67400 3.94202 -23.62688 45.84143 3.93468 0.29728 -23.93908 -0.60218 + 0.67500 3.91842 -23.58006 47.80865 3.91076 0.29667 -23.88751 -0.62716 + 0.67600 3.89486 -23.53128 49.74619 3.88690 0.29603 -23.83392 -0.65175 + 0.67700 3.87136 -23.48057 51.65368 3.86310 0.29536 -23.77836 -0.67594 + 0.67800 3.84790 -23.42798 53.53075 3.83935 0.29468 -23.72085 -0.69973 + 0.67900 3.82450 -23.37352 55.37708 3.81566 0.29396 -23.66143 -0.72311 + 0.68000 3.80116 -23.31724 57.19234 3.79203 0.29323 -23.60013 -0.74609 + 0.68100 3.77787 -23.25915 58.97626 3.76846 0.29247 -23.53698 -0.76865 + 0.68200 3.75464 -23.19929 60.72856 3.74495 0.29169 -23.47203 -0.79079 + 0.68300 3.73147 -23.13770 62.44899 3.72151 0.29089 -23.40531 -0.81251 + 0.68400 3.70836 -23.07441 64.13734 3.69814 0.29007 -23.33685 -0.83381 + 0.68500 3.68532 -23.00944 65.79339 3.67484 0.28922 -23.26669 -0.85468 + 0.68600 3.66234 -22.94283 67.41697 3.65161 0.28836 -23.19486 -0.87513 + 0.68700 3.63944 -22.87462 69.00791 3.62845 0.28747 -23.12141 -0.89514 + 0.68800 3.61660 -22.80483 70.56608 3.60537 0.28657 -23.04636 -0.91473 + 0.68900 3.59383 -22.73349 72.09135 3.58236 0.28564 -22.96975 -0.93389 + 0.69000 3.57113 -22.66065 73.58364 3.55943 0.28470 -22.89162 -0.95261 + 0.69100 3.54851 -22.58634 75.04285 3.53658 0.28374 -22.81201 -0.97090 + 0.69200 3.52596 -22.51058 76.46893 3.51380 0.28276 -22.73095 -0.98875 + 0.69300 3.50349 -22.43341 77.86184 3.49111 0.28176 -22.64848 -1.00617 + 0.69400 3.48109 -22.35487 79.22157 3.46851 0.28075 -22.56463 -1.02316 + 0.69500 3.45878 -22.27498 80.54812 3.44599 0.27972 -22.47945 -1.03971 + 0.69600 3.43654 -22.19378 81.84150 3.42355 0.27867 -22.39296 -1.05583 + 0.69700 3.41439 -22.11131 83.10174 3.40120 0.27760 -22.30520 -1.07152 + 0.69800 3.39232 -22.02759 84.32891 3.37894 0.27652 -22.21621 -1.08678 + 0.69900 3.37033 -21.94266 85.52308 3.35677 0.27543 -22.12603 -1.10161 + 0.70000 3.34843 -21.85655 86.68434 3.33469 0.27432 -22.03469 -1.11601 + 0.70100 3.32662 -21.76930 87.81278 3.31270 0.27320 -21.94222 -1.12998 + 0.70200 3.30490 -21.68094 88.90855 3.29080 0.27206 -21.84867 -1.14353 + 0.70300 3.28326 -21.59150 89.97176 3.26900 0.27091 -21.75406 -1.15666 + 0.70400 3.26171 -21.50101 91.00258 3.24730 0.26975 -21.65843 -1.16937 + 0.70500 3.24026 -21.40950 92.00118 3.22569 0.26857 -21.56181 -1.18166 + 0.70600 3.21889 -21.31701 92.96774 3.20417 0.26739 -21.46425 -1.19354 + 0.70700 3.19762 -21.22358 93.90245 3.18276 0.26619 -21.36577 -1.20501 + 0.70800 3.17645 -21.12922 94.80553 3.16144 0.26498 -21.26641 -1.21606 + 0.70900 3.15537 -21.03398 95.67720 3.14023 0.26375 -21.16620 -1.22672 + 0.71000 3.13438 -20.93788 96.51769 3.11911 0.26252 -21.06518 -1.23697 + 0.71100 3.11349 -20.84095 97.32725 3.09810 0.26128 -20.96337 -1.24682 + 0.71200 3.09270 -20.74323 98.10615 3.07718 0.26003 -20.86081 -1.25628 + 0.71300 3.07200 -20.64475 98.85465 3.05637 0.25877 -20.75754 -1.26535 + 0.71400 3.05141 -20.54553 99.57304 3.03567 0.25750 -20.65358 -1.27403 + 0.71500 3.03091 -20.44561 100.26161 3.01507 0.25622 -20.54897 -1.28233 + 0.71600 3.01052 -20.34502 100.92065 2.99457 0.25493 -20.44373 -1.29026 + 0.71700 2.99022 -20.24378 101.55049 2.97418 0.25364 -20.33790 -1.29781 + 0.71800 2.97003 -20.14193 102.15143 2.95389 0.25234 -20.23151 -1.30499 + 0.71900 2.94994 -20.03949 102.72381 2.93372 0.25103 -20.12459 -1.31180 + 0.72000 2.92995 -19.93649 103.26796 2.91365 0.24971 -20.01716 -1.31826 + 0.72100 2.91007 -19.83296 103.78423 2.89368 0.24839 -19.90926 -1.32436 + 0.72200 2.89029 -19.72893 104.27296 2.87383 0.24707 -19.80092 -1.33011 + 0.72300 2.87061 -19.62442 104.73451 2.85408 0.24573 -19.69216 -1.33551 + 0.72400 2.85104 -19.51947 105.16925 2.83444 0.24440 -19.58301 -1.34057 + 0.72500 2.83157 -19.41409 105.57754 2.81492 0.24305 -19.47351 -1.34530 + 0.72600 2.81221 -19.30832 105.95976 2.79550 0.24170 -19.36366 -1.34970 + 0.72700 2.79295 -19.20218 106.31628 2.77619 0.24035 -19.25351 -1.35377 + 0.72800 2.77381 -19.09570 106.64749 2.75699 0.23900 -19.14308 -1.35753 + 0.72900 2.75476 -18.98890 106.95377 2.73790 0.23764 -19.03239 -1.36096 + 0.73000 2.73583 -18.88180 107.23551 2.71892 0.23628 -18.92148 -1.36409 + 0.73100 2.71700 -18.77443 107.49311 2.70006 0.23491 -18.81035 -1.36691 + 0.73200 2.69828 -18.66682 107.72696 2.68130 0.23354 -18.69905 -1.36944 + 0.73300 2.67967 -18.55899 107.93746 2.66266 0.23217 -18.58759 -1.37167 + 0.73400 2.66116 -18.45095 108.12502 2.64413 0.23080 -18.47599 -1.37361 + 0.73500 2.64276 -18.34275 108.29003 2.62571 0.22942 -18.36428 -1.37527 + 0.73600 2.62448 -18.23438 108.43289 2.60740 0.22805 -18.25249 -1.37666 + 0.73700 2.60630 -18.12589 108.55402 2.58920 0.22667 -18.14063 -1.37777 + 0.73800 2.58822 -18.01728 108.65382 2.57112 0.22529 -18.02872 -1.37861 + 0.73900 2.57026 -17.90859 108.73269 2.55315 0.22391 -17.91679 -1.37919 + 0.74000 2.55241 -17.79982 108.79104 2.53529 0.22253 -17.80485 -1.37952 + 0.74100 2.53466 -17.69101 108.82928 2.51754 0.22115 -17.69293 -1.37959 + 0.74200 2.51702 -17.58217 108.84781 2.49990 0.21978 -17.58105 -1.37942 + 0.74300 2.49950 -17.47332 108.84704 2.48237 0.21840 -17.46922 -1.37901 + 0.74400 2.48208 -17.36448 108.82737 2.46496 0.21702 -17.35747 -1.37836 + 0.74500 2.46477 -17.25567 108.78921 2.44766 0.21564 -17.24582 -1.37749 + 0.74600 2.44757 -17.14691 108.73295 2.43047 0.21426 -17.13427 -1.37639 + 0.74700 2.43047 -17.03821 108.65900 2.41339 0.21289 -17.02285 -1.37507 + 0.74800 2.41349 -16.92960 108.56776 2.39642 0.21151 -16.91158 -1.37354 + 0.74900 2.39662 -16.82108 108.45961 2.37957 0.21014 -16.80047 -1.37180 + 0.75000 2.37985 -16.71268 108.33496 2.36282 0.20877 -16.68954 -1.36985 + 0.75100 2.36319 -16.60442 108.19420 2.34619 0.20740 -16.57881 -1.36771 + 0.75200 2.34664 -16.49630 108.03770 2.32967 0.20603 -16.46828 -1.36537 + 0.75300 2.33020 -16.38835 107.86587 2.31325 0.20467 -16.35798 -1.36285 + 0.75400 2.31386 -16.28057 107.67907 2.29695 0.20331 -16.24792 -1.36014 + 0.75500 2.29764 -16.17300 107.47770 2.28076 0.20195 -16.13811 -1.35725 + 0.75600 2.28152 -16.06562 107.26213 2.26467 0.20059 -16.02857 -1.35419 + 0.75700 2.26550 -15.95848 107.03272 2.24870 0.19924 -15.91932 -1.35096 + 0.75800 2.24960 -15.85156 106.78985 2.23283 0.19789 -15.81035 -1.34756 + 0.75900 2.23380 -15.74490 106.53389 2.21708 0.19655 -15.70170 -1.34401 + 0.76000 2.21811 -15.63850 106.26518 2.20143 0.19520 -15.59336 -1.34030 + 0.76100 2.20252 -15.53237 105.98410 2.18589 0.19387 -15.48535 -1.33644 + 0.76200 2.18704 -15.42654 105.69100 2.17046 0.19253 -15.37769 -1.33243 + 0.76300 2.17167 -15.32100 105.38622 2.15514 0.19120 -15.27038 -1.32828 + 0.76400 2.15640 -15.21577 105.07011 2.13992 0.18987 -15.16343 -1.32399 + 0.76500 2.14124 -15.11086 104.74300 2.12481 0.18855 -15.05686 -1.31958 + 0.76600 2.12618 -15.00628 104.40525 2.10981 0.18724 -14.95068 -1.31503 + 0.76700 2.11123 -14.90205 104.05717 2.09491 0.18592 -14.84489 -1.31036 + 0.76800 2.09638 -14.79817 103.69909 2.08012 0.18461 -14.73950 -1.30556 + 0.76900 2.08163 -14.69466 103.33134 2.06543 0.18331 -14.63453 -1.30066 + 0.77000 2.06699 -14.59151 102.95423 2.05085 0.18201 -14.52998 -1.29564 + 0.77100 2.05245 -14.48875 102.56808 2.03637 0.18072 -14.42586 -1.29051 + 0.77200 2.03801 -14.38638 102.17320 2.02199 0.17943 -14.32217 -1.28527 + 0.77300 2.02367 -14.28441 101.76989 2.00772 0.17815 -14.21894 -1.27994 + 0.77400 2.00944 -14.18284 101.35844 1.99356 0.17687 -14.11615 -1.27451 + 0.77500 1.99531 -14.08169 100.93915 1.97949 0.17560 -14.01383 -1.26899 + 0.77600 1.98128 -13.98097 100.51232 1.96553 0.17433 -13.91198 -1.26337 + 0.77700 1.96735 -13.88067 100.07822 1.95167 0.17307 -13.81060 -1.25767 + 0.77800 1.95352 -13.78081 99.63713 1.93791 0.17182 -13.70970 -1.25189 + 0.77900 1.93978 -13.68140 99.18934 1.92425 0.17057 -13.60929 -1.24603 + 0.78000 1.92615 -13.58244 98.73510 1.91069 0.16933 -13.50937 -1.24010 + 0.78100 1.91262 -13.48393 98.27468 1.89723 0.16809 -13.40995 -1.23409 + 0.78200 1.89918 -13.38589 97.80835 1.88387 0.16686 -13.31104 -1.22801 + 0.78300 1.88585 -13.28832 97.33636 1.87061 0.16563 -13.21263 -1.22187 + 0.78400 1.87261 -13.19122 96.85895 1.85744 0.16442 -13.11473 -1.21566 + 0.78500 1.85947 -13.09460 96.37638 1.84438 0.16320 -13.01736 -1.20939 + 0.78600 1.84642 -12.99847 95.88888 1.83141 0.16200 -12.92050 -1.20307 + 0.78700 1.83347 -12.90282 95.39669 1.81854 0.16080 -12.82417 -1.19669 + 0.78800 1.82061 -12.80768 94.90004 1.80576 0.15960 -12.72837 -1.19026 + 0.78900 1.80785 -12.71303 94.39916 1.79308 0.15842 -12.63311 -1.18379 + 0.79000 1.79519 -12.61888 93.89426 1.78049 0.15724 -12.53838 -1.17727 + 0.79100 1.78261 -12.52524 93.38558 1.76800 0.15606 -12.44419 -1.17070 + 0.79200 1.77014 -12.43211 92.87331 1.75560 0.15489 -12.35055 -1.16410 + 0.79300 1.75775 -12.33949 92.35766 1.74330 0.15373 -12.25745 -1.15745 + 0.79400 1.74546 -12.24739 91.83884 1.73109 0.15258 -12.16490 -1.15077 + 0.79500 1.73326 -12.15582 91.31706 1.71897 0.15143 -12.07290 -1.14406 + 0.79600 1.72114 -12.06476 90.79249 1.70694 0.15029 -11.98145 -1.13732 + 0.79700 1.70913 -11.97423 90.26533 1.69501 0.14916 -11.89056 -1.13055 + 0.79800 1.69720 -11.88423 89.73577 1.68316 0.14803 -11.80022 -1.12376 + 0.79900 1.68536 -11.79476 89.20398 1.67141 0.14691 -11.71045 -1.11694 + 0.80000 1.67361 -11.70582 88.67015 1.65974 0.14580 -11.62123 -1.11010 + 0.80100 1.66194 -11.61742 88.13445 1.64816 0.14469 -11.53257 -1.10324 + 0.80200 1.65037 -11.52956 87.59704 1.63668 0.14359 -11.44448 -1.09636 + 0.80300 1.63889 -11.44223 87.05808 1.62527 0.14250 -11.35695 -1.08947 + 0.80400 1.62749 -11.35544 86.51775 1.61396 0.14141 -11.26998 -1.08257 + 0.80500 1.61617 -11.26919 85.97619 1.60273 0.14033 -11.18358 -1.07565 + 0.80600 1.60495 -11.18349 85.43356 1.59159 0.13926 -11.09774 -1.06872 + 0.80700 1.59381 -11.09833 84.89000 1.58054 0.13819 -11.01247 -1.06179 + 0.80800 1.58275 -11.01371 84.34566 1.56957 0.13714 -10.92776 -1.05485 + 0.80900 1.57178 -10.92964 83.80068 1.55868 0.13608 -10.84362 -1.04791 + 0.81000 1.56089 -10.84611 83.25520 1.54788 0.13504 -10.76005 -1.04096 + 0.81100 1.55009 -10.76312 82.70934 1.53716 0.13400 -10.67704 -1.03401 + 0.81200 1.53937 -10.68069 82.16324 1.52653 0.13297 -10.59460 -1.02706 + 0.81300 1.52873 -10.59880 81.61703 1.51597 0.13195 -10.51272 -1.02012 + 0.81400 1.51817 -10.51745 81.07083 1.50550 0.13093 -10.43141 -1.01318 + 0.81500 1.50769 -10.43666 80.52474 1.49511 0.12992 -10.35066 -1.00624 + 0.81600 1.49729 -10.35640 79.97890 1.48480 0.12892 -10.27047 -0.99931 + 0.81700 1.48698 -10.27670 79.43342 1.47457 0.12792 -10.19085 -0.99238 + 0.81800 1.47674 -10.19754 78.88839 1.46442 0.12693 -10.11179 -0.98547 + 0.81900 1.46658 -10.11892 78.34393 1.45435 0.12595 -10.03329 -0.97857 + 0.82000 1.45650 -10.04085 77.80014 1.44435 0.12498 -9.95535 -0.97167 + 0.82100 1.44650 -9.96332 77.25712 1.43443 0.12401 -9.87797 -0.96479 + 0.82200 1.43658 -9.88634 76.71496 1.42460 0.12305 -9.80114 -0.95793 + 0.82300 1.42673 -9.80989 76.17376 1.41483 0.12209 -9.72487 -0.95107 + 0.82400 1.41696 -9.73399 75.63361 1.40515 0.12115 -9.64916 -0.94424 + 0.82500 1.40726 -9.65862 75.09459 1.39553 0.12020 -9.57399 -0.93742 + 0.82600 1.39764 -9.58380 74.55680 1.38600 0.11927 -9.49938 -0.93062 + 0.82700 1.38809 -9.50951 74.02030 1.37653 0.11834 -9.42532 -0.92384 + 0.82800 1.37862 -9.43576 73.48519 1.36715 0.11742 -9.35180 -0.91708 + 0.82900 1.36922 -9.36254 72.95153 1.35783 0.11651 -9.27884 -0.91033 + 0.83000 1.35989 -9.28985 72.41940 1.34859 0.11560 -9.20641 -0.90361 + 0.83100 1.35064 -9.21770 71.88888 1.33942 0.11470 -9.13453 -0.89692 + 0.83200 1.34146 -9.14607 71.36003 1.33032 0.11381 -9.06318 -0.89024 + 0.83300 1.33235 -9.07498 70.83291 1.32129 0.11292 -8.99238 -0.88359 + 0.83400 1.32331 -9.00441 70.30759 1.31233 0.11204 -8.92211 -0.87697 + 0.83500 1.31434 -8.93436 69.78413 1.30345 0.11117 -8.85237 -0.87037 + 0.83600 1.30544 -8.86484 69.26260 1.29463 0.11030 -8.78317 -0.86380 + 0.83700 1.29661 -8.79584 68.74304 1.28588 0.10944 -8.71449 -0.85725 + 0.83800 1.28785 -8.72735 68.22552 1.27720 0.10859 -8.64634 -0.85073 + 0.83900 1.27915 -8.65939 67.71008 1.26859 0.10774 -8.57872 -0.84424 + 0.84000 1.27053 -8.59193 67.19678 1.26004 0.10690 -8.51161 -0.83778 + 0.84100 1.26197 -8.52499 66.68566 1.25156 0.10606 -8.44503 -0.83134 + 0.84200 1.25348 -8.45856 66.17677 1.24315 0.10524 -8.37896 -0.82494 + 0.84300 1.24505 -8.39264 65.67016 1.23481 0.10441 -8.31341 -0.81857 + 0.84400 1.23669 -8.32722 65.16586 1.22653 0.10360 -8.24837 -0.81222 + 0.84500 1.22840 -8.26230 64.66392 1.21831 0.10279 -8.18384 -0.80591 + 0.84600 1.22017 -8.19789 64.16438 1.21016 0.10199 -8.11981 -0.79963 + 0.84700 1.21200 -8.13397 63.66727 1.20207 0.10119 -8.05629 -0.79339 + 0.84800 1.20390 -8.07055 63.17263 1.19404 0.10040 -7.99327 -0.78717 + 0.84900 1.19586 -8.00763 62.68050 1.18608 0.09962 -7.93074 -0.78099 + 0.85000 1.18788 -7.94519 62.19089 1.17818 0.09884 -7.86872 -0.77484 + 0.85100 1.17997 -7.88325 61.70386 1.17035 0.09807 -7.80718 -0.76873 + 0.85200 1.17212 -7.82178 61.21942 1.16257 0.09730 -7.74614 -0.76265 + 0.85300 1.16433 -7.76081 60.73760 1.15485 0.09654 -7.68558 -0.75660 + 0.85400 1.15660 -7.70031 60.25842 1.14720 0.09579 -7.62551 -0.75059 + 0.85500 1.14893 -7.64029 59.78192 1.13960 0.09504 -7.56591 -0.74461 + 0.85600 1.14132 -7.58074 59.30811 1.13207 0.09430 -7.50680 -0.73867 + 0.85700 1.13376 -7.52167 58.83702 1.12459 0.09356 -7.44816 -0.73276 + 0.85800 1.12627 -7.46307 58.36866 1.11717 0.09283 -7.38999 -0.72689 + 0.85900 1.11884 -7.40493 57.90306 1.10981 0.09211 -7.33230 -0.72105 + 0.86000 1.11146 -7.34726 57.44023 1.10250 0.09139 -7.27507 -0.71525 + 0.86100 1.10414 -7.29005 56.98019 1.09526 0.09068 -7.21830 -0.70948 + 0.86200 1.09688 -7.23330 56.52295 1.08807 0.08997 -7.16200 -0.70376 + 0.86300 1.08968 -7.17700 56.06854 1.08093 0.08927 -7.10615 -0.69806 + 0.86400 1.08253 -7.12116 55.61695 1.07385 0.08857 -7.05076 -0.69241 + 0.86500 1.07543 -7.06577 55.16821 1.06683 0.08789 -6.99582 -0.68679 + 0.86600 1.06840 -7.01082 54.72232 1.05986 0.08720 -6.94133 -0.68121 + 0.86700 1.06141 -6.95632 54.27929 1.05295 0.08652 -6.88728 -0.67566 + 0.86800 1.05448 -6.90227 53.83913 1.04609 0.08585 -6.83367 -0.67015 + 0.86900 1.04761 -6.84865 53.40186 1.03928 0.08518 -6.78051 -0.66468 + 0.87000 1.04079 -6.79546 52.96747 1.03253 0.08452 -6.72778 -0.65925 + 0.87100 1.03402 -6.74271 52.53597 1.02583 0.08386 -6.67549 -0.65385 + 0.87200 1.02730 -6.69039 52.10737 1.01918 0.08321 -6.62363 -0.64849 + 0.87300 1.02064 -6.63849 51.68168 1.01258 0.08257 -6.57219 -0.64316 + 0.87400 1.01402 -6.58702 51.25888 1.00603 0.08193 -6.52118 -0.63788 + 0.87500 1.00746 -6.53597 50.83900 0.99954 0.08129 -6.47059 -0.63263 + 0.87600 1.00095 -6.48534 50.42202 0.99309 0.08066 -6.42042 -0.62742 + 0.87700 0.99449 -6.43513 50.00795 0.98669 0.08004 -6.37066 -0.62224 + 0.87800 0.98808 -6.38533 49.59679 0.98035 0.07942 -6.32132 -0.61710 + 0.87900 0.98172 -6.33594 49.18854 0.97405 0.07880 -6.27239 -0.61200 + 0.88000 0.97541 -6.28695 48.78320 0.96780 0.07819 -6.22386 -0.60694 + 0.88100 0.96915 -6.23837 48.38076 0.96160 0.07759 -6.17573 -0.60191 + 0.88200 0.96293 -6.19019 47.98122 0.95545 0.07699 -6.12801 -0.59692 + 0.88300 0.95677 -6.14240 47.58459 0.94935 0.07639 -6.08068 -0.59196 + 0.88400 0.95065 -6.09502 47.19085 0.94329 0.07580 -6.03375 -0.58705 + 0.88500 0.94458 -6.04802 46.80000 0.93728 0.07522 -5.98721 -0.58217 + 0.88600 0.93855 -6.00142 46.41204 0.93132 0.07464 -5.94106 -0.57732 + 0.88700 0.93257 -5.95520 46.02696 0.92540 0.07407 -5.89529 -0.57252 + 0.88800 0.92664 -5.90936 45.64476 0.91953 0.07350 -5.84991 -0.56775 + 0.88900 0.92075 -5.86391 45.26542 0.91370 0.07293 -5.80490 -0.56301 + 0.89000 0.91491 -5.81883 44.88895 0.90792 0.07237 -5.76028 -0.55831 + 0.89100 0.90912 -5.77413 44.51532 0.90218 0.07181 -5.71602 -0.55365 + 0.89200 0.90336 -5.72980 44.14455 0.89648 0.07126 -5.67214 -0.54903 + 0.89300 0.89766 -5.68584 43.77661 0.89083 0.07072 -5.62862 -0.54444 + 0.89400 0.89199 -5.64224 43.41150 0.88523 0.07017 -5.58547 -0.53988 + 0.89500 0.88637 -5.59901 43.04920 0.87966 0.06964 -5.54269 -0.53536 + 0.89600 0.88079 -5.55614 42.68972 0.87414 0.06910 -5.50026 -0.53088 + 0.89700 0.87526 -5.51363 42.33304 0.86866 0.06857 -5.45819 -0.52643 + 0.89800 0.86977 -5.47148 41.97915 0.86322 0.06805 -5.41647 -0.52202 + 0.89900 0.86432 -5.42967 41.62803 0.85783 0.06753 -5.37510 -0.51764 + 0.90000 0.85891 -5.38822 41.27968 0.85247 0.06701 -5.33408 -0.51330 diff --git a/matlab/Magnetic_Field_GLS_2020/Cryogenic/r_beam_Cryogenic_170.m b/matlab/Magnetic_Field_GLS_2020/Cryogenic/r_beam_Cryogenic_170.m new file mode 100644 index 0000000..92505fb --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/Cryogenic/r_beam_Cryogenic_170.m @@ -0,0 +1,79 @@ + function r_beam = r_beam_Cryogenic_170(magnet,I) +% +% function r_beam = r_beam_Cryogenic_170(magnet,I) +% +% Ex: >> r_beam = r_beam_Cryogenic_170('cryogenic',[57.712 , 68.596 , 107.780 , 107.780]) +% +% Returns an estimate of the electron beam radius in the cavity of the GT140 gyrotron +%% +% Version: 1.0 J.-P. Hogge Feb. 27, 2008 +% 1.1 J.-P. Hogge Nov. 23, 2011 : Refurbished first prototype parameters +% 2.0 J.-P. Hogge Aug. 10th, 2017 : Estimation based on elliptical integrals only (a bit more complicated, but more precise) +% 2.1 J.-P. Hogge Jun. 7th, 2018 : corrected minor bug (so far only cryogenic magnet was implemented. +% +% +% magnet : 'cryogenic' or any other 170GHz magnet +% +% +% Procedure: +% ---------- +% +% First the azimuthal component aphi of the vector potential is computed at the cathode. +% Then the axial component of the magnetic field in the vicinity of the axis, and +% in the cavity region is estimated. +% By applying flux conservation, the beam radius is estimated. +% +%**************************************************************************************** + +% rcat = 0.05318; % Cathode center radius [m] 1st 1MW Prototype, cold dimension (2017) +% rcat = 0.0533693; % Cathode center radius [m] 1st 1MW Prototype, warm dimension (2017) +% zcat = 0.136; % Cathode center location [m] Refurbished Prototype (2011) +% zcav = 0.4995; % Cavity location [m] +% + GT170_1MW_Geometry + +% Compute vector potential aphi at cathode location + + [Aphi] = B_Ellip_Cryogenic_170('aphi',magnet,I,r_cat,z_cat); + +% flux = 2 * pi * rcat * Aphi; + +% Compute axial magnetic field and its derivatives in cavity + +% [Bzcav,dBzcav,d2Bzcav] = B_on_axis_170('asg_modified_201206',I,zcav); + + Bzcav = B_Ellip_Cryogenic_170('bz', magnet,I,0,z_cav); + dBzcav = B_Ellip_Cryogenic_170('dbzdz', magnet,I,0,z_cav); + d2Bzcav = B_Ellip_Cryogenic_170('d2bzdz2',magnet,I,0,z_cav); + +% +% Apply flux conservation to find beam radius in cavity +% The exact flux at cathode (r_cat * Aphi) is equalled to the flux +% estimated with paraxial expansion. +% + a = 1/16 * d2Bzcav; + b = - Bzcav/2; + c = r_cat * Aphi; + + rbsq_plus = 1./(2*a) * (-b + sqrt(b^2 - 4*a*c)); + rbsq_minus = 1./(2*a) * (-b - sqrt(b^2 - 4*a*c)); + + r_beam = sqrt(rbsq_minus); + +% +% Estimation based on elliptical integrals only. +% The following equation is solved for r_beam: +% r_cat * Aphi(r_cat,z_cat) = r_beam * Aphi(r_beam,z_cav) +% + raphi_cat = r_cat * Aphi; + + myfun = @(r,z_cav,I,raphi_cat) r*B_Ellip_Cryogenic_170('aphi',magnet,I,r,z_cav)-raphi_cat; + + fun = @(r) myfun(r,z_cav,I,raphi_cat); + + r_beam = fzero(fun, 0.009); + + + + + diff --git a/matlab/Magnetic_Field_GLS_2020/Refurbished_geom.xlsx b/matlab/Magnetic_Field_GLS_2020/Refurbished_geom.xlsx new file mode 100644 index 0000000..6ee417c Binary files /dev/null and b/matlab/Magnetic_Field_GLS_2020/Refurbished_geom.xlsx differ diff --git a/matlab/Magnetic_Field_GLS_2020/body increasee.txt b/matlab/Magnetic_Field_GLS_2020/body increasee.txt new file mode 100644 index 0000000..8b406b1 --- /dev/null +++ b/matlab/Magnetic_Field_GLS_2020/body increasee.txt @@ -0,0 +1,11 @@ +crnP321 36 90.020801 +crnP322 32 90.020801 +crnP33 28 90.020801 +crnP331 24 90.020801 +crnP332 5 90.020801 +crnP34 -10 90.020801 +crnP35 -20 90.020801 +crnP36 -30 90.020801 +crnP37 -40 90.020801 +crnP38 -40 100 +crnP39 -40 110 \ No newline at end of file diff --git a/matlab/Testflux.m b/matlab/Testflux.m index ae479ef..945861b 100644 --- a/matlab/Testflux.m +++ b/matlab/Testflux.m @@ -1,139 +1,101 @@ -%% Computes the electric potential profile along the magnetic field line passing at z=0 and r=rgrid(rAthetpos) +%% +rAthetpos=30; -rAthetpos=15+27; -rAthetpos=29; - -fieldstep=length(M.t2d)-500:10:length(M.t2d); +fieldstep=length(M.t2d);%-100:5:length(M.t2d); Vpar=M.fluidUR(:,:,fieldstep).*(M.Br./M.B)' + (M.Bz./M.B)'.*M.fluidUZ(:,:,fieldstep); N=M.N(:,:,fieldstep); Gammapar=mean(N.*Vpar,3); + levels=M.rAthet(rAthetpos,floor(M.nz/2)+1)*[1 1]; rAthetposend=find(levels(1)>=M.rAthet(:,1),1,'last'); rleft=sqrt(levels(1)/(M.rAthet(rAthetposend,1)/M.rgrid(rAthetposend)^2)); - -%% triple subplot showing the magnetic field line of interest on the: -% particle density, parallel electron flux and parallel velocity surface plots -thefig=figure('Name', sprintf('%s flux line ',M.name)); +thefig=figure; sp(1)=subplot(1,3,1); contourf(M.zgrid,M.rgrid,mean(N,3),'edgecolor','none'); hold on; contour(M.zgrid,M.rgrid,M.rAthet,levels,'r-','linewidth',1.5,'Displayname','Magnetic field lines'); c=colorbar; c.Label.String='n_e [m^{-3}]'; - sp(2)=subplot(1,3,2); contourf(M.zgrid,M.rgrid,Gammapar,'edgecolor','none'); hold on contour(M.zgrid,M.rgrid,M.rAthet,levels,'r-','linewidth',1.5,'Displayname','Magnetic field lines'); c=colorbar; c.Label.String='\Gamma_{par} [m^{-2}s^{-1}]'; - sp(3)=subplot(1,3,3); contourf(M.zgrid,M.rgrid,mean(Vpar,3),'edgecolor','none'); hold on contour(M.zgrid,M.rgrid,M.rAthet,levels,'r-','linewidth',1.5,'Displayname','Magnetic field line'); c=colorbar; c.Label.String='V_{par} [ms^{-1}]'; linkaxes(sp); xlabel(sp,'z [m]') ylabel(sp,'r [m]') ylim(sp,[M.rgrid(1) M.rgrid(sum(M.nnr(1:2)))]) M.savegraph(thefig,sprintf('%s/%s_finalwellfluxline',M.folder,M.name),[12,10]) -%% Plot of the magnetic field line on the density alone -thefig=figure('Name', sprintf('%s dens line ',M.name)); -sp=gca; -contourf(M.zgrid,M.rgrid,mean(N,3),'edgecolor','none'); -hold on; -contour(M.zgrid,M.rgrid,M.rAthet,levels,'r-','linewidth',1.5,'Displayname','Magnetic field lines'); -c=colorbar; -c.Label.String='n_e [m^{-3}]'; -xlabel(sp,'z [m]') -ylabel(sp,'r [m]') -ylim(sp,[M.rgrid(1) M.rgrid(sum(M.nnr(1:2)))]) -M.savegraph(thefig,sprintf('%s/%s_finalwellline',M.folder,M.name),[9,8]) - - - -%% Computation of a prediction for the maximum potential hill height in steady state, -% depending on the external electric field, the particle maxwellian source temperature and the magnetic field mirror ratio and amplitude +%% +dN=1e13*M.weight; +dN=0; +rp=9.85e-3; +rm=7e-3; +V=2*pi*(rp^2-rm^2); +n2=mean(mean(mean(N(rAthetposend+(0:1),[1 end],:),3))); +vpar2=(dN/V/n2)^2; +actvpar2=mean(mean(abs(mean(Vpar(rAthetposend+(0:1),[1 end],:),3))))^2; b=M.rgrid(end); a=M.rgrid(1); vd1=((M.potout-M.potinn)*M.phinorm/M.rgrid(rAthetpos))/M.Bz(floor(M.nz/2)+1,rAthetpos)/log(b/a); %vd1=-M.Er(rAthetpos+5,M.nz/2+1,end)/M.Bz(M.nz/2+1,rAthetpos+5) vinit=sqrt(M.kb*10000/M.me) %vinit=sqrt(80*M.qe/M.me) vd2=((M.potout-M.potinn)*M.phinorm/rleft)/M.Bz(1,rAthetposend)/log(b/a); -deltaphi=0.5*M.me/M.qe*((vd1+vinit)^2*(1-M.Rcurv)) -%ratioparper=vpar2/((vd1+vinit)^2*(1-M.Rcurv)) +deltaphi=-0.5*M.me/M.qe*(vpar2-(vd1+vinit)^2*(1-M.Rcurv)) +ratioparper=vpar2/((vd1+vinit)^2*(1-M.Rcurv)) + +%% -%% Plot of the parallel density profile and the well along the magnetic field line of interest -thefig=figure('Name', sprintf('%s final well',M.name)); +thefig=figure; %fieldstep=fieldstep(end); plotaxes(1)=subplot(1,2,1,'Parent',thefig); plotaxes(2)=subplot(1,2,2,'Parent',thefig); dens=mean(M.N(:,:,fieldstep),3); model=M.potentialwellmodel(fieldstep); z=model.z; r=model.r; pot=model.pot; rathet=model.rathet; [Zmesh,Rmesh]=meshgrid(M.zgrid,M.rAthet(:,floor(M.nz/2)+1)); densplot=zeros(size(Zmesh,1),size(Zmesh,2),length(fieldstep)); for i=1:length(fieldstep) densplot(:,:,i)=griddata(Zmesh,M.rAthet,dens,Zmesh,Rmesh,'natural'); end plot(plotaxes(1),M.zgrid,mean(densplot(rAthetpos,1:end,:),3)); xlim(plotaxes(1),[M.zgrid(1) M.zgrid(end)]) xlabel(plotaxes(1),'z [m]') ylabel(plotaxes(1),'n [m^{-3}]') title(plotaxes(1),'Density') plotpot=zeros(size(Zmesh,1),size(Zmesh,2),length(fieldstep)); for i=1:length(fieldstep) plotpot(:,:,i)=griddata(z,rathet,pot(:,i),Zmesh,Rmesh,'natural'); end plotpot=mean(plotpot,3); plot(plotaxes(2),M.zgrid(1:end),plotpot(rAthetpos,1:end)); hold on plot(plotaxes(2),M.zgrid(1:end),deltaphi*ones(size(M.zgrid)),'k--','displayname','Analytical') xlim(plotaxes(2),[M.zgrid(1) M.zgrid(end)]) xlabel(plotaxes(2),'z [m]') ylabel(plotaxes(2),'depth [eV]') title(plotaxes(2),'Well') sgtitle(thefig,sprintf('r(0)=%1.2f [mm] t= %1.2f [ns]',M.rgrid(rAthetpos)*1e3,M.t2d(fieldstep(end))*1e9)) M.savegraph(thefig,sprintf('%s/%s_finalwell',M.folder,M.name),[15,10]) -%% Plot of the final electric potential well along the magnetic field line -thefig=figure('Name', sprintf('%s final well only',M.name)); -theplots=gobjects(2,1); -theplots(1)=plot(M.zgrid(1:end),-plotpot(rAthetpos,1:end),'displayname','Simulation'); -hold on -theplots(2)=plot(M.zgrid(1:end),-deltaphi*ones(size(M.zgrid)),'k--','displayname','\Delta\phi_{21} Prediction'); -xlim([M.zgrid(1) M.zgrid(end)]) -xlabel('z [m]') -ylabel('\phi(z)-\phi(0) [V]') -legend - -ylimits=ylim; -%annotation('textarrow',[M.zgrid(5) M.zgrid(1)]/(M.zgrid(end)-M.zgrid(1))+0.5,[-plotpot(rAthetpos,1)*1.05 -plotpot(rAthetpos,1)]/diff(ylimits),'Linewidth',2) -p1=[M.zgrid(30),-plotpot(rAthetpos,1)*1.02]; -p2=[M.zgrid(1),-plotpot(rAthetpos,1)]; -dp=p2-p1; -quiver(p1(1), p1(2), dp(1), dp(2),1,'k','showarrowhead','off') -text(p1(1),p1(2),'\Delta\phi_{21}') -title(sprintf('r(0)=%1.2f [mm] \\Delta\\phi_{ba}= %1.2g[kV] R=%1.1f',M.rgrid(rAthetpos)*1e3,(M.potout-M.potinn)*M.phinorm,M.Rcurv)) - -legend(theplots,'location','north') -M.savegraph(thefig,sprintf('%s/%s_finalwellonly',M.folder,M.name),[9,8]) - - - diff --git a/matlab/WellVideosaving.m b/matlab/WellVideosaving.m index 0f9af2b..e7813a9 100644 --- a/matlab/WellVideosaving.m +++ b/matlab/WellVideosaving.m @@ -1,139 +1,139 @@ fieldstep=1; maxN=1.4e17; Minwell=-6000; %tend=min(8000,length(M.t2d)); tend=length(M.t2d); plot3d=true; logdensity=false; fracn=0.1; rAthetpos=177; thefig=figure('Position',[0 0 1600 900]); filename=M.name; if logdensity filename=strcat(filename,'_log'); end if plot3d filename=strcat(filename,'_well3D.avi'); else filename=strcat(filename,'_well2D.avi'); end videowriterobj=VideoWriter([M.folder,'/',filename]); videowriterobj.FrameRate=5; open(videowriterobj); if plot3d plotaxes(1)=subplot(2,1,1,'Parent',thefig); plotaxes(2)=subplot(2,1,2,'Parent',thefig); sf=surface(plotaxes(1),M.zgrid,M.rgrid,M.N(:,:,fieldstep),'edgecolor','none'); hold(plotaxes(1),'on') contour(plotaxes(1),M.zgrid,M.rgrid,M.geomweight(:,:,1),[0 0],'r--') if logdensity set(plotaxes(1),'zscale','log') set(plotaxes(1),'colorscale','log') end xlim(plotaxes(1),[M.zgrid(1) M.zgrid(end)]) %ylim(plotaxes(1),[M.rgrid(1) M.rgrid(sum(M.nnr(1:2))+5)]) xlabel(plotaxes(1),'z [m]') ylabel(plotaxes(1),'r [m]') title(plotaxes(1),'Density') c = colorbar(plotaxes(1)); c.Label.String= 'n[m^{-3}]'; %caxis(plotaxes(1),[-Inf maxN]); well=M.PotentialWell(fieldstep); sf=surface(plotaxes(2),M.zgrid,M.rgrid,well','edgecolor','none'); hold(plotaxes(2),'on') dens=M.N(:,:,fieldstep); contour(plotaxes(2),M.zgrid,M.rgrid,dens-fracn*max(dens(:)),[0 0],'k--') contour(plotaxes(2),M.zgrid,M.rgrid,M.geomweight(:,:,1),[0 0],'r--') xlim(plotaxes(2),[M.zgrid(1) M.zgrid(end)]) %ylim(plotaxes(2),[M.rgrid(1) M.rgrid(sum(M.nnr(1:2))+5)]) xlabel(plotaxes(2),'z [m]') ylabel(plotaxes(2),'r [m]') title(plotaxes(2),'Well') c = colorbar(plotaxes(2)); c.Label.String= 'depth [V]'; view(plotaxes(2),2) colormap(plotaxes(2),'jet'); caxis(plotaxes(2),[Minwell 0]); zlim(plotaxes(2),[Minwell 0]); axis(plotaxes(1),'equal') axis(plotaxes(2),'equal') for i=fieldstep:80:tend sgtitle(thefig,sprintf('t= %1.2f [ns]',M.t2d(i)*1e9)) dens=M.N(:,:,i); dens(M.geomweight(:,:,1)<0)=NaN; well=M.PotentialWell(i); well=well'; plotaxes(1).Children(end).ZData=dens; plotaxes(1).Children(end).CData=dens; plotaxes(2).Children(end-1).ZData=dens-fracn*max(dens(:)); plotaxes(2).Children(end).ZData=well; plotaxes(2).Children(end).CData=well; writeVideo(videowriterobj,getframe(thefig)); end else dens=M.N(:,:,fieldstep); model=M.potentialwellmodel(fieldstep); z=model.z; r=model.r; pot=model.pot; rathet=model.rathet; [Zmesh,Rmesh]=meshgrid(M.zgrid,M.rAthet(:,1)); dens=griddata(Zmesh,M.rAthet,dens,Zmesh,Rmesh); plot(M.zgrid,dens(rAthetpos,1:end)); plotaxes(1)=gca; xlim(plotaxes(1),[M.zgrid(1) M.zgrid(end)]) ylim(plotaxes(1),[0 maxN]); xlabel(plotaxes(1),'z [m]') ylabel(plotaxes(1),'n [m^{-3}]') grid(plotaxes(1), 'on') pot=griddata(z,rathet,pot,Zmesh,Rmesh); yyaxis right plot(M.zgrid(1:end),pot(rAthetpos,1:end)); plotaxes(2)=gca; ylim(plotaxes(2),[Minwell 0]); ylabel(plotaxes(2),'depth [eV]') Curve2=plotaxes(2).Children; yyaxis left plotaxes(1)=gca; Curve1=plotaxes(1).Children; for i=fieldstep:80:tend sgtitle(thefig,sprintf('rA_\\theta=%1.3g [Tm^2] t= %1.2f [ns]',Rmesh(rAthetpos,1),M.t2d(i)*1e9)) dens=M.N(:,:,i); model=M.potentialwellmodel(i); z=model.z; r=model.r; pot=model.pot; rathet=model.rathet; [Zmesh,Rmesh]=meshgrid(M.zgrid,M.rAthet(:,1)); dens=griddata(Zmesh,M.rAthet,dens,Zmesh,Rmesh); pot=griddata(z,rathet,pot,Zmesh,Rmesh); Curve1.YData=dens(rAthetpos,1:end); Curve2.YData=pot(rAthetpos,1:end); drawnow; writeVideo(videowriterobj,getframe(thefig)); end end -close(videowriterobj); +close(videowriterobj); \ No newline at end of file diff --git a/matlab/distribution_function.m b/matlab/distribution_function.m index 6c5aa3c..ddb2df7 100644 --- a/matlab/distribution_function.m +++ b/matlab/distribution_function.m @@ -1,464 +1,374 @@ %% Show the particles velocity histogram at the position set using ginput % The histogram is compared between timesteppart and end -timeinit=1; -timesteppart=length(M.tpart)-1; -%timesteppart=1; -timestepNinit=find(M.tpart(timeinit)==M.t2d); -timestepNend=find(M.tpart(timesteppart)==M.t2d); - -gcs=false; % use guiding center reference system for Vperp coordinates - -zleftlim=1; - -%Rindex=15+28; -Rindex=28;%43;%29; -Zindex=193; +timesteppart=length(M.tpart); fig=figure; ax1=gca; -% get the relevant timesteps between 2d and particles variables timestepN=find(M.tpart(end)==M.t2d,1); -% Plot the density at the end of simulation to select the region of interest Ndistrib=M.N(:,:,timestepN); h=contourf(ax1,M.zgrid,M.rgrid,Ndistrib); %set(h, 'EdgeColor', 'none'); hold on [r,z]=find(Ndistrib~=0); xlim(ax1,[M.zgrid(min(z)) M.zgrid(max(z))]) ylim(ax1,[M.rgrid(min(r)) M.rgrid(max(r))]) xlabel(ax1,'Z [m]') ylabel(ax1,'R [m]') c = colorbar(ax1); c.Label.String= 'n [m^{-3}]'; view(ax1,2) +%set(ax1,'colorscale','log') % [x,y]=ginput(1); % Zindex=find(x>M.zgrid,1,'last'); % Rindex=find(y>M.rgrid,1,'last'); % Rindex=155; % Zindex=344; Z=(M.zgrid(Zindex)); R=(M.rgrid(Rindex)); - -% Show this point on the density map plot(Z,R,'rx','Markersize',12); % Rindex=16; Zindex=64; % Rindex=28; Zindex=floor(size(M.zgrid,1)/2)+1; - nbp=min(M.R.nparts,M.nbparts(1)); Rp=M.R(1:nbp,1,false); Zp=M.Z(1:nbp,1,false); Indices=Rp>=M.rgrid(Rindex) & Rp=M.zgrid(Zindex) & Zp=M.rgrid(Rindex) & Rend=M.zgrid(Zindex) & Zend1) -h1=histogram(Vr,'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(timeinit)*1e9)); +h1=histogram(Vr,'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(1)*1e9)); %h1=histfit(ax1,Vr); set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(1)*1e9)); end hold on h1=histogram(Vrend,'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(end)*1e9)); %h1=histfit(ax1,Vrend); -set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(timesteppart)*1e9)); +set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(end)*1e9)); ylabel('counts') -xlabel('v_r [m/s]') +xlabel('\beta_r') + grid on -ylimits=ylim(); -Veb=(-M.Er(Rindex,Zindex,end)*M.Bz(Zindex,Rindex)+M.Ez(Rindex,Zindex,end)*M.Br(Zindex,Rindex))/M.B(Zindex,Rindex)^2; -plot(-Veb*[1, 1],ylimits,'--k','DisplayName','-V_{ExB}','linewidth',1.5) -plot(Veb*[1, 1],ylimits,'--k','DisplayName','V_{ExB}','linewidth',1.5) ax2=subplot(1,3,2); binwidth=abs(max(Vthetend)-min(Vthetend))/sqrt(length(Vthetend)); if(length(Vthet)>1) -h1=histogram(Vthet(:,1),'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(timeinit)*1e9)); +h1=histogram(Vthet(:,1),'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(1)*1e9)); set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(1)*1e9)); end %h1=histfit(ax2,Vthet(:,1)); hold on h1=histogram(Vthetend,'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(end)*1e9)); %h1=histfit(ax2,Vthetend); -set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(timesteppart)*1e9)); - +set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(end)*1e9)); ylabel('counts') -xlabel('v_\theta [m/s]') +xlabel('\beta_\theta') legend(ax2,'location','northoutside','orientation','vertical') grid on -ylimits=ylim(); -Veb=(-M.Er(Rindex,Zindex,end)*M.Bz(Zindex,Rindex)+M.Ez(Rindex,Zindex,end)*M.Br(Zindex,Rindex))/M.B(Zindex,Rindex)^2; -plot(Veb*[1, 1],ylimits,'--k','DisplayName','V_{ExB}','linewidth',1.5) -plot(-Veb*[1, 1],ylimits,'--k','DisplayName','V_{ExB}','linewidth',1.5) ax3=subplot(1,3,3); %h1=histogram(Vz(:,1),'Binwidth',binwidth,'Normalization','probability','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(1)*1e9)); binwidth=abs(max(Vzend)-min(Vzend))/sqrt(length(Vzend)); if(length(Vz)>1) h1=histogram(ax3,Vz(:,1),'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(1)*1e9)); set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(1)*1e9)); end hold on %h1=histogram(Vzend,'Binwidth',binwidth,'Normalization','probability','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(end)*1e9)); h1=histogram(ax3,Vzend,'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(end)*1e9)); set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(end)*1e9)); ylabel('counts') -xlabel('v_z [m/s]') -ax3.Children=ax3.Children([1,3,2,4]); +xlabel('\beta_z') grid on f=gcf; -sgtitle(sprintf('R=%1.2e[m] Z=%1.2e[m] dt=%1.2e[ns]',M.rgrid(Rindex),M.zgrid(Zindex),M.dt*1e9)) +sgtitle(sprintf('R=%1.2e[m] Z=%1.2e[m] dt=%1.2e[ns]',M.rgrid(Rindex+1),M.zgrid(Zindex+1),M.dt*1e9)) f.PaperOrientation='landscape'; f.PaperUnits='centimeters'; papsize=[16 10]; f.PaperSize=papsize; -name=strcat(M.folder,'/',M.name); -print(f,sprintf('%sParts_V_RZ_R%dZ%d',name,Rindex,Zindex),'-dpdf','-fillpage') -savefig(f,sprintf('%sParts_V_RZ_R%dZ%d',name,Rindex,Zindex)) +[~, name, ~] = fileparts(M.file); +print(f,sprintf('%sParts_V_RZ',name),'-dpdf','-fillpage') +savefig(f,sprintf('%sParts_V_RZ',name)) -%% Defines the legends given the selected time steps +%% Shows the particles phase space at position (rindex, zindex) +% and times tinit and timesteppart +timeinit=1; +timestepNinit=find(M.tpart(timeinit)==M.t2d); +timesteppart=length(M.tpart); +timestepNend=find(M.tpart(timesteppart)==M.t2d); + +Rp=M.R(:,timeinit,false); +Zp=M.Z(:,timeinit,false); +Indices=Rp>=M.rgrid(Rindex) & Rp=M.zgrid(Zindex) & Zp=M.rgrid(Rindex) & Rend=M.zgrid(Zindex) & Zend1) -h1=histogram(Vperp,'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(timeinit)*1e9)); -%h1=histfit(ax1,Vr); -set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(1)*1e9)); -end +f=figure; +subplot(1,2,1) +p(1)=scatter(Vpar,Vperp,'.','displayname',legendinit); hold on -h1=histogram(Vperpend,'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(end)*1e9)); -%h1=histfit(ax1,Vrend); -set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(timesteppart)*1e9)); -ylabel('counts') -grid on -ylimits=ylim(); -plot(mean(Vthetend)*[1, 1],ylimits,'--k','DisplayName','','linewidth',1.5) -if gcs - xlabel('v_{perp}^* [m/s]') - plot(mean(Vperpend)*[1, 1],ylimits,'--g','DisplayName','','linewidth',1.5) -else - xlabel('v_{perp} [m/s]') - plot(mean(Vperpend)*[1, 1],ylimits,'--g','DisplayName','','linewidth',1.5) -end -plot(Veb*[1, 1],ylimits,'--b','DisplayName','V_{ExB}','linewidth',1.5) -legend(ax1,'location','northoutside','orientation','vertical') +p(2)=scatter(Vparend,Vperpend,'.','displayname',legendend); +xlabel('v_{par}/c') +ylabel('v_\perp/c') +legend('location','southoutside') +zleftlim=1; -ax2=subplot(1,3,2); -if(length(Vpar)>1) -h1=histogram(Vpar(:,1),'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(timeinit)*1e9)); -set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(1)*1e9)); +vpar=linspace(1,M.vlight,1000); +dN=1e13*M.weight; +dN=0; +rp=9.85e-3; +rm=7e-3; +V=2*pi*(rp^2-rm^2); +N=M.N(:,:,timestepNend); +levels=M.rAthet(Rindex,Zindex)*[1 1]; +rAthetposend=find(levels(1)>=M.rAthet(:,zleftlim),1,'last'); +rleft=sqrt(levels(1)/(M.rAthet(rAthetposend,1)/M.rgrid(rAthetposend)^2)); +rposleft=find(M.rgrid>=rleft,1,'first'); +n2=mean(mean(N(rposleft,[1 end],:),3)); +vpar2=(dN/V/n2)^2; +if n2==0 + vpar2=0; end b=M.rgrid(end); a=M.rgrid(1); vd1=((M.potout-M.potinn)*M.phinorm/M.rgrid(Rindex))/M.Bz(Zindex,Rindex)/log(b/a); vd1=-M.Er(Rindex,Zindex,1)/M.Bz(Zindex,Rindex); %vd1=-M.Er(Rindex,Zindex,timestepNend)/M.Bz(Zindex,Rindex); vinit=sqrt(M.kb*10000/M.me); %vinit=sqrt(M.qe*80/M.me) %vinit=sqrt(120*M.qe/M.me) %vd2=((M.potout-M.potinn)*M.phinorm/M.rgrid(25))/M.Bz(1,25)/log(b/a); [Zmesh,Rmesh]=meshgrid(M.zgrid,M.rAthet(:,floor(M.nz/2)+1)); Rcurv=griddata(Zmesh,M.rAthet,M.B',M.zgrid(zleftlim),M.rAthet(Rindex,Zindex),'natural')/M.B(Zindex,Rindex); deltaphicomp=-0.5*M.me/M.qe*(vpar2-(vd1+vinit)^2*(1-M.Rcurv)) ratioparper=vpar2/((vd1+vinit)^2*(1-M.Rcurv)) Ndistrib=M.N(:,:,timestepNend); model=M.potentialwellmodel(timestepNend); z=model.z; r=model.r; pot=model.pot; rathet=model.rathet; Zeval=[M.zgrid(zleftlim) M.zgrid(Zindex)]; Psieval=M.rAthet(Rindex,Zindex)*[1 1]; phis=griddata(Zmesh,M.rAthet,M.pot(:,:,end),Zeval,Psieval,'natural'); deltaphi=-diff(phis) %deltaphi=-215; R=griddata(Zmesh,M.rAthet,M.B',M.zgrid(zleftlim),M.rAthet(Rindex,Zindex),'natural')/M.B(Zindex,Rindex); % if vper is above line then electron is kept axially vper=sqrt(2*M.qe/M.me*deltaphi/(R-1)+vpar.^2/(R-1))/M.vlight; vpar=vpar/M.vlight; vpar=vpar(real(vper)~=0); vper=vper(real(vper)~=0); xlimits=xlim; ylimits=ylim; if(length(vper)>0) p(3)=plot(vpar,vper,'b-','displayname','Loss parabolla simul'); hold on plot(-vpar,vper,'b-') end vpar=linspace(1,M.vlight,1000); vper=sqrt(-2*M.qe/M.me*deltaphicomp/(R-1)+vpar.^2/(R-1))/M.vlight; vpar=vpar/M.vlight; vpar=vpar(real(vper)~=0); vper=vper(real(vper)~=0); if(length(vper)>0) p(4)=plot(vpar,vper,'k--','displayname','Loss parabolla prediction'); hold on plot(-vpar,vper,'k--') end xlim(xlimits) ylim(ylimits) legend(p) axis equal % subplot(2,2,2) % scatter(Zp,Vpar,'.','displayname','Init') % hold on % scatter(Zend,Vparend,'.','displayname','End') % xlabel('z [m]') % ylabel('\beta_{par}') % % subplot(2,2,3) % scatter(Vperp,Rp,'.','displayname','Init') % hold on % scatter(Vperpend,Rend,'.','displayname','End') % xlabel('\beta_\perp') % ylabel('R [m]') ax1=subplot(1,2,2); h=contourf(ax1,M.zgrid,M.rgrid,Ndistrib); hold on [r,z]=find(Ndistrib~=0); xlim(ax1,[M.zgrid(min(z)) M.zgrid(max(z))]) ylim(ax1,[M.rgrid(min(r)) M.rgrid(max(r))]) xlabel(ax1,'Z [m]') ylabel(ax1,'R [m]') c = colorbar(ax1); c.Label.String= 'n [m^{-3}]'; Zx=(M.zgrid(Zindex)); Rx=(M.rgrid(Rindex)); plot(ax1,Zx,Rx,'rx','Markersize',12); sgtitle(sprintf('r=%1.3g [m] z=%1.3g [m] \\Delta\\phi=%1.3g[kV] R=%1.3g',M.rgrid(Rindex),M.zgrid(Zindex),(M.potout-M.potinn)*M.phinorm,M.Rcurv)) M.savegraph(f,sprintf('%s/%s_phasespaceR%dZ%dpos',M.folder,M.name,Rindex,Zindex),[16,12]) -ax2=subplot(1,3,3); -if(length(Vpar)>1) -h1=histogram(sqrt(Vr.^2+Vthet.^2+Vz.^2),'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(1)*1e9)); -set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(timeinit)*1e9)); -end +%% +f=figure; +p(1)=scatter(Vpar,Vperp,'.','displayname','Initial'); hold on -h1=histogram(sqrt(Vrend.^2+Vthetend.^2+Vzend.^2),'Binwidth',binwidth,'Normalization','count','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(end)*1e9)); -%h1=histfit(ax2,Vthetend); -set(h1,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(timesteppart)*1e9)); -ylabel('counts') -xlabel('|v|') -legend(ax2,'location','northoutside','orientation','vertical') -grid on +p(2)=scatter(Vparend,Vperpend,'.','displayname','Final'); +xlabel('v_{par}/c') +ylabel('v_\perp/c') -% ax3=subplot(1,3,3); -% h1=histogram(Vz(:,1),'Binwidth',binwidth,'Normalization','probability','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(timeinit)*1e9)); -% if(length(Vz)>1) -% h2=histfit(ax3,sqrt(Vr.^2+Vthet.^2+Vz.^2),[],'Rayleigh'); -% set(h2,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(1)*1e9)); -% h2(1).FaceAlpha=0.6; -% h2(1).FaceColor=[0.00,0.45,0.74]; -% h2(2).Color='blue'; -% end -% hold on -% h1=histogram(Vzend,'Binwidth',binwidth,'Normalization','probability','DisplayName',sprintf("t=%2.3d [ns]",M.tpart(end)*1e9)); -% h2=histfit(ax3,sqrt(Vrend.^2+Vthetend.^2+Vzend.^2),[],'Rayleigh'); -% set(h2,'DisplayName',sprintf("t=%2.3d [ns]",M.tpart(timesteppart)*1e9)); -% h2(1).FaceAlpha=0.6; -% h2(1).FaceColor=[0.85,0.33,0.10]; -% h2(2).Color='red'; -% ylabel('counts') -% xlabel('|v| [m/s]') -% ax3.Children=ax3.Children([1,3,2,4]); -% grid on -f=gcf; -sgtitle(sprintf('R=%1.2e[m] Z=%1.2e[m] dt=%1.2e[ns]',M.rgrid(Rindex),M.zgrid(Zindex),M.dt*1e9)) -f.PaperOrientation='landscape'; -f.PaperUnits='centimeters'; -papsize=[16 10]; -f.PaperSize=papsize; -name=strcat(M.folder,'/',M.name); -if gcs - print(f,sprintf('%sParts_V_perparstarR%dZ%d',name,Rindex,Zindex),'-dpdf','-fillpage') - savefig(f,sprintf('%sParts_V_perparstarR%dZ%d',name,Rindex,Zindex)) -else - print(f,sprintf('%sParts_V_perparR%dZ%d',name,Rindex,Zindex),'-dpdf','-fillpage') - savefig(f,sprintf('%sParts_V_perparR%dZ%d',name,Rindex,Zindex)) +zleftlim=1; + +vpar=linspace(1,M.vlight,1000); +dN=1e13*M.weight; +dN=0; +rp=9.85e-3; +rm=7e-3; +V=2*pi*(rp^2-rm^2); +N=M.N(:,:,timestepNend); +levels=M.rAthet(Rindex,Zindex)*[1 1]; +rAthetposend=find(levels(1)>=M.rAthet(:,zleftlim),1,'last'); +rleft=sqrt(levels(1)/(M.rAthet(rAthetposend,1)/M.rgrid(rAthetposend)^2)); +rposleft=find(M.rgrid>=rleft,1,'first'); +n2=mean(mean(N(rposleft,[1 end],:),3)); +vpar2=(dN/V/n2)^2; +if n2==0 + vpar2=0; end b=M.rgrid(end); a=M.rgrid(1); vd1=((M.potout-M.potinn)*M.phinorm/M.rgrid(Rindex))/M.Bz(Zindex,Rindex)/log(b/a); vd1=-M.Er(Rindex,Zindex,1)/M.Bz(Zindex,Rindex); %vd1=-M.Er(Rindex,Zindex,timestepNend)/M.Bz(Zindex,Rindex); vinit=sqrt(M.kb*10000/M.me); %vinit=sqrt(M.qe*80/M.me) %vinit=sqrt(120*M.qe/M.me) %vd2=((M.potout-M.potinn)*M.phinorm/M.rgrid(25))/M.Bz(1,25)/log(b/a); [Zmesh,Rmesh]=meshgrid(M.zgrid,M.rAthet(:,floor(M.nz/2)+1)); % Find the R magnetic ratio between local position and left Rcurv=griddata(Zmesh,M.rAthet,M.B',M.zgrid(zleftlim),M.rAthet(Rindex,Zindex),'natural')/M.B(Zindex,Rindex); deltaphicomp=-0.5*M.me/M.qe*(vpar2-(vd1+vinit)^2*(1-M.Rcurv)) ratioparper=vpar2/((vd1+vinit)^2*(1-M.Rcurv)) Ndistrib=M.N(:,:,timestepNend); model=M.potentialwellmodel(timestepNend); z=model.z; r=model.r; pot=model.pot; rathet=model.rathet; Zeval=[M.zgrid(zleftlim) M.zgrid(Zindex)]; Psieval=M.rAthet(Rindex,Zindex)*[1 1]; phis=griddata(Zmesh,M.rAthet,M.pot(:,:,end),Zeval,Psieval,'natural'); % calculate the potential difference between left and local deltaphi=-diff(phis) %deltaphi=-215; R=griddata(Zmesh,M.rAthet,M.B',M.zgrid(zleftlim),M.rAthet(Rindex,Zindex),'natural')/M.B(Zindex,Rindex); vper=sqrt(2*M.qe/M.me*deltaphi/(R-1)+vpar.^2/(R-1))/M.vlight; vpar=vpar/M.vlight; vpar=vpar(real(vper)~=0); vper=vper(real(vper)~=0); xlimits=xlim; ylimits=ylim; if(length(vper)>0) p(3)=plot(vpar,vper,'b-','displayname','Simulation'); hold on plot(-vpar,vper,'b-') end vpar=linspace(1,M.vlight,1000); vper=sqrt(-2*M.qe/M.me*deltaphicomp/(R-1)+vpar.^2/(R-1))/M.vlight; vpar=vpar/M.vlight; vpar=vpar(real(vper)~=0); vper=vper(real(vper)~=0); if(length(vper)>0) p(4)=plot(vpar,vper,'k--','displayname','Prediction'); hold on plot(-vpar,vper,'k--') end xlim(xlimits) ylim(ylimits) legend(p) axis equal legend('location','northeast') title(sprintf('r=%1.3g [m] z=%1.3g [m] \\Delta\\phi=%1.3g[kV] R=%1.3g',M.rgrid(Rindex),M.zgrid(Zindex),(M.potout-M.potinn)*M.phinorm,M.Rcurv)) -%% Show the phase space at begining and end of the simulation at position (Rindex,Zindex) as a probability density -f=figure(); -ax1=subplot(1,2,1); -ax2=subplot(1,2,2); -%[p,maxnb,c]=M.displayPhaseSpace(1:2,Rindex,Zindex,'',sprintf('t=%1.3g [s]',M.tpart(1)),ax1); -% ax1=subplot(1,2,1); -% hold(ax1,'off') -c=cell(2,1); -c{1}=linspace(-3e6,3e6,21); -c{2}=linspace(-0e6,1.3e7,51); -[p,maxnb,c]=M.displayPhaseSpace('parper',1:2,Rindex,Zindex,'',sprintf('t=%1.3g [s]',M.tpart(1)),ax1,-1,c); -M.displayPhaseSpace('parper',length(M.tpart)+(-1:0),Rindex,Zindex,'',sprintf('t=%1.3g [s]',M.tpart(end)),ax2,maxnb,c); -xlimits=xlim(ax1); -xlimits=[min([xlimits,xlim(ax2)]) max([xlimits,xlim(ax2)])]; -ylimits=ylim(ax1); -ylimits=[min([ylimits,ylim(ax2)]) max([ylimits,ylim(ax2)])]; -xlim([ax1,ax2],xlimits) -ylim([ax1,ax2],ylimits) -climitsmax=max([caxis(ax1),caxis(ax2)]); -caxis(ax1,[0 climitsmax]); -caxis(ax2,[0 climitsmax]); -xtickformat(ax1,'%.3g') -ytickformat(ax1,'%.3g') -ax1.YAxis.Exponent = 0; -ax1.XAxis.Exponent = 0; - -xtickformat(ax2,'%.3g') -ytickformat(ax2,'%.3g') -ax2.YAxis.Exponent = 0; -ax2.XAxis.Exponent = 0; - -sgtitle(sprintf('r=%1.2f [mm] z=%1.2f [mm] \\Delta\\phi=%1.1f[kV] R=%1.1f',M.rgrid(Rindex)*1e3,M.zgrid(Zindex)*1e3,(M.potout-M.potinn)*M.phinorm/1e3,M.Rcurv)) -M.savegraph(f,sprintf('%s/%s_phasespaceR%dZ%dbegend',M.folder,M.name,Rindex,Zindex),[15,10]); - - -%% Show the phase space at begining and end of the simulation at position (Rindex,Zindex) as a probability density -f=figure(); -ax1=subplot(1,2,1); -ax2=subplot(1,2,2); -%[p,maxnb,c]=M.displayPhaseSpace(1:2,Rindex,Zindex,'',sprintf('t=%1.3g [s]',M.tpart(1)),ax1); -% ax1=subplot(1,2,1); -% hold(ax1,'off') -c=cell(2,1); -c{1}=linspace(-1e7,1e7,21); -c{2}=linspace(-1.5e7,1.5e7,51); -[p,maxnb,c]=M.displayPhaseSpace('rthet',1:2,Rindex,Zindex,'',sprintf('t=%1.3g [s]',M.tpart(1)),ax1,-1,c); -M.displayPhaseSpace('rthet',length(M.tpart)+(-1:0),Rindex,Zindex,'',sprintf('t=%1.3g [s]',M.tpart(end)),ax2,maxnb,c); -xlimits=xlim(ax1); -xlimits=[min([xlimits,xlim(ax2)]) max([xlimits,xlim(ax2)])]; -ylimits=ylim(ax1); -ylimits=[min([ylimits,ylim(ax2)]) max([ylimits,ylim(ax2)])]; -xlim([ax1,ax2],xlimits) -ylim([ax1,ax2],ylimits) -climitsmax=max([caxis(ax1),caxis(ax2)]); -caxis(ax1,[0 climitsmax]); -caxis(ax2,[0 climitsmax]); -xtickformat(ax1,'%.3g') -ytickformat(ax1,'%.3g') -ax1.YAxis.Exponent = 0; -ax1.XAxis.Exponent = 0; - -xtickformat(ax2,'%.3g') -ytickformat(ax2,'%.3g') -ax2.YAxis.Exponent = 0; -ax2.XAxis.Exponent = 0; - -sgtitle(sprintf('r=%1.2f [mm] z=%1.2f [mm] \\Delta\\phi=%1.1f[kV] R=%1.1f',M.rgrid(Rindex)*1e3,M.zgrid(Zindex)*1e3,(M.potout-M.potinn)*M.phinorm/1e3,M.Rcurv)) -M.savegraph(f,sprintf('%s/%s_phasespaceR%dZ%dbegendrthet',M.folder,M.name,Rindex,Zindex),[15,10]); +M.savegraph(f,sprintf('%s/%s_phasespaceR%dZ%d',M.folder,M.name,Rindex,Zindex),[12,8]) \ No newline at end of file diff --git a/matlab/export_fig/.gitignore b/matlab/export_fig/.gitignore new file mode 100644 index 0000000..6d02904 --- /dev/null +++ b/matlab/export_fig/.gitignore @@ -0,0 +1,6 @@ +/.ignore +.DS_store +*.txt +*.asv +*~ +*.mex* diff --git a/matlab/export_fig/.ignore/ghostscript.txt b/matlab/export_fig/.ignore/ghostscript.txt new file mode 100644 index 0000000..cb50752 --- /dev/null +++ b/matlab/export_fig/.ignore/ghostscript.txt @@ -0,0 +1 @@ +gs \ No newline at end of file diff --git a/matlab/export_fig/.ignore/gs_font_path.txt b/matlab/export_fig/.ignore/gs_font_path.txt new file mode 100644 index 0000000..7166667 --- /dev/null +++ b/matlab/export_fig/.ignore/gs_font_path.txt @@ -0,0 +1 @@ +/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype \ No newline at end of file diff --git a/matlab/export_fig/.ignore/pdftops.txt b/matlab/export_fig/.ignore/pdftops.txt new file mode 100644 index 0000000..6f9b68e --- /dev/null +++ b/matlab/export_fig/.ignore/pdftops.txt @@ -0,0 +1 @@ +pdftops \ No newline at end of file diff --git a/matlab/export_fig/2022-05-24.zip b/matlab/export_fig/2022-05-24.zip new file mode 100644 index 0000000..d8766ee Binary files /dev/null and b/matlab/export_fig/2022-05-24.zip differ diff --git a/matlab/export_fig/Export_fig.prj b/matlab/export_fig/Export_fig.prj new file mode 100644 index 0000000..0afc345 --- /dev/null +++ b/matlab/export_fig/Export_fig.prj @@ -0,0 +1,2 @@ + + diff --git a/matlab/export_fig/ImageSelection.class b/matlab/export_fig/ImageSelection.class new file mode 100644 index 0000000..cfac41d Binary files /dev/null and b/matlab/export_fig/ImageSelection.class differ diff --git a/matlab/export_fig/ImageSelection.java b/matlab/export_fig/ImageSelection.java new file mode 100644 index 0000000..7ec32fd --- /dev/null +++ b/matlab/export_fig/ImageSelection.java @@ -0,0 +1,38 @@ +/* + * Based on code snippet from + * http://java.sun.com/developer/technicalArticles/releases/data/ + * + * Copyright © 2008, 2010 Oracle and/or its affiliates. All rights reserved. Use is subject to license terms. + */ + +import java.awt.image.BufferedImage; +import java.awt.datatransfer.*; + +public class ImageSelection implements Transferable { + + private static final DataFlavor flavors[] = + {DataFlavor.imageFlavor}; + + private BufferedImage image; + + public ImageSelection(BufferedImage image) { + this.image = image; + } + + // Transferable + public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { + if (flavor.equals(flavors[0]) == false) { + throw new UnsupportedFlavorException(flavor); + } + return image; + } + + public DataFlavor[] getTransferDataFlavors() { + return flavors; + } + + public boolean isDataFlavorSupported(DataFlavor + flavor) { + return flavor.equals(flavors[0]); + } +} \ No newline at end of file diff --git a/matlab/export_fig/LICENSE b/matlab/export_fig/LICENSE new file mode 100644 index 0000000..1a05830 --- /dev/null +++ b/matlab/export_fig/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014, Oliver J. Woodford, Yair M. Altman +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the {organization} nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/matlab/export_fig/README.md b/matlab/export_fig/README.md new file mode 100644 index 0000000..c54307c --- /dev/null +++ b/matlab/export_fig/README.md @@ -0,0 +1,272 @@ +export_fig +========== + +A toolbox for exporting figures from MATLAB to standard image and document formats nicely. + +### Overview +Exporting a figure from MATLAB the way you want it (hopefully the way it looks on screen), can be a real headache for the unitiated, thanks to all the settings that are required, and also due to some eccentricities (a.k.a. features and bugs) of functions such as `print`. The first goal of export_fig is to make transferring a plot from screen to document, just the way you expect (again, assuming that's as it appears on screen), a doddle. + +The second goal is to make the output media suitable for publication, allowing you to publish your results in the full glory that you originally intended. This includes embedding fonts, setting image compression levels (including lossless), anti-aliasing, cropping, setting the colourspace, alpha-blending and getting the right resolution. + +Perhaps the best way to demonstrate what export_fig can do is with some examples. + +*Note: `export_fig` currently supports only figures created with the `figure` function, or GUIDE. Figures created using `uifigure` or AppDesigner are only partially supported. See issues [#287](https://github.com/altmany/export_fig/issues/287), [#261](https://github.com/altmany/export_fig/issues/261) for details.* + +### Examples +**Visual accuracy** - MATLAB's exporting functions, namely `saveas` and `print`, change many visual properties of a figure, such as size, axes limits and ticks, and background colour, in unexpected and unintended ways. Export_fig aims to faithfully reproduce the figure as it appears on screen. For example: +```Matlab +plot(cos(linspace(0, 7, 1000))); +set(gcf, 'Position', [100 100 150 150]); +saveas(gcf, 'test.png'); +export_fig test2.png +``` +generates the following: + +| Figure: | test.png: | test2.png: | +|:-------:|:---------:|:----------:| +|![](https://farm6.staticflickr.com/5616/15589249291_16e485c29a_o_d.png)|![](https://farm4.staticflickr.com/3944/15406302850_4d2e1c7afa_o_d.png)|![](https://farm6.staticflickr.com/5607/15568225476_8ce9bd5f6b_o_d.png)| + +Note that the size and background colour of test2.png (the output of export_fig) are the same as those of the on screen figure, in contrast to test.png. Of course, if you want the figure background to be white (or any other colour) in the exported file then you can set this prior to exporting using: +```Matlab +set(gcf, 'Color', 'w'); +``` + +Notice also that export_fig crops and anti-aliases (smooths, for bitmaps only) the output by default. However, these options can be disabled; see the Tips section below for details. + +**Resolution** - by default, export_fig exports bitmaps at screen resolution. However, you may wish to save them at a different resolution. You can do this using either of two options: `-m`, where is a positive real number, magnifies the figure by the factor for export, e.g. `-m2` produces an image double the size (in pixels) of the on screen figure; `-r`, again where is a positive real number, specifies the output bitmap to have pixels per inch, the dimensions of the figure (in inches) being those of the on screen figure. For example, using: +```Matlab +export_fig test.png -m2.5 +``` +on the figure from the example above generates: + +![](https://farm4.staticflickr.com/3937/15591910915_dc7040c477_o_d.png) + +Sometimes you might have a figure with an image in. For example: +```Matlab +imshow(imread('cameraman.tif')) +hold on +plot(0:255, sin(linspace(0, 10, 256))*127+128); +set(gcf, 'Position', [100 100 150 150]); +``` +generates this figure: + +![](https://farm4.staticflickr.com/3942/15589249581_ff87a56a3f_o_d.png) + +Here the image is displayed in the figure at resolution lower than its native resolution. However, you might want to export the figure at a resolution such that the image is output at its native (i.e. original) size (in pixels). Ordinarily this would require some non-trivial computation to work out what that resolution should be, but export_fig has an option to do this for you. Using: +```Matlab +export_fig test.png -native +``` +produces: + +![](https://farm6.staticflickr.com/5604/15589249591_da2b2652e4_o_d.png) + +with the image being the size (in pixels) of the original image. Note that if you want an image to be a particular size, in pixels, in the output (other than its original size) then you can resize it to this size and use the `-native` option to achieve this. + +All resolution options (`-m`, `-q` and `-native`) correctly set the resolution information in PNG and TIFF files, as if the image were the dimensions of the on screen figure. + +**Shrinking dots & dashes** - when exporting figures with dashed or dotted lines using either the ZBuffer or OpenGL (default for bitmaps) renderers, the dots and dashes can appear much shorter, even non-existent, in the output file, especially if the lines are thick and/or the resolution is high. For example: +```Matlab +plot(sin(linspace(0, 10, 1000)), 'b:', 'LineWidth', 4); +hold on +plot(cos(linspace(0, 7, 1000)), 'r--', 'LineWidth', 3); +grid on +export_fig test.png +``` +generates: + +![](https://farm4.staticflickr.com/3956/15592747732_f943d4aa0a_o_d.png) + +This problem can be overcome by using the painters renderer. For example: +```Matlab +export_fig test.png -painters +``` +used on the same figure generates: + +![](https://farm4.staticflickr.com/3945/14971168504_77692f11f5_o_d.png) + +Note that not only are the plot lines correct, but the grid lines are too. + +**Transparency** - sometimes you might want a figure and axes' backgrounds to be transparent, so that you can see through them to a document (for example a presentation slide, with coloured or textured background) that the exported figure is placed in. To achieve this, first (optionally) set the axes' colour to 'none' prior to exporting, using: +```Matlab +set(gca, 'Color', 'none'); % Sets axes background +``` + +then use export_fig's `-transparent` option when exporting: +```Matlab +export_fig test.png -transparent +``` + +This will make the background transparent in PDF, EPS and PNG outputs. You can additionally save fully alpha-blended semi-transparent patch objects to the PNG format. For example: + +```Matlab +logo; +alpha(0.5); +``` + +generates a figure like this: + +![](https://farm4.staticflickr.com/3933/15405290339_b08de33528_o_d.png) + +If you then export this to PNG using the `-transparent` option you can then put the resulting image into, for example, a presentation slide with fancy, textured background, like so: + +![](https://farm6.staticflickr.com/5599/15406302920_59beaefff1_o_d.png) + +and the image blends seamlessly with the background. + +**Image quality** - when publishing images of your results, you want them to look as good as possible. By default, when outputting to lossy file formats (PDF, EPS and JPEG), export_fig uses a high quality setting, i.e. low compression, for images, so little information is lost. This is in contrast to MATLAB's print and saveas functions, whose default quality settings are poor. For example: +```Matlab +A = im2double(imread('peppers.png')); +B = randn(ceil(size(A, 1)/6), ceil(size(A, 2)/6), 3) * 0.1; +B = cat(3, kron(B(:,:,1), ones(6)), kron(B(:,:,2), ones(6)), kron(B(:,:,3), ones(6))); +B = A + B(1:size(A, 1),1:size(A, 2),:); +imshow(B); +print -dpdf test.pdf +``` +generates a PDF file, a sub-window of which looks (when zoomed in) like this: + +![](https://farm6.staticflickr.com/5613/15405290309_881b2774d6_o_d.png) + +while the command + +```Matlab +export_fig test.pdf +``` +on the same figure produces this: + +![](https://farm4.staticflickr.com/3947/14971168174_687473133f_o_d.png) + +While much better, the image still contains some compression artifacts (see the low level noise around the edge of the pepper). You may prefer to export with no artifacts at all, i.e. lossless compression. Alternatively, you might need a smaller file, and be willing to accept more compression. Either way, export_fig has an option that can suit your needs: `-q`, where is a number from 0-100, will set the level of lossy image compression (again in PDF, EPS and JPEG outputs only; other formats are lossless), from high compression (0) to low compression/high quality (100). If you want lossless compression in any of those formats then specify a greater than 100. For example: +```Matlab +export_fig test.pdf -q101 +``` +again on the same figure, produces this: + +![](https://farm6.staticflickr.com/5608/15405803908_934512c1fe_o_d.png) + +Notice that all the noise has gone. + +### Tips +**Anti-aliasing** - the anti-aliasing which export_fig applies to bitmap outputs by default makes the images look nice, but it can also blur images and increase exporting time and memory requirements, so you might not always want it. You can set the level of anti-aliasing by using the `-a` option, where is 1 (no anti-aliasing), 2, 3 (default) or 4 (maximum anti-aliasing). + +**Cropping** - by default, export_fig crops its output to minimize the amount of empty space around the figure. If you'd prefer the figure to be uncropped, and instead have the same appearance (in terms of border width) as the on screen figure, then use the `-nocrop` option. + +**Colourspace** - by default, export_fig generates files in the RGB [colourspace](https://en.wikipedia.org/wiki/Color_space). However, you can also export in greyscale or the CMYK colourspace, using the `-grey` (or `-gray`) and `-cmyk` options respectively. The CMYK option is useful for publishers who require documents in this colourspace, but the option is only supported for PDF, EPS and TIFF files. + +**Specifying a target directory** - you can get export_fig to save output files to any directory (for which you have write permission), simply by specifying the full or relative path in the filename. For example: +```Matlab +export_fig ../subdir/fig.png; +export_fig('C:/Users/Me/Documents/figures/myfig', '-pdf', '-png'); +``` + +**Variable file names** - often you might want to save a series of figures in a for loop, each with a different name. For this you can use the functional form of input arguments, i.e. `export_fig(arg1, arg2)`, and construct the filename string in a variable. Here's an example of this: +```Matlab +for a = 1:5 + plot(rand(5, 2)); + export_fig(sprintf('plot%d.png', a)); +end +``` +When using the functional form like this, be sure to put string variables in quotes: +```Matlab +export_fig(sprintf('plot%d', a), '-a1', '-pdf', '-png'); +``` + +**Specifying the figure/axes** - if you have multiple figures open you can specify which figure to export using its handle: +```Matlab +export_fig(figure_handle, filename); +``` +Equally, if your figure contains several subplots then you can export just one of them by giving export_fig the handle to the relevant axes: +```Matlab +export_fig(axes_handle, filename); +``` + +**Multiple formats** - save time by exporting to multiple formats simultaneously. E.g.: +```Matlab +export_fig filename -pdf -eps -png -jpg -tiff +``` + +**Other file formats** - if you'd like to save your figure to a bitmap format that is not supported by export_fig, e.g. animated GIF, PPM file or a frame in a movie, then you can use export_fig to output the image, and optionally an alpha-matte, to the workspace. E.g.: +```Matlab +frame = export_fig; +``` +or +```Matlab +[frame, alpha] = export_fig; +``` +These variables can then be saved to other image formats using other functions, such as imwrite. + +**Appending to a file** - you can use the `-append` option to append the figure to the end of an image/document, if it already exists. This is supported for PDF and TIFF files only. Note that if you wish to append a lot of figures consecutively to a PDF, it can be more efficient to save all the figures to PDF separately then append them all in one go at the end (e.g. using [append_pdfs](http://www.mathworks.com/matlabcentral/fileexchange/31215-appendpdfs)). + +**Output to clipboard** - you can use the `-clipboard` option to copy the specified figure or axes to the system clipboard, for easy paste into other documents (e.g., Word or PowerPoint). Note that the image is copied in bitmap (not vector) format. + +**Font size** - if you want to place an exported figure in a document with the font a particular size then you need to set the font to that size in the figure, and not resize the output of export_fig in the document. To avoid resizing, simply make sure that the on screen figure is the size you want the output to be in the document before exporting. + +**Renderers** - MATLAB has three renderers for displaying and exporting figures: painters, OpenGL and ZBuffer. The different renderers have different [features](http://www.mathworks.com/access/helpdesk/help/techdoc/creating_plots/f3-84337.html#f3-102410), so if you aren't happy with the result from one renderer try another. By default, vector formats (i.e. PDF and EPS outputs) use the painters renderer, while other formats use the OpenGL renderer. Non-default renderers can be selected by using one of these three export_fig input options: `-painters`, `-opengl`, `-zbuffer`: +```Matlab +export_fig test.png -painters +``` + +**Artifacts** - sometimes the output that you get from export_fig is not what you expected. If an output file contains artifacts that aren't in the on screen figure then make sure that the renderer used for rendering the figure on screen is the same as that used for exporting. To set the renderer used to display the figure, use: +```Matlab +set(figure_handle, 'Renderer', 'opengl'); +``` +After matching the two renderers, if the artifact appears in the on screen figure then you'll need to fix that before exporting. Alternatively you can try changing the renderer used by export_fig. Finally check that it isn't one of the known issues mentioned in the section below. + +**Smoothed/interpolated images in output PDF** - if you produce a PDF using export_fig and images in the PDF look overly smoothed or interpolated, this is because the software you are using to view the PDF is smoothing or interpolating the image data. The image is not smoothed in the PDF file itself. If the software has an option to disable this feature, you should select it. Alternatively, use another PDF viewer that doesn't exhibit this problem. + +**Locating Ghostscript/pdftops** - You may find a dialogue box appears when using export_fig, asking you to locate either [Ghostscript](http://www.ghostscript.com) or [pdftops (part of the Xpdf package)](http://www.xpdfreader.com). These are separate applications which export_fig requires to perform certain functions. If such a dialogue appears it is because export_fig can't find the application automatically. This is because you either haven't installed it, or it isn't in the normal place. Make sure you install the applications correctly first. They can be downloaded from the following places: + 1. Ghostscript: [www.ghostscript.com](http://www.ghostscript.com) + 2. pdftops (install the Xpdf package): [www.xpdfreader.com](http://www.xpdfreader.com) + +If you choose to install them in a non-default location then point export_fig +to this location using the dialogue box. + +**Undefined function errors** - If you download and run export_fig and get an error similar to this: +``` +??? Undefined function or method 'print2array' for input arguments of type 'double'. +``` +then you are missing one or more of the files that come in the export_fig package. Make sure that you click the "Get from GitHub" button at the top-right of the download [page](http://www.mathworks.co.uk/matlabcentral/fileexchange/23629-exportfig), then extract all the files in the zip file to the same directory. You should then have all the necessary files. + +### Known issues +There are lots of problems with MATLAB's exporting functions, especially `print`. Export_fig is simply a glorified wrapper for MATLAB's `print` function, and doesn't solve all of its bugs (yet?). Some of the problems I know about are: + +**Fonts** - when using the painters renderer, MATLAB can only export a small number of fonts, details of which can be found [here](http://www.mathworks.com/help/releases/R2014a/matlab/creating_plots/choosing-a-printer-driver.html#f3-96545). Export_fig attempts to correct font names in the resulting EPS file (up to a maximum of 11 different fonts in one figure), but this is not always guaranteed to work. In particular, the text positions will be affected. It also does not work for text blocks where the 'Interpreter' property is set to 'latex'. + +Also, when using the painters renderer, ghostscript will sometimes throw an error such as `Error: /undefined in /findfont`. This suggests that ghostscript could not find a definition file for one of your fonts. One possible fix for this is to make sure the file `EXPORT_FIG_PATH/.ignore/gs_font_path.txt` exists and contains a list of paths to the folder(s) containing the necessary font definitions (make sure that they are TrueType definitions!), separated by a semicolon. + +**RGB color data not yet supported in Painter's mode** - you will see this as a warning if you try to export a figure which contains patch objects whose face or vertex colors are specified as an RGB colour, rather than an index into the colormap, using the painters renderer (the default renderer for vector output). This problem can arise if you use `pcolor`, for example. This is a problem with MATLAB's painters renderer, which also affects `print`; there is currently no fix available in export_fig (other than to export to bitmap). The suggested workaround is to avoid colouring patches using RGB. First, try to use colours in the figure's colourmap (instructions [here](http://www.mathworks.co.uk/support/solutions/en/data/1-6OTPQE/)) - change the colourmap, if necessary. If you are using `pcolor`, try using [uimagesc](http://www.mathworks.com/matlabcentral/fileexchange/11368) (on the file exchange) instead. + +**Dashed contour lines appear solid** - when using the painters renderer, MATLAB cannot generate dashed lines using the `contour` function (either on screen or in exported PDF and EPS files). Details can be found [here](http://www.mathworks.com/support/solutions/en/data/1-14PPHB/?solution=1-14PPHB). + +**Text size** - when using the OpenGL or ZBuffer renderers, large text can be resized relative to the figure when exporting at non-screen-resolution (including using anti-alising at screen resolution). This is a feature of MATLAB's `print `function. In this case, try using the `-painters` option. + +**Lighting and transparency** - when using the painters renderer, transparency and lighting effects are not supported. Sorry, but this is an inherent feature of MATLAB's painters renderer. To find out more about the capabilities of each rendering method, see [here](http://www.mathworks.com/access/helpdesk/help/techdoc/creating_plots/f3-84337.html#f3-102410). You can still export transparent objects to vector format (SVG) using the excellent [plot2svg](http://www.mathworks.com/matlabcentral/fileexchange/7401) package, then convert this to PDF, for example using [Inkscape](http://inkscape.org/). However, it can't handle lighting. + +**Lines in patch objects** - when exporting patch objects to PDF using the painters renderer (default), sometimes the output can appear to have lines across the middle of rectangular patches; these lines are the colour of the background, as if there is a crack in the patch, allowing you to see through. This appears to be due to bugs in MATLAB's internal vector rendering code. These lines can often be removed from the PDF using software such as [InkScape](https://inkscape.org). Sometimes disabling anti-aliasing in the PDF-reader software can get rid of the lines ([discussion](https://github.com/altmany/export_fig/issues/44)). + +**Out of memory** - if you run into memory issues when using export_fig, some ways to get round this are: + 1. Reduce the level of anti-aliasing. + 2. Reduce the size of the figure. + 3. Reduce the export resolution (dpi). + 4. Change the renderer to painters or ZBuffer. + +**Errors** - the other common type of errors people get with export_fig are OpenGL errors. This isn't a fault of export_fig, but either a bug in MATLAB's `print`, or your graphics driver getting itself into a state. Always make sure your graphics driver is up-to-date. If it still doesn't work, try using the ZBuffer renderer. + +### Raising issues +If you think you have found a genuine error or issue with export_fig **that is not listed above**, first ensure that the figure looks correct on screen when rendered using the renderer that export_fig is set to use (e.g. if exporting to PDF or EPS, does the figure look correct on screen using the painters renderer, or if exporting to bitmap, does the figure look correct on screen using the OpenGL renderer?). If it looks wrong then the problem is there, and I cannot help (other than to suggest you try exporting using a different renderer). + +Secondly, if exporting to bitmap, do try all the renderers (i.e. try the options `-opengl`, `-zbuffer` and `-painters` separately), to see if one of them does produce an acceptable output, and if so, use that. + +If this still does not help, then ensure that you are using the latest version of export_fig, which is available [here](https://github.com/altmany/export_fig/archive/master.zip). + +If the figure looks correct on screen, but an error exists in the exported output (which cannot be solved using a different renderer) then please feel free to raise an [issue](https://github.com/altmany/export_fig/issues). Please be sure to include the .fig file, the export_fig command you use, the output you get, and a description of what you expected. I can't promise anything, but if it's easy to fix I may indeed do it. Often I will find that the error is due to a bug in MATLAB's `print` function, in which case I will suggest you submit it as a bug to TheMathWorks, and inform me of any fix they suggest. Also, if there's a feature you'd like that isn't supported please tell me what it is and I'll consider implementing it. + +### And finally... + +![](https://farm4.staticflickr.com/3956/15591911455_b9008bd77e_o_d.jpg) + +If you've ever wondered what's going on in the logo on the export_fig download page (reproduced here), then this explanantion is for you. The logo is designed to demonstrate as many of export_fig's features as possible: + +Given a figure containing a translucent mesh (top right), export_fig can export to pdf (bottom centre), which allows the figure to be zoomed-in without losing quality (because it's a vector graphic), but isn't able to reproduce the translucency. Also, depending on the PDF viewer program, small gaps appear between the patches, which are seen here as thin white lines. + +By contrast, when exporting to png (top left), translucency is preserved (see how the graphic below shows through), and the figure is anti-aliased. However, zooming-in does not reveal more detail since png is a bitmap format. Also, lines appear less sharp than in the pdf output. + diff --git a/matlab/export_fig/SYNTAX b/matlab/export_fig/SYNTAX new file mode 100644 index 0000000..1d9a534 --- /dev/null +++ b/matlab/export_fig/SYNTAX @@ -0,0 +1,217 @@ +Syntax: + [imageData, alpha] = export_fig(filename, [handle], options...) + +Examples: + imageData = export_fig + [imageData, alpha] = export_fig + export_fig filename + export_fig filename -format1 -format2 + export_fig ... -nocrop + export_fig ... -c[,,,] + export_fig ... -transparent + export_fig ... -native + export_fig ... -m + export_fig ... -r + export_fig ... -a + export_fig ... -q + export_fig ... -p + export_fig ... -d + export_fig ... -depsc + export_fig ... - + export_fig ... - + export_fig ... -append + export_fig ... -bookmark + export_fig ... -clipboard<:format> + export_fig ... -update + export_fig ... -version + export_fig ... -nofontswap + export_fig ... -font_space + export_fig ... -linecaps + export_fig ... -noinvert + export_fig ... -preserve_size + export_fig ... -options + export_fig ... -silent + export_fig ... -regexprep + export_fig ... -toolbar + export_fig ... -menubar + export_fig(..., handle) + export_fig(..., figName) + +Description: + This function saves a figure or single axes to one or more vector and/or + bitmap file formats, and/or outputs a rasterized version to the workspace, + with the following properties: + - Figure/axes reproduced as it appears on screen + - Cropped/padded borders (optional) + - Embedded fonts (vector formats) + - Improved line and grid line styles + - Anti-aliased graphics (bitmap formats) + - Render images at native resolution (optional for bitmap formats) + - Transparent background supported (pdf, eps, png, tif, gif) + - Semi-transparent patch objects supported (png, tif) + - RGB, CMYK or grayscale output (CMYK only with pdf, eps, tif) + - Variable image compression, including lossless (pdf, eps, jpg) + - Optional rounded line-caps (pdf, eps) + - Optionally append to file (pdf, tif, gif) + - Vector formats: pdf, eps, emf, svg + - Bitmap formats: png, tif, jpg, bmp, gif, clipboard, export to workspace + + This function is especially suited to exporting figures for use in + publications and presentations, because of the high quality and + portability of media produced. + + Note that the background color and figure dimensions are reproduced + (the latter approximately, and ignoring cropping & magnification) in the + output file. For transparent background (and semi-transparent patch + objects), use the -transparent option or set the figure 'Color' property + to 'none'. To make axes transparent set the axes 'Color' property to + 'none'. PDF, EPS, TIF & PNG are the only formats that support a transparent + background; only TIF & PNG formats support transparency of patch objects. + + The choice of renderer (opengl/zbuffer/painters) has a large impact on the + output quality. The default value (opengl for bitmaps, painters for vector + formats) generally gives good results, but if you aren't satisfied + then try another renderer. Notes: + 1) For vector formats (EPS,PDF), only painters generates vector graphics + 2) For bitmap formats, only opengl correctly renders transparent patches + 3) For bitmap formats, only painters correctly scales line dash and dot + lengths when magnifying or anti-aliasing + 4) Fonts may be substitued with Courier when using painters + + When exporting to vector format (PDF & EPS) and bitmap format using the + painters renderer, this function requires that ghostscript is installed + on your system. You can download this from: http://www.ghostscript.com + When exporting to EPS it additionally requires pdftops, from the Xpdf + suite of functions. You can download this from: http://xpdfreader.com + + SVG output uses Matlab's built-in SVG export if available, or otherwise the + fig2svg (https://github.com/kupiqu/fig2svg) or plot2svg + (https://github.com/jschwizer99/plot2svg) utilities, if available. + Note: cropping/padding are not supported in export_fig's SVG and EMF output. + +Inputs: + filename - string containing the name (optionally including full or + relative path) of the file the figure is to be saved as. If + a path is not specified, the figure is saved in the current + directory. If no name and no output arguments are specified, + the default name, 'export_fig_out', is used. If neither a + file extension nor a format are specified, a ".png" is added + and the figure saved in that format. + - - string(s) containing the output file extension(s). Options: + '-pdf', '-eps', 'emf', '-svg', '-png', '-tif', '-jpg' and '-bmp'. + Multiple formats can be specified, without restriction. + For example: export_fig('-jpg', '-pdf', '-png', ...) + Note: '-tif','-tiff' are equivalent, and so are '-jpg','-jpeg'. + -transparent - option indicating that the figure background is to be made + transparent (PNG,PDF,TIF,EPS,EMF formats only). Implies -noinvert. + -nocrop - option indicating that empty margins should not be cropped. + -c[,,,] - option indicating crop amounts. Must be + a 4-element vector of numeric values: [top,right,bottom,left] + where NaN/Inf indicates auto-cropping, 0 means no cropping, any + other value means cropping in pixel amounts. e.g. '-c7,15,0,NaN' + Note: this option is not supported by SVG and EMF formats. + -p - option to pad a border of width val to exported files, where + val is either a relative size with respect to cropped image + size (i.e. p=0.01 adds a 1border). For EPS & PDF formats, + val can also be integer in units of 1/72" points (abs(val)>1). + val can be positive (padding) or negative (extra cropping). + If used, the -nocrop flag will be ignored, i.e. the image will + always be cropped and then padded. Default: 0 (i.e. no padding). + Note: this option is not supported by SVG and EMF formats. + -m - option val indicates the factor to magnify the figure dimensions + when generating bitmap outputs (does not affect vector formats). + Default: '-m1' (i.e. val=1). Note: val~=1 slows down export_fig. + -r - option val indicates the resolution (in pixels per inch) to + export bitmap and vector outputs, without changing dimensions of + the on-screen figure. Default: '-r864' (for vector output only). + Note: -m option overides -r option for bitmap exports only. + -native - option indicating that the output resolution (when outputting + a bitmap format) should be such that the vertical resolution + of the first suitable image found in the figure is at the + native resolution of that image. To specify a particular + image to use, give it the tag 'export_fig_native'. + Notes: This overrides any value set with the -m and -r options. + It also assumes that the image is displayed front-to-parallel + with the screen. The output resolution is approximate and + should not be relied upon. Anti-aliasing can have adverse + effects on image quality (disable with the -a1 option). + -a1, -a2, -a3, -a4 - option indicating the amount of anti-aliasing (AA) to + use for bitmap outputs, when GraphicsSmoothing is not available. + '-a1'=no AA; '-a4'=max. Default: 3 for HG1, 1 for HG2. + - - option to force a particular renderer (painters, opengl or + [in R2014a or older] zbuffer). Default value: opengl for bitmap + formats or figures with patches and/or transparent annotations; + painters for vector formats without patches/transparencies. + - - option indicating which colorspace color figures should + be saved in: RGB (default), CMYK or gray. Usage example: '-gray'. + Note: CMYK is only supported in PDF, EPS and TIF formats. + -q - option to vary bitmap image quality (PDF, EPS, JPG formats only). + A larger val, in the range 0-100, produces higher quality and + lower compression. val > 100 results in lossless compression. + Default: '-q95' for JPG, ghostscript prepress default for PDF,EPS. + Note: lossless compression can sometimes give a smaller file size + than the default lossy compression, depending on the image type. + -append - option indicating that if the file already exists the figure is to + be appended as a new page, instead of being overwritten (default). + PDF, TIF & GIF output formats only (multi-image GIF = animated). + -bookmark - option to indicate that a bookmark with the name of the + figure is to be created in the output file (PDF format only). + -clipboard - option to save output as an image on the system clipboard. + -clipboard<:format> - copies to clipboard in the specified format: + image (default), bitmap, emf, or pdf. + Notes: Only -clipboard (or -clipboard:image, which is the same) + applies export_fig parameters such as cropping, padding etc. + Only the emf format supports -transparent background + -clipboard:image create a bitmap image using export_fig processing + -clipboard:bitmap create a bitmap image as-is (no auto-cropping etc.) + -clipboard:emf is vector format without auto-cropping; Windows-only + -clipboard:pdf is vector format without cropping; not universally supported + -d - option to indicate a ghostscript setting. For example, + -dMaxBitmap=0 or -dNoOutputFonts (Ghostscript 9.15+). + -depsc - option to use EPS level-3 rather than the default level-2 print + device. This solves some bugs with Matlab's default -depsc2 device + such as discolored subplot lines on images (vector formats only). + -update - option to download and install the latest version of export_fig + -version - return the current export_fig version, without any figure export + -nofontswap - option to avoid font swapping. Font swapping is automatically + done in vector formats (only): 11 standard Matlab fonts are + replaced by the original figure fonts. This option prevents this. + -font_space - option to set a spacer character for font-names that + contain spaces, used by EPS/PDF. Default: '' + -linecaps - option to create rounded line-caps (vector formats only). + -noinvert - option to avoid setting figure's InvertHardcopy property to + 'off' during output (this solves some problems of empty outputs). + -preserve_size - option to preserve the figure's PaperSize property in output + file (PDF/EPS formats only; default is to not preserve it). + -options - format-specific parameters as defined in Matlab's + documentation of the imwrite function, contained in a struct under + the format name. For example to specify the JPG Comment parameter, + pass a struct such as this: options.JPG.Comment='abc'. Similarly, + options.PNG.BitDepth=4. Only used by PNG,TIF,JPG,GIF output formats. + Options can also be specified as a cell array of name-value pairs, + e.g. {'BitDepth',4, 'Author','Yair'} - these options will be used + by all supported output formats of the export_fig command. + -silent - option to avoid various warning and informational messages, such + as version update checks, transparency or renderer issues, etc. + -regexprep - replaces all occurances of (a regular expression + string or array of strings; case-sensitive), with the corresponding + string(s), in EPS/PDF files (only). See regexp function's doc. + Warning: invalid replacement can make your EPS/PDF file unreadable! + -toolbar - adds an interactive export button to the figure's toolbar + -menubar - adds an interactive export menu to the figure's menubar + handle - handle of the figure, axes or uipanels (can be an array of handles + but all the objects must be in the same figure) to be exported. + Default: gcf (handle of current figure). + figName - name (title) of the figure to export (e.g. 'Figure 1' or 'My fig'). + Overriden by handle (if specified); Default: current figure + +Outputs: + imageData - MxNxC uint8 image array of the exported image. + alpha - MxN single array of alphamatte values in the range [0,1], + for the case when the background is transparent. + +Some helpful examples/tips are listed at: https://github.com/altmany/export_fig + +See also PRINT, SAVEAS, ScreenCapture (on the Matlab File Exchange) + +Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015- diff --git a/matlab/export_fig/append_pdfs.m b/matlab/export_fig/append_pdfs.m new file mode 100644 index 0000000..efd82ae --- /dev/null +++ b/matlab/export_fig/append_pdfs.m @@ -0,0 +1,172 @@ +function append_pdfs(varargin) +%APPEND_PDFS Appends/concatenates multiple PDF files +% +% Usage example: +% append_pdfs(outputFilename, inputFilename1, inputFilename2, ...) +% append_pdfs(outputFilename, inputFilenames_list{:}) +% append_pdfs(outputFilename, inputFilenames_cell_or_string_array) +% append_pdfs output.pdf input1.pdf input2.pdf +% +% This function appends multiple PDF files to an existing PDF file, or +% concatenates them into a PDF file if the output file doesn't yet exist. +% +% This function requires that you have ghostscript installed on your +% system. Ghostscript can be downloaded from: http://www.ghostscript.com +% +% Inputs: +% output - output file name (including the .pdf extension). +% If it exists it is appended to; if not, it is created. +% input1 - input file name(s) (including the .pdf extension). +% All input files are appended in order. +% input_list - cell array list of input file name strings. All input +% files are appended in order. + +% Copyright: Oliver Woodford, 2011-2014, Yair Altman 2015- + +%{ +% Thanks to Reinhard Knoll for pointing out that appending multiple pdfs in +% one go is much faster than appending them one at a time. + +% Thanks to Michael Teo for reporting the issue of a too long command line. +% Issue resolved on 5/5/2011, by passing gs a command file. + +% Thanks to Martin Wittmann for pointing out quality issue when appending bitmaps +% Issue resolved (to best of my ability) 1/6/2011, using the prepress setting + +% 26/02/15: If temp dir is not writable, use the output folder for temp +% files when appending (Javier Paredes); sanity check of inputs +% 24/01/18: Fixed error in case of existing output file (append mode) +% 24/01/18: Fixed issue #213: non-ASCII characters in folder names on Windows +% 06/12/18: Avoid an "invalid escape-char" warning upon error +% 22/03/20: Alert if ghostscript.m is not found on Matlab path +% 29/03/20: Accept a cell-array of input files (issue #299); accept both "strings", 'chars' +% 25/01/22: Improved handling of missing input files & folder with non-ASCII chars (issue #349) +%} + + if nargin < 2, return; end % sanity check + + % Convert strings => chars; strtrim extra spaces + varargin = cellfun(@str2char,varargin,'un',false); + + % Convert cell array into individual strings (issue #299) + if nargin==2 && iscell(varargin{2}) + varargin = {varargin{1} varargin{2}{:}}; %#ok + end + + % Handle special cases of input args + numArgs = numel(varargin); + if numArgs < 2 + error('export_fig:append_pdfs:NoInputs', 'append_pdfs: Missing input filenames') + end + + % Ensure that ghostscript() exists on the Matlab path + if ~exist('ghostscript','file') + error('export_fig:append_pdfs:ghostscript', 'The ghostscript.m function is required by append_pdf.m. Install the complete export_fig package from https://www.mathworks.com/matlabcentral/fileexchange/23629-export_fig or https://github.com/altmany/export_fig') + end + + % Are we appending or creating a new file? + append = exist(varargin{1}, 'file') == 2; + if ~append && numArgs == 2 % only 1 input file - copy it directly to output + copyfile(varargin{2}, varargin{1}); + return + end + + % Ensure that the temp dir is writable (Javier Paredes 26/2/15) + output = [tempname '.pdf']; + try + fid = fopen(output,'w'); + fwrite(fid,1); + fclose(fid); + delete(output); + isTempDirOk = true; + catch + % Temp dir is not writable, so use the output folder + [dummy,fname,fext] = fileparts(output); %#ok + fpath = fileparts(varargin{1}); + output = fullfile(fpath,[fname fext]); + isTempDirOk = false; + end + if ~append + output = varargin{1}; + varargin = varargin(2:end); + end + + % Ensure that all input files exist + for fileIdx = 2 : numel(varargin) + filename = varargin{fileIdx}; + if ~exist(filename,'file') + error('export_fig:append_pdf:MissingFile','Input file %s does not exist',filename); + end + end + + % Create the command file + if isTempDirOk + cmdfile = [tempname '.txt']; + else + cmdfile = fullfile(fpath,[fname '.txt']); + end + prepareCmdFile(cmdfile, output, varargin{:}); + + % Call ghostscript + [status, errMsg] = ghostscript(['@"' cmdfile '"']); + + % Check for ghostscript execution errors + if status && ~isempty(strfind(errMsg,'undefinedfile')) && ispc %#ok + % Fix issue #213: non-ASCII characters in folder names on Windows + for fileIdx = 2 : numel(varargin) + [fpath,fname,fext] = fileparts(varargin{fileIdx}); + varargin{fileIdx} = fullfile(normalizePath(fpath),[fname fext]); + end + % Rerun ghostscript with the normalized folder names + prepareCmdFile(cmdfile, output, varargin{:}); + [status, errMsg] = ghostscript(['@"' cmdfile '"']); + end + + % Delete the command file + delete(cmdfile); + + % Check for ghostscript execution errors + if status + errMsg = strrep(errMsg,'\','\\'); % Avoid an "invalid escape-char" warning + error('export_fig:append_pdf:ghostscriptError',errMsg); + end + + % Rename the file if needed + if append + movefile(output, varargin{1}, 'f'); + end +end + +% Prepare a text file with ghostscript directives +function prepareCmdFile(cmdfile, output, varargin) + fh = fopen(cmdfile, 'w'); + fprintf(fh, '-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile="%s" -f', output); + fprintf(fh, ' "%s"', varargin{:}); + fclose(fh); +end + +% Convert long/non-ASCII folder names into their short ASCII equivalents +function pathStr = normalizePath(pathStr) + [fpath,fname,fext] = fileparts(pathStr); + if isempty(fpath) || strcmpi(fpath,pathStr), return, end + dirOutput = evalc(['system(''dir /X /AD "' pathStr '*"'')']); + regexpStr = ['.*\s(\S+)\s*' fname fext '.*']; + shortName = regexprep(dirOutput,regexpStr,'$1'); + if isempty(shortName) || isequal(shortName,dirOutput) + shortName = [fname fext]; + end + fpath = normalizePath(fpath); %recursive until entire fpath is processed + pathStr = fullfile(fpath, shortName); +end + +% Convert a possible string => char +function value = str2char(value) + try + value = controllib.internal.util.hString2Char(value); + catch + if isa(value,'string') + value = char(value); + end + end + value = strtrim(value); +end diff --git a/matlab/export_fig/copyfig.m b/matlab/export_fig/copyfig.m new file mode 100644 index 0000000..9a5b8cb --- /dev/null +++ b/matlab/export_fig/copyfig.m @@ -0,0 +1,59 @@ +function fh = copyfig(fh) +%COPYFIG Create a copy of a figure, without changing the figure +% +% Examples: +% fh_new = copyfig(fh_old) +% +% This function will create a copy of a figure, but not change the figure, +% as copyobj sometimes does, e.g. by changing legends. +% +% IN: +% fh_old - The handle of the figure to be copied. Default: gcf. +% +% OUT: +% fh_new - The handle of the created figure. + +% Copyright (C) Oliver Woodford 2012, Yair Altman 2015 + +% 26/02/15: If temp dir is not writable, use the dest folder for temp +% destination files (Javier Paredes) +% 15/04/15: Suppress warnings during copyobj (Dun Kirk comment on FEX page 2013-10-02) +% 09/09/18: Fix issue #252: Workaround for cases where copyobj() fails for any reason + + % Set the default + if nargin == 0 + fh = gcf; + end + % Is there a legend? + useCopyobj = isempty(findall(fh, 'Type', 'axes', 'Tag', 'legend')); + if useCopyobj + % Safe to copy using copyobj + oldWarn = warning('off'); %Suppress warnings during copyobj (Dun Kirk comment on FEX page 2013-10-02) + try + fh = copyobj(fh, 0); + catch + % Fix issue #252: Workaround for cases where copyobj() fails for any reason + useCopyobj = false; % if copyobj() croaks, use file save/load below + end + warning(oldWarn); + end + if ~useCopyobj + % copyobj will change the figure, so save and then load it instead + tmp_nam = [tempname '.fig']; + try + % Ensure that the temp dir is writable (Javier Paredes 26/2/15) + fid = fopen(tmp_nam,'w'); + fwrite(fid,1); + fclose(fid); + delete(tmp_nam); % cleanup + catch + % Temp dir is not writable, so use the current folder + [dummy,fname,fext] = fileparts(tmp_nam); %#ok + fpath = pwd; + tmp_nam = fullfile(fpath,[fname fext]); + end + hgsave(fh, tmp_nam); + fh = hgload(tmp_nam); + delete(tmp_nam); + end +end diff --git a/matlab/export_fig/crop_borders.m b/matlab/export_fig/crop_borders.m new file mode 100644 index 0000000..83abd61 --- /dev/null +++ b/matlab/export_fig/crop_borders.m @@ -0,0 +1,161 @@ +function [A, vA, vB, bb_rel] = crop_borders(A, bcol, padding, crop_amounts) +%CROP_BORDERS Crop the borders of an image or stack of images +% +% [B, vA, vB, bb_rel] = crop_borders(A, bcol, [padding]) +% +%IN: +% A - HxWxCxN stack of images. +% bcol - Cx1 background colour vector. +% padding - scalar indicating how much padding to have in relation to +% the cropped-image-size (0<=padding<=1). Default: 0 +% crop_amounts - 4-element vector of crop amounts: [top,right,bottom,left] +% where NaN/Inf indicate auto-cropping, 0 means no cropping, +% and any other value mean cropping in pixel amounts. +% +%OUT: +% B - JxKxCxN cropped stack of images. +% vA - coordinates in A that contain the cropped image +% vB - coordinates in B where the cropped version of A is placed +% bb_rel - relative bounding box (used for eps-cropping) + +%{ +% 06/03/15: Improved image cropping thanks to Oscar Hartogensis +% 08/06/15: Fixed issue #76: case of transparent figure bgcolor +% 21/02/16: Enabled specifying non-automated crop amounts +% 04/04/16: Fix per Luiz Carvalho for old Matlab releases +% 23/10/16: Fixed issue #175: there used to be a 1px minimal padding in case of crop, now removed +% 15/05/22: Fixed EPS bounding box (issue #356) +%} + + if nargin < 3 + padding = 0; + end + if nargin < 4 + crop_amounts = nan(1,4); % =auto-cropping + end + crop_amounts(end+1:4) = NaN; % fill missing values with NaN + + [h, w, c, n] = size(A); + if isempty(bcol) % case of transparent bgcolor + bcol = A(ceil(end/2),1,:,1); + end + if isscalar(bcol) + bcol = bcol(ones(c, 1)); + end + + % Crop margin from left + if ~isfinite(crop_amounts(4)) + bail = false; + for l = 1:w + for a = 1:c + if ~all(col(A(:,l,a,:)) == bcol(a)) + bail = true; + break; + end + end + if bail + break; + end + end + else + l = 1 + abs(crop_amounts(4)); + end + + % Crop margin from right + if ~isfinite(crop_amounts(2)) + bcol = A(ceil(end/2),w,:,1); + bail = false; + for r = w:-1:l + for a = 1:c + if ~all(col(A(:,r,a,:)) == bcol(a)) + bail = true; + break; + end + end + if bail + break; + end + end + else + r = w - abs(crop_amounts(2)); + end + + % Crop margin from top + if ~isfinite(crop_amounts(1)) + bcol = A(1,ceil(end/2),:,1); + bail = false; + for t = 1:h + for a = 1:c + if ~all(col(A(t,:,a,:)) == bcol(a)) + bail = true; + break; + end + end + if bail + break; + end + end + else + t = 1 + abs(crop_amounts(1)); + end + + % Crop margin from bottom + bcol = A(h,ceil(end/2),:,1); + if ~isfinite(crop_amounts(3)) + bail = false; + for b = h:-1:t + for a = 1:c + if ~all(col(A(b,:,a,:)) == bcol(a)) + bail = true; + break; + end + end + if bail + break; + end + end + else + b = h - abs(crop_amounts(3)); + end + + if padding == 0 % no padding + % Issue #175: there used to be a 1px minimal padding in case of crop, now removed + %{ + if ~isequal([t b l r], [1 h 1 w]) % Check if we're actually croppping + padding = 1; % Leave one boundary pixel to avoid bleeding on resize + bcol(:) = nan; % make the 1px padding transparent + end + %} + elseif abs(padding) < 1 % pad value is a relative fraction of image size + padding = sign(padding)*round(mean([b-t r-l])*abs(padding)); % ADJUST PADDING + else % pad value is in units of 1/72" points + padding = round(padding); % fix cases of non-integer pad value + end + + if padding > 0 % extra padding + % Create an empty image, containing the background color, that has the + % cropped image size plus the padded border + B = repmat(bcol,[(b-t)+1+padding*2,(r-l)+1+padding*2,1,n]); % Fix per Luiz Carvalho + % vA - coordinates in A that contain the cropped image + vA = [t b l r]; + % vB - coordinates in B where the cropped version of A will be placed + vB = [padding+1, (b-t)+1+padding, padding+1, (r-l)+1+padding]; + % Place the original image in the empty image + B(vB(1):vB(2), vB(3):vB(4), :, :) = A(vA(1):vA(2), vA(3):vA(4), :, :); + A = B; + else % extra cropping + vA = [t-padding b+padding l-padding r+padding]; + A = A(vA(1):vA(2), vA(3):vA(4), :, :); + vB = [NaN NaN NaN NaN]; + end + + % For EPS cropping, determine the relative BoundingBox - bb_rel + bb_pixels = [l-1 h-b-1 r+1 h-t+1]; %[LowerLeftXY, UpperRightXY] + bb_pixels(bb_pixels<0) = 0; + bb_pixels = min(bb_pixels, [w h w h]); + bb_rel = bb_pixels ./ [w h w h]; +end + +function A = col(A) + A = A(:); +end diff --git a/matlab/export_fig/eps2pdf.m b/matlab/export_fig/eps2pdf.m new file mode 100644 index 0000000..aef0c08 --- /dev/null +++ b/matlab/export_fig/eps2pdf.m @@ -0,0 +1,285 @@ +function eps2pdf(source, dest, crop, append, gray, quality, gs_options) +%EPS2PDF Convert an eps file to pdf format using ghostscript +% +% Examples: +% eps2pdf source dest +% eps2pdf(source, dest, crop) +% eps2pdf(source, dest, crop, append) +% eps2pdf(source, dest, crop, append, gray) +% eps2pdf(source, dest, crop, append, gray, quality) +% eps2pdf(source, dest, crop, append, gray, quality, gs_options) +% +% This function converts an eps file to pdf format. The output can be +% optionally cropped and also converted to grayscale. If the output pdf +% file already exists then the eps file can optionally be appended as a new +% page on the end of the eps file. The level of bitmap compression can also +% optionally be set. +% +% This function requires that you have ghostscript installed on your system. +% Ghostscript can be downloaded from: http://www.ghostscript.com +% +% Inputs: +% source - filename of the source eps file to convert. The filename is +% assumed to already have the extension ".eps". +% dest - filename of the destination pdf file. The filename is assumed +% to already have the extension ".pdf". +% crop - boolean indicating whether to crop the borders off the pdf. +% Default: true. +% append - boolean indicating whether the eps should be appended to the +% end of the pdf as a new page (if the pdf exists already). +% Default: false. +% gray - boolean indicating whether the output pdf should be grayscale +% or not. Default: false. +% quality - scalar indicating the level of image bitmap quality to +% output. A larger value gives a higher quality. quality > 100 +% gives lossless output. Default: ghostscript prepress default. +% gs_options - optional ghostscript options (e.g.: '-dNoOutputFonts'). If +% multiple options are needed, enclose in call array: {'-a','-b'} + +% Copyright (C) Oliver Woodford 2009-2014, Yair Altman 2015- + +% Suggestion of appending pdf files provided by Matt C at: +% http://www.mathworks.com/matlabcentral/fileexchange/23629 + +% Thank you Fabio Viola for pointing out compression artifacts, leading to the quality setting. +% Thank you Scott for pointing out the subsampling of very small images, which was fixed for lossless compression settings. + +% 09/12/11: Pass font path to ghostscript +% 26/02/15: If temp dir is not writable, use the dest folder for temp destination files (Javier Paredes) +% 28/02/15: Enable users to specify optional ghostscript options (issue #36) +% 01/03/15: Upon GS error, retry without the -sFONTPATH= option (this might solve +% some /findfont errors according to James Rankin, FEX Comment 23/01/15) +% 23/06/15: Added extra debug info in case of ghostscript error; code indentation +% 04/10/15: Suggest a workaround for issue #41 (missing font path; thanks Mariia Fedotenkova) +% 22/02/16: Bug fix from latest release of this file (workaround for issue #41) +% 20/03/17: Added informational message in case of GS croak (issue #186) +% 16/01/18: Improved appending of multiple EPS files into single PDF (issue #233; thanks @shartjen) +% 18/10/19: Workaround for GS 9.51+ .setpdfwrite removal problem (issue #285) +% 18/10/19: Warn when ignoring GS fontpath or quality options; clarified error messages +% 15/01/20: Added information about the GS/destination filepath in case of error (issue #294) +% 20/01/20: Attempted fix for issue #285: unsupported patch transparency in some Ghostscript versions +% 12/02/20: Improved fix for issue #285: add -dNOSAFER and -dALLOWPSTRANSPARENCY (thanks @linasstonys) +% 26/08/21: Added GS version to error message; fixed some problems with PDF append (issue #339) + + % Intialise the options string for ghostscript + options = ['-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sOutputFile="' dest '"']; + + % Set crop option + if nargin < 3 || crop + options = [options ' -dEPSCrop']; + end + + % Set the font path + fp = font_path(); + if ~isempty(fp) + options = [options ' -sFONTPATH="' fp '"']; + end + + % Set the grayscale option + if nargin > 4 && gray + options = [options ' -sColorConversionStrategy=Gray -dProcessColorModel=/DeviceGray']; + end + + % Set the bitmap quality + qualityOptions = ''; + if nargin > 5 && ~isempty(quality) + qualityOptions = ' -dAutoFilterColorImages=false -dAutoFilterGrayImages=false'; + if quality > 100 + qualityOptions = [qualityOptions ' -dColorImageFilter=/FlateEncode -dGrayImageFilter=/FlateEncode']; + qualityOptions = [qualityOptions ' -c ".setpdfwrite << /ColorImageDownsampleThreshold 10 /GrayImageDownsampleThreshold 10 >> setdistillerparams"']; + else + qualityOptions = [qualityOptions ' -dColorImageFilter=/DCTEncode -dGrayImageFilter=/DCTEncode']; + v = 1 + (quality < 80); + quality = 1 - quality / 100; + s = sprintf('<< /QFactor %.2f /Blend 1 /HSample [%d 1 1 %d] /VSample [%d 1 1 %d] >>', quality, v, v, v, v); + qualityOptions = [qualityOptions ' -c ".setpdfwrite << /ColorImageDict ' s ' /GrayImageDict ' s ' >> setdistillerparams"']; + end + options = [options qualityOptions]; + end + + % Enable users to specify optional ghostscript options (issue #36) + if nargin > 6 && ~isempty(gs_options) + if iscell(gs_options) + gs_options = sprintf(' %s',gs_options{:}); + elseif ~ischar(gs_options) + error('gs_options input argument must be a string or cell-array of strings'); + else + gs_options = [' ' gs_options]; + end + options = [options gs_options]; + end + + % Check if the output file exists + if nargin > 3 && append && exist(dest, 'file') == 2 + % Store the original filesize for later use below + try + file_info = dir(dest); + orig_bytes = file_info.bytes; + catch + orig_bytes = []; + end + % File exists - append current figure to the end + tmp_nam = [tempname '.pdf']; + [fpath,fname,fext] = fileparts(tmp_nam); + try + % Ensure that the temp dir is writable (Javier Paredes 26/2/15) + fid = fopen(tmp_nam,'w'); + fwrite(fid,1); + fclose(fid); + delete(tmp_nam); + catch + % Temp dir is not writable, so use the dest folder + fpath = fileparts(dest); + tmp_nam = fullfile(fpath,[fname fext]); + end + % Copy the original (dest) pdf file to temporary folder + copyfile(dest, tmp_nam); + % Produce an interim pdf of the source eps, rather than adding the eps directly (issue #233) + % this will override the original (dest) pdf file + orig_options = options; + ghostscript([options ' -f "' source '"']); + [~,fname] = fileparts(tempname); + tmp_nam2 = fullfile(fpath,[fname fext]); % ensure using a writable folder (not necessarily tempdir) + copyfile(dest, tmp_nam2); + % Add the original pdf (tmp_nam) and interim pdf (dest=>tmp_nam2) as inputs to ghostscript + %options = [options ' -f "' tmp_nam '" "' source '"']; % append the source eps to dest pdf + options = [options ' -f "' tmp_nam '" "' tmp_nam2 '"']; % append the interim pdf to dest pdf + try + % Convert to pdf using ghostscript + [status, message] = ghostscript(options); + % The output pdf should now be in dest + + % If the returned message is non-empty, a possible error may have + % occured, so check the file size to ensure whether the file grew + if ~isempty(message) && ~isempty(orig_bytes) + file_info = dir(dest); + new_bytes = file_info.bytes; + if new_bytes < orig_bytes + 100 + % Looks like nothing substantial (if anything) was appended to + % the original pdf, so try adding the eps file directly (issue #339) + options = [orig_options ' -f "' tmp_nam '" "' source '"']; % append the source eps to dest pdf + [status, message] = ghostscript(options); + end + end + + % Delete the intermediate (temporary) files + delete(tmp_nam); + delete(tmp_nam2); + catch me + % Delete the intermediate files and rethrow the error + delete(tmp_nam); + delete(tmp_nam2); + rethrow(me); + end + else + % File doesn't exist or should be over-written + % Add the source eps file as input to ghostscript + options = [options ' -f "' source '"']; + % Convert to pdf using ghostscript + [status, message] = ghostscript(options); + end + + % Check for error + if status + % Catch and correct undefined .setopacityalpha errors (issue #285) + % (see explanation inside print2eps.m) + if ~isempty(regexpi(message,'undefined in .setopacityalpha')) + % First try with -dNOSAFER and -dALLOWPSTRANSPARENCY (thanks @linasstonys) + new_options = [options ' -dNOSAFER -dALLOWPSTRANSPARENCY']; + [status, message] = ghostscript(new_options); + if ~status % hurray! (no error) + return + elseif isempty(regexpi(message,'undefined in .setopacityalpha')) % still some other error + options = new_options; + else % we still get a .setopacityalpha error + % Remove the transparency and retry + fstrm = read_write_entire_textfile(source); + fstrm = regexprep(fstrm, '0?\.\d+ .setopacityalpha \w+\n', ''); + read_write_entire_textfile(source, fstrm); + [status, message] = ghostscript(options); + if ~status % hurray! (no error) + % Alert the user that transparency is not supported + warning('export_fig:GS:quality','Export_fig Face/Edge alpha transparancy is ignored - not supported by your Ghostscript version') + return + end + end + end + + % Retry without the -sFONTPATH= option (this might solve some GS + % /findfont errors according to James Rankin, FEX Comment 23/01/15) + orig_options = options; + if ~isempty(fp) + options = regexprep(options, ' -sFONTPATH=[^ ]+ ',' '); + [status, message] = ghostscript(options); + if ~status % hurray! (no error) + warning('export_fig:GS:fontpath','Export_fig font option is ignored - not supported by your Ghostscript version') + return + end + end + + % Retry without quality options (may solve problems with GS 9.51+, issue #285) + if ~isempty(qualityOptions) + options = strrep(orig_options, qualityOptions, ''); + [status, message] = ghostscript(options); + if ~status % hurray! (no error) + warning('export_fig:GS:quality','Export_fig quality option is ignored - not supported by your Ghostscript version') + return + end + end + + % Report error + if isempty(message) + error(['Unable to generate pdf. Ensure that the destination folder (' fileparts(dest) ') is writable.']); + elseif ~isempty(strfind(message,'/typecheck in /findfont')) %#ok + % Suggest a workaround for issue #41 (missing font path) + font_name = strtrim(regexprep(message,'.*Operand stack:\s*(.*)\s*Execution.*','$1')); + fprintf(2, 'Ghostscript error: could not find the following font(s): %s\n', font_name); + %fpath = fileparts(mfilename('fullpath')); + %gs_fonts_file = fullfile(fpath, '.ignore', 'gs_font_path.txt'); + [unused, gs_fonts_file] = user_string('gs_font_path'); %#ok + fprintf(2, ' try to add the font''s folder to your %s file\n\n', gs_fonts_file); + error('export_fig error'); + else + gs_options = strtrim(gs_options); + fprintf(2, '\nGhostscript error: '); + msg = regexprep(message, '^Error: /([^\n]+).*', '$1'); + if ~isempty(msg) && ~strcmp(msg,message) + fprintf(2,'%s',msg); + end + fprintf(2, '\n * perhaps %s is open by another application\n', dest); + try gs_version = str2num(evalc('ghostscript(''--version'');')); catch, gs_version = ''; end %#ok + if ~isempty(gs_version), gs_version = [' ' num2str(gs_version)]; end + if ~isempty(gs_options) + fprintf(2, ' * or maybe your Ghostscript version%s does not accept the extra "%s" option(s) that you requested\n', gs_version, gs_options); + end + fprintf(2, ' * or maybe you have another gs executable in your system''s path\n\n'); + fprintf(2, 'Ghostscript path: %s\n', user_string('ghostscript')); + fprintf(2, 'Ghostscript options: %s\n\n', orig_options); + error(message); + end + end +end + +% Function to return (and create, where necessary) the font path +function fp = font_path() + fp = user_string('gs_font_path'); + if ~isempty(fp) + return + end + % Create the path + % Start with the default path + fp = getenv('GS_FONTPATH'); + % Add on the typical directories for a given OS + if ispc + if ~isempty(fp) + fp = [fp ';']; + end + fp = [fp getenv('WINDIR') filesep 'Fonts']; + else + if ~isempty(fp) + fp = [fp ':']; + end + fp = [fp '/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype']; + end + user_string('gs_font_path', fp); +end diff --git a/matlab/export_fig/export_fig-master/resources/project/Extensions.type.Root/DependencyAnalysis.type.Extension/ExternalFiles.type.Extension.xml b/matlab/export_fig/export_fig-master/resources/project/Extensions.type.Root/DependencyAnalysis.type.Extension/ExternalFiles.type.Extension.xml new file mode 100644 index 0000000..91869b6 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Extensions.type.Root/DependencyAnalysis.type.Extension/ExternalFiles.type.Extension.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Project.xml b/matlab/export_fig/export_fig-master/resources/project/Project.xml new file mode 100644 index 0000000..4a9e34e --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Project.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/ProjectData.type.Info.xml b/matlab/export_fig/export_fig-master/resources/project/ProjectData.type.Info.xml new file mode 100644 index 0000000..de0b14e --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/ProjectData.type.Info.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category.xml new file mode 100644 index 0000000..ef38945 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/artifact.type.Label.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/artifact.type.Label.xml new file mode 100644 index 0000000..b56f659 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/artifact.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/convenience.type.Label.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/convenience.type.Label.xml new file mode 100644 index 0000000..5272801 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/convenience.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/derived.type.Label.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/derived.type.Label.xml new file mode 100644 index 0000000..5a873c8 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/derived.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/design.type.Label.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/design.type.Label.xml new file mode 100644 index 0000000..59cb0be --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/design.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/none.type.Label.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/none.type.Label.xml new file mode 100644 index 0000000..27ca3e7 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/none.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/other.type.Label.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/other.type.Label.xml new file mode 100644 index 0000000..14d104f --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/other.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/test.type.Label.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/test.type.Label.xml new file mode 100644 index 0000000..5a6f802 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Categories/FileClassCategory.type.Category/test.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/.gitignore.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/.gitignore.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/.gitignore.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/ImageSelection.class.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/ImageSelection.class.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/ImageSelection.class.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/ImageSelection.java.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/ImageSelection.java.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/ImageSelection.java.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/LICENSE.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/LICENSE.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/LICENSE.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/README.md.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/README.md.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/README.md.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/append_pdfs.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/append_pdfs.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/append_pdfs.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/copyfig.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/copyfig.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/copyfig.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/crop_borders.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/crop_borders.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/crop_borders.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/eps2pdf.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/eps2pdf.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/eps2pdf.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/export_fig.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/export_fig.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/export_fig.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/fix_lines.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/fix_lines.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/fix_lines.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/ghostscript.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/ghostscript.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/ghostscript.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/im2gif.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/im2gif.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/im2gif.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/isolate_axes.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/isolate_axes.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/isolate_axes.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/pdf2eps.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/pdf2eps.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/pdf2eps.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/pdftops.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/pdftops.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/pdftops.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/print2array.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/print2array.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/print2array.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/print2eps.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/print2eps.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/print2eps.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/read_write_entire_textfile.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/read_write_entire_textfile.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/read_write_entire_textfile.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/user_string.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/user_string.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/user_string.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/using_hg2.m.type.File.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/using_hg2.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.Files/using_hg2.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/Root.type.ProjectPath/a533e478-c90b-4a1f-a45b-f8877af57bee.type.Reference.xml b/matlab/export_fig/export_fig-master/resources/project/Root.type.ProjectPath/a533e478-c90b-4a1f-a45b-f8877af57bee.type.Reference.xml new file mode 100644 index 0000000..59b7a5d --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/Root.type.ProjectPath/a533e478-c90b-4a1f-a45b-f8877af57bee.type.Reference.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig-master/resources/project/uuid-cc21a9b0-026d-4b70-9821-3eb23d2abf81.xml b/matlab/export_fig/export_fig-master/resources/project/uuid-cc21a9b0-026d-4b70-9821-3eb23d2abf81.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/export_fig-master/resources/project/uuid-cc21a9b0-026d-4b70-9821-3eb23d2abf81.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/export_fig.m b/matlab/export_fig/export_fig.m new file mode 100644 index 0000000..f29492d --- /dev/null +++ b/matlab/export_fig/export_fig.m @@ -0,0 +1,2665 @@ +function [imageData, alpha] = export_fig(varargin) %#ok<*STRCL1> +%EXPORT_FIG Exports figures in a publication-quality format +% +% Examples: +% imageData = export_fig +% [imageData, alpha] = export_fig +% export_fig filename +% export_fig filename -format1 -format2 +% export_fig ... -nocrop +% export_fig ... -c[,,,] +% export_fig ... -transparent +% export_fig ... -native +% export_fig ... -m +% export_fig ... -r +% export_fig ... -a +% export_fig ... -q +% export_fig ... -p +% export_fig ... -d +% export_fig ... -depsc +% export_fig ... - +% export_fig ... - +% export_fig ... -append +% export_fig ... -bookmark +% export_fig ... -clipboard<:format> +% export_fig ... -update +% export_fig ... -version +% export_fig ... -nofontswap +% export_fig ... -font_space +% export_fig ... -linecaps +% export_fig ... -noinvert +% export_fig ... -preserve_size +% export_fig ... -options +% export_fig ... -silent +% export_fig ... -regexprep +% export_fig ... -toolbar +% export_fig ... -menubar +% export_fig(..., handle) +% export_fig(..., figName) +% +% This function saves a figure or single axes to one or more vector and/or +% bitmap file formats, and/or outputs a rasterized version to the workspace, +% with the following properties: +% - Figure/axes reproduced as it appears on screen +% - Cropped borders (optional) +% - Embedded fonts (vector formats) +% - Improved line and grid line styles +% - Anti-aliased graphics (bitmap formats) +% - Render images at native resolution (optional for bitmap formats) +% - Transparent background supported (pdf, eps, png, tif, gif) +% - Semi-transparent patch objects supported (png, tif) +% - RGB, CMYK or grayscale output (CMYK only with pdf, eps, tif) +% - Variable image compression, including lossless (pdf, eps, jpg) +% - Optional rounded line-caps (pdf, eps) +% - Optionally append to file (pdf, tif, gif) +% - Vector formats: pdf, eps, emf, svg +% - Bitmap formats: png, tif, jpg, bmp, gif, clipboard, export to workspace +% +% This function is especially suited to exporting figures for use in +% publications and presentations, because of the high quality and +% portability of media produced. +% +% Note that the background color and figure dimensions are reproduced +% (the latter approximately, and ignoring cropping & magnification) in the +% output file. For transparent background (and semi-transparent patch +% objects), use the -transparent option or set the figure 'Color' property +% to 'none'. To make axes transparent set the axes 'Color' property to +% 'none'. PDF, EPS, TIF & PNG are the only formats that support a transparent +% background; only TIF & PNG formats support transparency of patch objects. +% +% The choice of renderer (opengl/zbuffer/painters) has a large impact on the +% output quality. The default value (opengl for bitmaps, painters for vector +% formats) generally gives good results, but if you aren't satisfied +% then try another renderer. Notes: +% 1) For vector formats (EPS,PDF), only painters generates vector graphics +% 2) For bitmap formats, only opengl correctly renders transparent patches +% 3) For bitmap formats, only painters correctly scales line dash and dot +% lengths when magnifying or anti-aliasing +% 4) Fonts may be substitued with Courier when using painters +% +% When exporting to vector format (PDF & EPS) and bitmap format using the +% painters renderer, this function requires that ghostscript is installed +% on your system. You can download this from: http://www.ghostscript.com +% When exporting to EPS it additionally requires pdftops, from the Xpdf +% suite of functions. You can download this from: http://xpdfreader.com +% +% SVG output uses Matlab's built-in SVG export if available, or otherwise the +% fig2svg (https://github.com/kupiqu/fig2svg) or plot2svg +% (https://github.com/jschwizer99/plot2svg) utilities, if available. +% Note: cropping/padding are not supported in export_fig's SVG and EMF output. +% +% Inputs: +% filename - string containing the name (optionally including full or +% relative path) of the file the figure is to be saved as. If +% a path is not specified, the figure is saved in the current +% directory. If no name and no output arguments are specified, +% the default name, 'export_fig_out', is used. If neither a +% file extension nor a format are specified, a ".png" is added +% and the figure saved in that format. +% - - string(s) containing the output file extension(s). Options: +% '-pdf', '-eps', 'emf', '-svg', '-png', '-tif', '-jpg' and '-bmp'. +% Multiple formats can be specified, without restriction. +% For example: export_fig('-jpg', '-pdf', '-png', ...) +% Note: '-tif','-tiff' are equivalent, and so are '-jpg','-jpeg'. +% -transparent - option indicating that the figure background is to be made +% transparent (PNG,PDF,TIF,EPS,EMF formats only). Implies -noinvert. +% -nocrop - option indicating that empty margins should not be cropped. +% -c[,,,] - option indicating crop amounts. Must be +% a 4-element vector of numeric values: [top,right,bottom,left] +% where NaN/Inf indicates auto-cropping, 0 means no cropping, any +% other value means cropping in pixel amounts. e.g. '-c7,15,0,NaN' +% Note: this option is not supported by SVG and EMF formats. +% -p - option to pad a border of width val to exported files, where +% val is either a relative size with respect to cropped image +% size (i.e. p=0.01 adds a 1% border). For EPS & PDF formats, +% val can also be integer in units of 1/72" points (abs(val)>1). +% val can be positive (padding) or negative (extra cropping). +% If used, the -nocrop flag will be ignored, i.e. the image will +% always be cropped and then padded. Default: 0 (i.e. no padding). +% Note: this option is not supported by SVG and EMF formats. +% -m - option val indicates the factor to magnify the figure dimensions +% when generating bitmap outputs (does not affect vector formats). +% Default: '-m1' (i.e. val=1). Note: val~=1 slows down export_fig. +% -r - option val indicates the resolution (in pixels per inch) to +% export bitmap and vector outputs, without changing dimensions of +% the on-screen figure. Default: '-r864' (for vector output only). +% Note: -m option overides -r option for bitmap exports only. +% -native - option indicating that the output resolution (when outputting +% a bitmap format) should be such that the vertical resolution +% of the first suitable image found in the figure is at the +% native resolution of that image. To specify a particular +% image to use, give it the tag 'export_fig_native'. +% Notes: This overrides any value set with the -m and -r options. +% It also assumes that the image is displayed front-to-parallel +% with the screen. The output resolution is approximate and +% should not be relied upon. Anti-aliasing can have adverse +% effects on image quality (disable with the -a1 option). +% -a1, -a2, -a3, -a4 - option indicating the amount of anti-aliasing (AA) to +% use for bitmap outputs, when GraphicsSmoothing is not available. +% '-a1'=no AA; '-a4'=max. Default: 3 for HG1, 1 for HG2. +% - - option to force a particular renderer (painters, opengl or +% [in R2014a or older] zbuffer). Default value: opengl for bitmap +% formats or figures with patches and/or transparent annotations; +% painters for vector formats without patches/transparencies. +% - - option indicating which colorspace color figures should +% be saved in: RGB (default), CMYK or gray. Usage example: '-gray'. +% Note: CMYK is only supported in PDF, EPS and TIF formats. +% -q - option to vary bitmap image quality (PDF, EPS, JPG formats only). +% A larger val, in the range 0-100, produces higher quality and +% lower compression. val > 100 results in lossless compression. +% Default: '-q95' for JPG, ghostscript prepress default for PDF,EPS. +% Note: lossless compression can sometimes give a smaller file size +% than the default lossy compression, depending on the image type. +% -append - option indicating that if the file already exists the figure is to +% be appended as a new page, instead of being overwritten (default). +% PDF, TIF & GIF output formats only (multi-image GIF = animated). +% -bookmark - option to indicate that a bookmark with the name of the +% figure is to be created in the output file (PDF format only). +% -clipboard - option to save output as an image on the system clipboard. +% -clipboard<:format> - copies to clipboard in the specified format: +% image (default), bitmap, emf, or pdf. +% Notes: Only -clipboard (or -clipboard:image, which is the same) +% applies export_fig parameters such as cropping, padding etc. +% Only the emf format supports -transparent background +% -clipboard:image create a bitmap image using export_fig processing +% -clipboard:bitmap create a bitmap image as-is (no auto-cropping etc.) +% -clipboard:emf is vector format without auto-cropping; Windows-only +% -clipboard:pdf is vector format without cropping; not universally supported +% -d - option to indicate a ghostscript setting. For example, +% -dMaxBitmap=0 or -dNoOutputFonts (Ghostscript 9.15+). +% -depsc - option to use EPS level-3 rather than the default level-2 print +% device. This solves some bugs with Matlab's default -depsc2 device +% such as discolored subplot lines on images (vector formats only). +% -update - option to download and install the latest version of export_fig +% -version - return the current export_fig version, without any figure export +% -nofontswap - option to avoid font swapping. Font swapping is automatically +% done in vector formats (only): 11 standard Matlab fonts are +% replaced by the original figure fonts. This option prevents this. +% -font_space - option to set a spacer character for font-names that +% contain spaces, used by EPS/PDF. Default: '' +% -linecaps - option to create rounded line-caps (vector formats only). +% -noinvert - option to avoid setting figure's InvertHardcopy property to +% 'off' during output (this solves some problems of empty outputs). +% -preserve_size - option to preserve the figure's PaperSize property in output +% file (PDF/EPS formats only; default is to not preserve it). +% -options - format-specific parameters as defined in Matlab's +% documentation of the imwrite function, contained in a struct under +% the format name. For example to specify the JPG Comment parameter, +% pass a struct such as this: options.JPG.Comment='abc'. Similarly, +% options.PNG.BitDepth=4. Only used by PNG,TIF,JPG,GIF output formats. +% Options can also be specified as a cell array of name-value pairs, +% e.g. {'BitDepth',4, 'Author','Yair'} - these options will be used +% by all supported output formats of the export_fig command. +% -silent - option to avoid various warning and informational messages, such +% as version update checks, transparency or renderer issues, etc. +% -regexprep - replaces all occurances of (a regular expression +% string or array of strings; case-sensitive), with the corresponding +% string(s), in EPS/PDF files (only). See regexp function's doc. +% Warning: invalid replacement can make your EPS/PDF file unreadable! +% -toolbar - adds an interactive export button to the figure's toolbar +% -menubar - adds an interactive export menu to the figure's menubar +% handle - handle of the figure, axes or uipanels (can be an array of handles +% but all the objects must be in the same figure) to be exported. +% Default: gcf (handle of current figure). +% figName - name (title) of the figure to export (e.g. 'Figure 1' or 'My fig'). +% Overriden by handle (if specified); Default: current figure +% +% Outputs: +% imageData - MxNxC uint8 image array of the exported image. +% alpha - MxN single array of alphamatte values in the range [0,1], +% for the case when the background is transparent. +% +% Some helpful examples and tips can be found at: +% https://github.com/altmany/export_fig +% +% See also PRINT, SAVEAS, ScreenCapture (on the Matlab File Exchange) + +%{ +% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015- + +% The idea of using ghostscript is inspired by Peder Axensten's SAVEFIG +% (fex id: 10889) which is itself inspired by EPS2PDF (fex id: 5782). +% The idea for using pdftops came from the MATLAB newsgroup (id: 168171). +% The idea of editing the EPS file to change line styles comes from Jiro +% Doke's FIXPSLINESTYLE (fex id: 17928). +% The idea of changing dash length with line width came from comments on +% fex id: 5743, but the implementation is mine :) +% The idea of anti-aliasing bitmaps came from Anders Brun's MYAA (fex id: +% 20979). +% The idea of appending figures in pdfs came from Matt C in comments on the +% FEX (id: 23629) + +% Thanks to Roland Martin for pointing out the colour MATLAB +% bug/feature with colorbar axes and transparent backgrounds. +% Thanks also to Andrew Matthews for describing a bug to do with the figure +% size changing in -nodisplay mode. I couldn't reproduce it, but included a +% fix anyway. +% Thanks to Tammy Threadgill for reporting a bug where an axes is not +% isolated from gui objects. +%} +%{ +% 23/02/12: Ensure that axes limits don't change during printing +% 14/03/12: Fix bug in fixing the axes limits (thanks to Tobias Lamour for reporting it). +% 02/05/12: Incorporate patch of Petr Nechaev (many thanks), enabling bookmarking of figures in pdf files. +% 09/05/12: Incorporate patch of Arcelia Arrieta (many thanks), to keep tick marks fixed. +% 12/12/12: Add support for isolating uipanels. Thanks to michael for suggesting it. +% 25/09/13: Add support for changing resolution in vector formats. Thanks to Jan Jaap Meijer for suggesting it. +% 07/05/14: Add support for '~' at start of path. Thanks to Sally Warner for suggesting it. +% 24/02/15: Fix Matlab R2014b bug (issue #34): plot markers are not displayed when ZLimMode='manual' +% 25/02/15: Fix issue #4 (using HG2 on R2014a and earlier) +% 25/02/15: Fix issue #21 (bold TeX axes labels/titles in R2014b) +% 26/02/15: If temp dir is not writable, use the user-specified folder for temporary EPS/PDF files (Javier Paredes) +% 27/02/15: Modified repository URL from github.com/ojwoodford to /altmany; Indented main function; Added top-level try-catch block to display useful workarounds +% 28/02/15: Enable users to specify optional ghostscript options (issue #36) +% 06/03/15: Improved image padding & cropping thanks to Oscar Hartogensis +% 26/03/15: Fixed issue #49 (bug with transparent grayscale images); fixed out-of-memory issue +% 26/03/15: Fixed issue #42: non-normalized annotations on HG1 +% 26/03/15: Fixed issue #46: Ghostscript crash if figure units <> pixels +% 27/03/15: Fixed issue #39: bad export of transparent annotations/patches +% 28/03/15: Fixed issue #50: error on some Matlab versions with the fix for issue #42 +% 29/03/15: Fixed issue #33: bugs in Matlab's print() function with -cmyk +% 29/03/15: Improved processing of input args (accept space between param name & value, related to issue #51) +% 30/03/15: When exporting *.fig files, then saveas *.fig if figure is open, otherwise export the specified fig file +% 30/03/15: Fixed edge case bug introduced yesterday (commit #ae1755bd2e11dc4e99b95a7681f6e211b3fa9358) +% 09/04/15: Consolidated header comment sections; initialize output vars only if requested (nargout>0) +% 14/04/15: Workaround for issue #45: lines in image subplots are exported in invalid color +% 15/04/15: Fixed edge-case in parsing input parameters; fixed help section to show the -depsc option (issue #45) +% 21/04/15: Bug fix: Ghostscript croaks on % chars in output PDF file (reported by Sven on FEX page, 15-Jul-2014) +% 22/04/15: Bug fix: Pdftops croaks on relative paths (reported by Tintin Milou on FEX page, 19-Jan-2015) +% 04/05/15: Merged fix #63 (Kevin Mattheus Moerman): prevent tick-label changes during export +% 07/05/15: Partial fix for issue #65: PDF export used painters rather than opengl renderer (thanks Nguyenr) +% 08/05/15: Fixed issue #65: bad PDF append since commit #e9f3cdf 21/04/15 (thanks Robert Nguyen) +% 12/05/15: Fixed issue #67: exponent labels cropped in export, since fix #63 (04/05/15) +% 28/05/15: Fixed issue #69: set non-bold label font only if the string contains symbols (\beta etc.), followup to issue #21 +% 29/05/15: Added informative error message in case user requested SVG output (issue #72) +% 09/06/15: Fixed issue #58: -transparent removed anti-aliasing when exporting to PNG +% 19/06/15: Added -update option to download and install the latest version of export_fig +% 07/07/15: Added -nofontswap option to avoid font-swapping in EPS/PDF +% 16/07/15: Fixed problem with anti-aliasing on old Matlab releases +% 11/09/15: Fixed issue #103: magnification must never become negative; also fixed reported error msg in parsing input params +% 26/09/15: Alert if trying to export transparent patches/areas to non-PNG outputs (issue #108) +% 04/10/15: Do not suggest workarounds for certain errors that have already been handled previously +% 01/11/15: Fixed issue #112: use same renderer in print2eps as export_fig (thanks to Jesús Pestana Puerta) +% 10/11/15: Custom GS installation webpage for MacOS. Thanks to Andy Hueni via FEX +% 19/11/15: Fixed clipboard export in R2015b (thanks to Dan K via FEX) +% 21/02/16: Added -c option for indicating specific crop amounts (idea by Cedric Noordam on FEX) +% 08/05/16: Added message about possible error reason when groot.Units~=pixels (issue #149) +% 17/05/16: Fixed case of image YData containing more than 2 elements (issue #151) +% 08/08/16: Enabled exporting transparency to TIF, in addition to PNG/PDF (issue #168) +% 11/12/16: Added alert in case of error creating output PDF/EPS file (issue #179) +% 13/12/16: Minor fix to the commit for issue #179 from 2 days ago +% 22/03/17: Fixed issue #187: only set manual ticks when no exponent is present +% 09/04/17: Added -linecaps option (idea by Baron Finer, issue #192) +% 15/09/17: Fixed issue #205: incorrect tick-labels when Ticks number don't match the TickLabels number +% 15/09/17: Fixed issue #210: initialize alpha map to ones instead of zeros when -transparent is not used +% 18/09/17: Added -font_space option to replace font-name spaces in EPS/PDF (workaround for issue #194) +% 18/09/17: Added -noinvert option to solve some export problems with some graphic cards (workaround for issue #197) +% 08/11/17: Fixed issue #220: axes exponent is removed in HG1 when TickMode is 'manual' (internal Matlab bug) +% 08/11/17: Fixed issue #221: alert if the requested folder does not exist +% 19/11/17: Workaround for issue #207: alert when trying to use transparent bgcolor with -opengl +% 29/11/17: Workaround for issue #206: warn if exporting PDF/EPS for a figure that contains an image +% 11/12/17: Fixed issue #230: use OpenGL renderer when exported image contains transparency (also see issue #206) +% 30/01/18: Updated SVG message to point to https://github.com/kupiqu/plot2svg and display user-selected filename if available +% 27/02/18: Fixed issue #236: axes exponent cropped from output if on right-hand axes +% 29/05/18: Fixed issue #245: process "string" inputs just like 'char' inputs +% 13/08/18: Fixed issue #249: correct black axes color to off-black to avoid extra cropping with -transparent +% 27/08/18: Added a possible file-open reason in EPS/PDF write-error message (suggested by "craq" on FEX page) +% 22/09/18: Xpdf website changed to xpdfreader.com +% 23/09/18: Fixed issue #243: only set non-bold font (workaround for issue #69) in R2015b or earlier; warn if changing font +% 23/09/18: Workaround for issue #241: don't use -r864 in EPS/PDF outputs when -native is requested (solves black lines problem) +% 18/11/18: Issue #261: Added informative alert when trying to export a uifigure (which is not currently supported) +% 13/12/18: Issue #261: Fixed last commit for cases of specifying axes/panel handle as input, rather than a figure handle +% 13/01/19: Issue #72: Added basic SVG output support +% 04/02/19: Workaround for issues #207 and #267: -transparent implies -noinvert +% 08/03/19: Issue #269: Added ability to specify format-specific options for PNG,TIF,JPG outputs; fixed help section +% 21/03/19: Fixed the workaround for issues #207 and #267 from 4/2/19 (-transparent now does *NOT* imply -noinvert; -transparent output should now be ok in all formats) +% 12/06/19: Issue #277: Enabled preservation of figure's PaperSize in output PDF/EPS file +% 06/08/19: Remove warning message about obsolete JavaFrame in R2019b +% 30/10/19: Fixed issue #261: added support for exporting uifigures and uiaxes (thanks to idea by @MarvinILA) +% 12/12/19: Added warning in case user requested anti-aliased output on an aliased HG2 figure (issue #292) +% 15/12/19: Added promo message +% 08/01/20: (3.00) Added check for newer version online (initialized to version 3.00) +% 15/01/20: (3.01) Clarified/fixed error messages; Added error IDs; easier -update; various other small fixes +% 20/01/20: (3.02) Attempted fix for issue #285 (unsupported patch transparency in some Ghostscript versions); Improved suggested fixes message upon error +% 03/03/20: (3.03) Suggest to upload problematic EPS file in case of a Ghostscript error in eps2pdf (& don't delete this file) +% 22/03/20: (3.04) Workaround for issue #15; Alert if ghostscript file not found on Matlab path +% 10/05/20: (3.05) Fix the generated SVG file, based on Cris Luengo's SVG_FIX_VIEWBOX; Don't generate PNG when only SVG is requested +% 02/07/20: (3.06) Significantly improved performance (speed) and fidelity of bitmap images; Return alpha matrix for bitmap images; Fixed issue #302 (-update bug); Added EMF output; Added -clipboard formats (image,bitmap,emf,pdf); Added hints for exportgraphics/copygraphics usage in certain use-cases; Added description of new version features in the update message; Fixed issue #306 (yyaxis cropping); Fixed EPS/PDF auto-cropping with -transparent +% 06/07/20: (3.07) Fixed issue #307 (bug in padding of bitmap images); Fixed axes transparency in -clipboard:emf with -transparent +% 07/07/20: (3.08) Fixed issue #308 (bug in R2019a and earlier) +% 18/07/20: (3.09) Fixed issue #310 (bug with tiny image on HG1); Fixed title cropping bug +% 23/07/20: (3.10) Fixed issues #313,314 (figure position changes if units ~= pixels); Display multiple versions change-log, if relevant; Fixed issue #312 (PNG: only use alpha channel if -transparent was requested) +% 30/07/20: (3.11) Fixed issue #317 (bug when exporting figure with non-pixels units); Potential solve also of issue #303 (size change upon export) +% 14/08/20: (3.12) Fixed some exportgraphics/copygraphics compatibility messages; Added -silent option to suppress non-critical messages; Reduced promo message display rate to once a week; Added progress messages during export_fig('-update') +% 07/10/20: (3.13) Added version info and change-log links to update message (issue #322); Added -version option to return the current export_fig version; Avoid JavaFrame warning message; Improved exportgraphics/copygraphics infomercial message inc. support of upcoming Matlab R2021a +% 10/12/20: (3.14) Enabled user-specified regexp replacements in generated EPS/PDF files (issue #324) +% 01/07/21: (3.15) Added informative message in case of setopacityalpha error (issue #285) +% 26/08/21: (3.16) Fixed problem of white elements appearing transparent (issue #330); clarified some error messages +% 27/09/21: (3.17) Made Matlab's builtin export the default for SVG, rather than fig2svg/plot2svg (issue #316); updated transparency error message (issues #285, #343); reduced promo message frequency +% 03/10/21: (3.18) Fixed warning about invalid escaped character when the output folder does not exist (issue #345) +% 25/10/21: (3.19) Fixed print error when exporting a specific subplot (issue #347); avoid duplicate error messages +% 11/12/21: (3.20) Added GIF support, including animated & transparent-background; accept format options as cell-array, not just nested struct +% 20/12/21: (3.21) Speedups; fixed exporting non-current figure (hopefully fixes issue #318); fixed warning when appending to animated GIF +% 02/03/22: (3.22) Fixed small potential memory leak during screen-capture; expanded exportgraphics message for vector exports; fixed rotated tick labels on R2021a+ +% 02/03/22: (3.23) Added -toolbar and -menubar options to add figure toolbar/menubar items for interactive figure export (issue #73); fixed edge-case bug with GIF export +% 14/03/22: (3.24) Added support for specifying figure name in addition to handle; added warning when trying to export TIF/JPG/BMP with transparency; use current figure as default handle even when its HandleVisibility is not 'on' +% 16/03/22: (3.25) Fixed occasional empty files due to excessive cropping (issues #318, #350, #351) +% 01/05/22: (3.26) Added -transparency option for TIFF files +% 15/05/22: (3.27) Fixed EPS bounding box (issue #356) +%} + + if nargout + [imageData, alpha] = deal([]); + end + displaySuggestedWorkarounds = true; + + % Ensure the figure is rendered correctly _now_ so that properties like axes limits are up-to-date + drawnow; + pause(0.05); % this solves timing issues with Java Swing's EDT (http://undocumentedmatlab.com/blog/solving-a-matlab-hang-problem) + + % Display promo (just once every 10 days!) + persistent promo_time + if isempty(promo_time) + try promo_time = getpref('export_fig','promo_time'); catch, promo_time=-inf; end + end + if abs(now-promo_time) > 10 && ~isdeployed + programsCrossCheck; + msg = char('Gps!qspgfttjpobm!Nbumbc!bttjtubodf-!qmfbtf!dpoubdu!=%?'-1); + url = char('iuuqt;00VoepdvnfoufeNbumbc/dpn0dpotvmujoh'-1); + displayPromoMsg(msg, url); + promo_time = now; + setpref('export_fig','promo_time',now) + end + + % Use the current figure as the default figure handle + % temporarily set ShowHiddenHandles='on' to access figure with HandleVisibility='off' + try oldValue = get(0,'ShowHiddenHandles'); set(0,'ShowHiddenHandles','on'); catch, end + fig = get(0, 'CurrentFigure'); + try set(0,'ShowHiddenHandles',oldValue); catch, end + + % Parse the input arguments + argNames = {}; + for idx = nargin:-1:1, argNames{idx} = inputname(idx); end + [fig, options] = parse_args(nargout, fig, argNames, varargin{:}); + + % Check for newer version and exportgraphics/copygraphics compatibility + currentVersion = 3.27; + if options.version % export_fig's version requested - return it and bail out + imageData = currentVersion; + return + end + if ~options.silent + % Check for newer version (not too often) + checkForNewerVersion(currentVersion); % this breaks in version 3.05- due to regexp limitation in checkForNewerVersion() + + % Hint to users to use exportgraphics/copygraphics in certain cases + alertForExportOrCopygraphics(options); + %return + end + + % Ensure that we have a figure handle + if isequal(fig,-1) + return % silent bail-out + elseif isempty(fig) + error('export_fig:NoFigure','No figure found'); + else + oldWarn = warning('off','MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame'); + warning off MATLAB:ui:javaframe:PropertyToBeRemoved + hFig = handle(ancestor(fig,'figure')); + try jf = get(hFig,'JavaFrame_I'); catch, try jf = get(hFig,'JavaFrame'); catch, jf=1; end, end %#ok + warning(oldWarn); + if isempty(jf) % this is a uifigure + %error('export_fig:uifigures','Figures created using the uifigure command or App Designer are not supported by export_fig. See %s for details.', hyperlink('https://github.com/altmany/export_fig/issues/261','issue #261')); + if numel(fig) > 1 + error('export_fig:uifigure:multipleHandles', 'export_fig only supports exporting a single uifigure handle at a time; array of handles is not currently supported.') + elseif ~any(strcmpi(fig.Type,{'figure','axes'})) + error('export_fig:uifigure:notFigureOrAxes', 'export_fig only supports exporting a uifigure or uiaxes handle; other handles of a uifigure are not currently supported.') + end + % fig is either a uifigure or uiaxes handle + isUiaxes = strcmpi(fig.Type,'axes'); + if isUiaxes + % Label the specified axes so that we can find it in the legacy figure + oldUserData = fig.UserData; + tempStr = tempname; + fig.UserData = tempStr; + end + try + % Create an invisible legacy figure at the same position/size as the uifigure + hNewFig = figure('Units',hFig.Units, 'Position',hFig.Position, 'MenuBar','none', 'ToolBar','none', 'Visible','off'); + % Copy the uifigure contents onto the new invisible legacy figure + try + hChildren = allchild(hFig); %=uifig.Children; + copyobj(hChildren,hNewFig); + catch + if ~options.silent + warning('export_fig:uifigure:controls', 'Some uifigure controls cannot be exported by export_fig and will not appear in the generated output.'); + end + end + try fig.UserData = oldUserData; catch, end % restore axes UserData, if modified above + % Replace the uihandle in the input args with the legacy handle + if isUiaxes % uiaxes + % Locate the corresponding axes handle in the new legacy figure + hAxes = findall(hNewFig,'type','axes','UserData',tempStr); + if isempty(hAxes) % should never happen, check just in case + hNewHandle = hNewFig; % export the figure instead of the axes + else + hNewHandle = hAxes; % new axes handle found: use it instead of the uiaxes + end + else % uifigure + hNewHandle = hNewFig; + end + varargin(cellfun(@(c)isequal(c,fig),varargin)) = {hNewHandle}; + % Rerun export_fig on the legacy figure (with the replaced handle) + [imageData, alpha] = export_fig(varargin{:}); + % Delete the temp legacy figure and bail out + try delete(hNewFig); catch, end + return + catch err + % Clean up the temp legacy figure and report the error + try delete(hNewFig); catch, end + rethrow(err) + end + end + end + + % If toolbar button was requested, add it to the specified figure(s) + if options.toolbar + addToolbarButton(hFig, options); + end + + % If menubar menu was requested, add it to the specified figure(s) + if options.menubar + addMenubarMenu(hFig, options); + end + + % Isolate the subplot, if it is one + cls = all(ismember(get(fig, 'Type'), {'axes', 'uipanel'})); + if cls + % Given handles of one or more axes, so isolate them from the rest + fig = isolate_axes(fig); + else + % Check we have a figure + if ~isequal(get(fig, 'Type'), 'figure') + error('export_fig:BadHandle','Handle must be that of a figure, axes or uipanel'); + end + % Get the old InvertHardcopy mode + old_mode = get(fig, 'InvertHardcopy'); + end + % from this point onward, fig is assured to be a figure handle + + % Hack the font units where necessary (due to a font rendering bug in print?). + % This may not work perfectly in all cases. + % Also it can change the figure layout if reverted, so use a copy. + magnify = options.magnify * options.aa_factor; + if isbitmap(options) && magnify ~= 1 + fontu = findall(fig, 'FontUnits', 'normalized'); + if ~isempty(fontu) + % Some normalized font units found + if ~cls + fig = copyfig(fig); + set(fig, 'Visible', 'off'); + fontu = findall(fig, 'FontUnits', 'normalized'); + cls = true; + end + set(fontu, 'FontUnits', 'points'); + end + end + + try + % MATLAB "feature": axes limits and tick marks can change when printing + Hlims = findall(fig, 'Type', 'axes'); + if ~cls + % Record the old axes limit and tick modes + Xlims = make_cell(get(Hlims, 'XLimMode')); + Ylims = make_cell(get(Hlims, 'YLimMode')); + Zlims = make_cell(get(Hlims, 'ZLimMode')); + Xtick = make_cell(get(Hlims, 'XTickMode')); + Ytick = make_cell(get(Hlims, 'YTickMode')); + Ztick = make_cell(get(Hlims, 'ZTickMode')); + Xlabel = make_cell(get(Hlims, 'XTickLabelMode')); + Ylabel = make_cell(get(Hlims, 'YTickLabelMode')); + Zlabel = make_cell(get(Hlims, 'ZTickLabelMode')); + try % XTickLabelRotation etc. was added in R2021a + Xtkrot = make_cell(get(Hlims, 'XTickLabelRotationMode')); + Ytkrot = make_cell(get(Hlims, 'YTickLabelRotationMode')); + Ztkrot = make_cell(get(Hlims, 'ZTickLabelRotationMode')); + catch + end % only in R2021a+ + end + + % Set all axes limit and tick modes to manual, so the limits and ticks can't change + % Fix Matlab R2014b bug (issue #34): plot markers are not displayed when ZLimMode='manual' + set_manual_axes_modes(Hlims, 'X'); + set_manual_axes_modes(Hlims, 'Y'); + if ~using_hg2(fig) + set_manual_axes_modes(Hlims, 'Z'); + end + catch + % ignore - fix issue #4 (using HG2 on R2014a and earlier) + end + + % Fix issue #21 (bold TeX axes labels/titles in R2014b when exporting to EPS/PDF) + try + if using_hg2(fig) && isvector(options) + % Set the FontWeight of axes labels/titles to 'normal' + % Fix issue #69: set non-bold font only if the string contains symbols (\beta etc.) + % Issue #243: only set non-bold font (workaround for issue #69) in R2015b or earlier + try isPreR2016a = verLessThan('matlab','8.7'); catch, isPreR2016a = true; end + if isPreR2016a + texLabels = findall(fig, 'type','text', 'FontWeight','bold'); + symbolIdx = ~cellfun('isempty',strfind({texLabels.String},'\')); + if ~isempty(symbolIdx) + set(texLabels(symbolIdx), 'FontWeight','normal'); + if ~options.silent + warning('export_fig:BoldTexLabels', 'Bold labels with Tex symbols converted into non-bold in export_fig (fix for issue #69)'); + end + end + end + end + catch + % ignore + end + + % Fix issue #42: non-normalized annotations on HG1 (internal Matlab bug) + annotationHandles = []; + try + if ~using_hg2(fig) + annotationHandles = findall(fig,'Type','hggroup','-and','-property','Units','-and','-not','Units','norm'); + try % suggested by Jesús Pestana Puerta (jespestana) 30/9/2015 + originalUnits = get(annotationHandles,'Units'); + set(annotationHandles,'Units','norm'); + catch + end + end + catch + % should never happen, but ignore in any case - issue #50 + end + + % Fix issue #46: Ghostscript crash if figure units <> pixels + pos = get(fig, 'Position'); % Fix issues #313, #314 + oldFigUnits = get(fig,'Units'); + set(fig,'Units','pixels'); + pixelpos = get(fig, 'Position'); %=getpixelposition(fig); + + tcol = get(fig, 'Color'); + tcol_orig = tcol; + + % Set to print exactly what is there + if options.invert_hardcopy + try set(fig, 'InvertHardcopy', 'off'); catch, end % fail silently in uifigures + end + + % Set the renderer + switch options.renderer + case 1 + renderer = '-opengl'; + case 2 + renderer = '-zbuffer'; + case 3 + renderer = '-painters'; + otherwise + renderer = '-opengl'; % Default for bitmaps + end + + try + tmp_nam = ''; % initialize + + % Do the bitmap formats first + if isbitmap(options) + if abs(options.bb_padding) > 1 + displaySuggestedWorkarounds = false; + error('export_fig:padding','For bitmap output (png,jpg,tif,bmp) the padding value (-p) must be between -1 1.1 * options.magnify * pixelpos(4) %1.1 to avoid edge-cases + % Downscale the image + A = downsize(A, options.aa_factor); + alpha = downsize(alpha, options.aa_factor); + end + % Crop the margins based on the bgcolor, if requested + if options.crop + %[alpha, v] = crop_borders(alpha, 0, 1, options.crop_amounts); + %A = A(v(1):v(2),v(3):v(4),:); + [A, vA, vB] = crop_borders(A, tcol, options.bb_padding, options.crop_amounts); + if ~any(isnan(vB)) % positive padding + sz = size(A); % Fix issue #308 + B = repmat(uint8(zeros(1,1,size(alpha,3))),sz([1,2])); % Fix issue #307 %=zeros(sz([1,2]),'uint8'); + B(vB(1):vB(2), vB(3):vB(4), :) = alpha(vA(1):vA(2), vA(3):vA(4), :); % ADDED BY OH + alpha = B; + else % negative padding + alpha = alpha(vA(1):vA(2), vA(3):vA(4), :); + end + end + % Get the non-alpha image (presumably unneeded with Java-based screen-capture) + %{ + if isbitmap(options) + % Modify the intensity of the pixels' RGB values based on their alpha transparency + % TODO: not sure that we want this with Java screen-capture values! + alph = alpha(:,:,ones(1, size(A, 3))); + A = uint8(single(A) .* alph + 255 * (1 - alph)); + end + %} + % Revert the figure properties back to their original values + set(fig, 'Units',oldFigUnits, 'Position',pos, 'Color',tcol_orig); + % Check for greyscale images + if options.colourspace == 2 + % Convert to greyscale + A = rgb2grey(A); + else + % Return only one channel for greyscale + A = check_greyscale(A); + end + % Change alpha from [0:255] uint8 => [0:1] single from here onward: + alpha = single(alpha) / 255; + % Outputs + if options.im + imageData = A; + end + if options.alpha + imageData = A; + %alpha = ones(size(A, 1), size(A, 2), 'single'); %=all pixels opaque + end + % Save the images + if options.png + % Compute the resolution + res = options.magnify * get(0, 'ScreenPixelsPerInch') / 25.4e-3; + % Save the png + [format_options, bitDepth] = getFormatOptions(options, 'png'); %Issue #269 + pngOptions = {[options.name '.png'], 'ResolutionUnit','meter', 'XResolution',res, 'YResolution',res, format_options{:}}; %#ok + if options.transparent % Fix issue #312: only use alpha channel if -transparent was requested + pngOptions = [pngOptions 'Alpha',double(alpha)]; + end + if ~isempty(bitDepth) && bitDepth < 16 && size(A,3) == 3 + % BitDepth specification requires using a color-map + [img, map] = rgb2ind(A, 256); + imwrite(img, map, pngOptions{:}); + else + imwrite(A, pngOptions{:}); + end + end + if options.bmp + imwrite(A, [options.name '.bmp']); + end + if options.jpg + % Save jpeg with the specified quality + quality = options.quality; + if isempty(quality) + quality = 95; + end + format_options = getFormatOptions(options, 'jpg'); %Issue #269 + if quality > 100 + imwrite(A, [options.name '.jpg'], 'Mode','lossless', format_options{:}); + else + imwrite(A, [options.name '.jpg'], 'Quality',quality, format_options{:}); + end + end + if options.tif + % Save tif images in cmyk if wanted (and possible) + if options.colourspace == 1 && size(A, 3) == 3 + img = double(255 - A); + K = min(img, [], 3); + K_ = 255 ./ max(255 - K, 1); + C = (img(:,:,1) - K) .* K_; + M = (img(:,:,2) - K) .* K_; + Y = (img(:,:,3) - K) .* K_; + img = uint8(cat(3, C, M, Y, K)); + clear C M Y K K_ + else + img = A; + end + resolution = options.magnify * get(0,'ScreenPixelsPerInch'); + filename = [options.name '.tif']; + if options.transparent && any(alpha(:) < 1) && any(isBgColor(:)) + % Need to use low-level Tiff library since imwrite/writetif doesn't support alpha channel + alpha8 = uint8(alpha*255); + tag = ['Matlab ' version ' export_fig v' num2str(currentVersion)]; + mode = 'w'; if options.append, mode = 'a'; end + t = Tiff(filename,mode); %R2009a or newer + %See https://www.awaresystems.be/imaging/tiff/tifftags/baseline.html + t.setTag('ImageLength', size(img,1)); + t.setTag('ImageWidth', size(img,2)); + t.setTag('Photometric', Tiff.Photometric.RGB); + t.setTag('Compression', Tiff.Compression.Deflate); + t.setTag('PlanarConfiguration', Tiff.PlanarConfiguration.Chunky); + t.setTag('ExtraSamples', Tiff.ExtraSamples.AssociatedAlpha); + t.setTag('ResolutionUnit', Tiff.ResolutionUnit.Inch); + t.setTag('BitsPerSample', 8); + t.setTag('SamplesPerPixel',size(img,3)+1); %+1=alpha channel + t.setTag('XResolution', resolution); + t.setTag('YResolution', resolution); + t.setTag('Software', tag); + t.write(cat(3,img,alpha8)); + t.close; + else + % Use the builtin imwrite/writetif function + append_mode = {'overwrite', 'append'}; + mode = append_mode{options.append+1}; + format_options = getFormatOptions(options, 'tif'); %Issue #269 + imwrite(img, filename, 'Resolution',resolution, 'WriteMode',mode, format_options{:}); + end + end + if options.gif + % TODO - merge contents with im2gif.m + % Convert to color-map image required by GIF specification + [img, map] = rgb2ind(A, 256); + % Handle the case of trying to append to non-existing GIF file + % (imwrite() croaks when asked to append to a non-existing file) + filename = [options.name '.gif']; + options.append = options.append && existFile(filename); + % Set the default GIF options for imwrite() + append_mode = {'overwrite', 'append'}; + writeMode = append_mode{options.append+1}; + gifOptions = {'WriteMode',writeMode}; + if options.transparent % only use alpha channel if -transparent was requested + exp = 256 .^ (0:2); + mapVals = sum(round(map*255).*exp,2); + tcolVal = sum(round(double(tcol)).*exp); + alphaIdx = find(mapVals==tcolVal,1); + if isempty(alphaIdx) || alphaIdx <= 0, alphaIdx = 1; end + % GIF color index of uint8/logical images starts at 0, not 1 + if ~isfloat(img), alphaIdx = alphaIdx - 1; end + gifOptions = [gifOptions, 'TransparentColor',alphaIdx, ... + 'DisposalMethod','restoreBG']; + else + alphaIdx = 1; + end + if ~options.append + % LoopCount and BackgroundColor can only be specified in the + % 1st GIF frame (not in append mode) + % Set default LoopCount=65535 to enable looping within MS Office + gifOptions = [gifOptions, 'LoopCount',65535, 'BackgroundColor',alphaIdx]; + end + % Set GIF-specific options specified by the user (if any) + format_options = getFormatOptions(options, 'gif'); + gifOptions = [gifOptions, format_options{:}]; + % Save the gif file + imwrite(img, map, filename, gifOptions{:}); + end + end + + % Now do the vector formats which are based on EPS + if isvector(options) + hImages = findall(fig,'type','image'); + % Set the default renderer to painters + if ~options.renderer + % Handle transparent patches + hasTransparency = ~isempty(findall(fig,'-property','FaceAlpha','-and','-not','FaceAlpha',1)); + if hasTransparency + % Alert if trying to export transparent patches/areas to non-supported outputs (issue #108) + % http://www.mathworks.com/matlabcentral/answers/265265-can-export_fig-or-else-draw-vector-graphics-with-transparent-surfaces + % TODO - use transparency when exporting to PDF by not passing via print2eps + msg = 'export_fig currently supports transparent patches/areas only in PNG output. '; + if options.pdf && ~options.silent + warning('export_fig:transparency', '%s\nTo export transparent patches/areas to PDF, use the print command:\n print(gcf, ''-dpdf'', ''%s.pdf'');', msg, options.name); + elseif ~options.png && ~options.tif && ~options.silent % issue #168 + warning('export_fig:transparency', '%s\nTo export the transparency correctly, try using the ScreenCapture utility on the Matlab File Exchange: http://bit.ly/1QFrBip', msg); + end + elseif ~isempty(hImages) + % Fix for issue #230: use OpenGL renderer when exported image contains transparency + for idx = 1 : numel(hImages) + cdata = get(hImages(idx),'CData'); + if any(isnan(cdata(:))) + hasTransparency = true; + break + end + end + end + hasPatches = ~isempty(findall(fig,'type','patch')); + if hasTransparency || hasPatches + % This is *MUCH* slower, but more accurate for patches and transparent annotations (issue #39) + renderer = '-opengl'; + else + renderer = '-painters'; + end + end + options.rendererStr = renderer; % fix for issue #112 + % Generate some filenames + tmp_nam = [tempname '.eps']; + try + % Ensure that the temp dir is writable (Javier Paredes 30/1/15) + fid = fopen(tmp_nam,'w'); + fwrite(fid,1); + fclose(fid); + delete(tmp_nam); + pdf_nam_tmp = [tempname '.pdf']; + catch + % Temp dir is not writable, so use the user-specified folder + [dummy,fname,fext] = fileparts(tmp_nam); %#ok + fpath = fileparts(options.name); + tmp_nam = fullfile(fpath,[fname fext]); + pdf_nam_tmp = fullfile(fpath,[fname '.pdf']); + end + if options.pdf + pdf_nam = [options.name '.pdf']; + try copyfile(pdf_nam, pdf_nam_tmp, 'f'); catch, end % fix for issue #65 + else + pdf_nam = pdf_nam_tmp; + end + % Generate the options for print + printArgs = {renderer}; + if ~isempty(options.resolution) % issue #241 + printArgs{end+1} = sprintf('-r%d', options.resolution); + end + if options.colourspace == 1 % CMYK + % Issue #33: due to internal bugs in Matlab's print() function, we can't use its -cmyk option + %printArgs{end+1} = '-cmyk'; + end + if ~options.crop + % Issue #56: due to internal bugs in Matlab's print() function, we can't use its internal cropping mechanism, + % therefore we always use '-loose' (in print2eps.m) and do our own cropping (with crop_borders.m) + %printArgs{end+1} = '-loose'; + end + if any(strcmpi(varargin,'-depsc')) + % Issue #45: lines in image subplots are exported in invalid color. + % The workaround is to use the -depsc parameter instead of the default -depsc2 + printArgs{end+1} = '-depsc'; + end + % Print to EPS file + try + % Remove background if requested (issue #207) + originalBgColor = get(fig, 'Color'); + [hXs, hXrs, hYs, hYrs, hZs, hZrs] = deal([]); + if options.transparent %&& ~isequal(get(fig, 'Color'), 'none') + if options.renderer == 1 && ~options.silent % OpenGL + warning('export_fig:openglTransparentBG', '-opengl sometimes fails to produce transparent backgrounds; in such a case, try to use -painters instead'); + end + + % Fix for issue #207, #267 (corrected) + set(fig,'Color','none'); + + % Correct black axes color to off-black (issue #249) + hAxes = findall(fig, 'Type','axes'); + [hXs,hXrs] = fixBlackAxle(hAxes, 'XColor'); + [hYs,hYrs] = fixBlackAxle(hAxes, 'YColor'); + [hZs,hZrs] = fixBlackAxle(hAxes, 'ZColor'); + + % Correct black titles to off-black + % https://www.mathworks.com/matlabcentral/answers/567027-matlab-export_fig-crops-title + try + hTitle = get(hAxes, 'Title'); + for idx = numel(hTitle) : -1 : 1 + color = get(hTitle,'Color'); + if isequal(color,[0,0,0]) || isequal(color,'k') + set(hTitle(idx), 'Color', [0,0,0.01]); %off-black + else + hTitle(idx) = []; % remove from list + end + end + catch + hTitle = []; + end + end + % Generate an eps + print2eps(tmp_nam, fig, options, printArgs{:}); %winopen(tmp_nam) + % { + % Remove the background, if desired + if options.transparent %&& ~isequal(get(fig, 'Color'), 'none') + eps_remove_background(tmp_nam, 1 + using_hg2(fig)); + + % Revert the black axes colors + set(hXs, 'XColor', [0,0,0]); + set(hYs, 'YColor', [0,0,0]); + set(hZs, 'ZColor', [0,0,0]); + set(hXrs, 'Color', [0,0,0]); + set(hYrs, 'Color', [0,0,0]); + set(hZrs, 'Color', [0,0,0]); + set(hTitle,'Color',[0,0,0]); + end + %} + % Restore the figure's previous background color (if modified) + try set(fig,'Color',originalBgColor); drawnow; catch, end + % Fix colorspace to CMYK, if requested (workaround for issue #33) + if options.colourspace == 1 % CMYK + % Issue #33: due to internal bugs in Matlab's print() function, we can't use its -cmyk option + change_rgb_to_cmyk(tmp_nam); + end + % Add a bookmark to the PDF if desired + if options.bookmark + fig_nam = get(fig, 'Name'); + if isempty(fig_nam) && ~options.silent + warning('export_fig:EmptyBookmark', 'Bookmark requested for figure with no name. Bookmark will be empty.'); + end + add_bookmark(tmp_nam, fig_nam); + end + % Generate a pdf + eps2pdf(tmp_nam, pdf_nam_tmp, 1, options.append, options.colourspace==2, options.quality, options.gs_options); + % Ghostscript croaks on % chars in the output PDF file, so use tempname and then rename the file + try + % Rename the file (except if it is already the same) + % Abbie K's comment on the commit for issue #179 (#commitcomment-20173476) + if ~isequal(pdf_nam_tmp, pdf_nam) + movefile(pdf_nam_tmp, pdf_nam, 'f'); + end + catch + % Alert in case of error creating output PDF/EPS file (issue #179) + if existFile(pdf_nam_tmp) + fpath = fileparts(pdf_nam); + if ~isempty(fpath) && exist(fpath,'dir')==0 + errMsg = ['Could not create ' pdf_nam ' - folder "' fpath '" does not exist']; + else % output folder exists + errMsg = ['Could not create ' pdf_nam ' - perhaps you do not have write permissions, or the file is open in another application']; + end + error('export_fig:PDF:create',errMsg); + else + error('export_fig:NoEPS','Could not generate the intermediary EPS file.'); + end + end + catch ex + % Restore the figure's previous background color (in case it was not already restored) + try set(fig,'Color',originalBgColor); drawnow; catch, end + % Delete the temporary eps file - NOT! (Yair 3/3/2020) + %delete(tmp_nam); + % Rethrow the EPS/PDF-generation error + rethrow(ex); + end + % Delete the eps + delete(tmp_nam); + if options.eps || options.linecaps + try + % Generate an eps from the pdf + % since pdftops can't handle relative paths (e.g., '..\'), use a temp file + eps_nam_tmp = strrep(pdf_nam_tmp,'.pdf','.eps'); + pdf2eps(pdf_nam, eps_nam_tmp); + + % Issue #192: enable rounded line-caps + if options.linecaps + fstrm = read_write_entire_textfile(eps_nam_tmp); + fstrm = regexprep(fstrm, '[02] J', '1 J'); + read_write_entire_textfile(eps_nam_tmp, fstrm); + if options.pdf + eps2pdf(eps_nam_tmp, pdf_nam, 1, options.append, options.colourspace==2, options.quality, options.gs_options); + end + end + + if options.eps + movefile(eps_nam_tmp, [options.name '.eps'], 'f'); + else % if options.pdf + try delete(eps_nam_tmp); catch, end + end + catch ex + if ~options.pdf + % Delete the pdf + delete(pdf_nam); + end + try delete(eps_nam_tmp); catch, end + rethrow(ex); + end + if ~options.pdf + % Delete the pdf + delete(pdf_nam); + end + end + % Issue #206: warn if the figure contains an image + if ~isempty(hImages) && strcmpi(renderer,'-opengl') && ~options.silent % see addendum to issue #206 + warnMsg = ['exporting images to PDF/EPS may result in blurry images on some viewers. ' ... + 'If so, try to change viewer, or increase the image''s CData resolution, or use -opengl renderer, or export via the print function. ' ... + 'See ' hyperlink('https://github.com/altmany/export_fig/issues/206', 'issue #206') ' for details.']; + warning('export_fig:pdf_eps:blurry_image', warnMsg); + end + end + + % SVG format + if options.svg + filename = [options.name '.svg']; + % Adapted from Dan Joshea's https://github.com/djoshea/matlab-save-figure : + try %if ~verLessThan('matlab', '8.4') + % Try Matlab's built-in svg engine (from Batik Graphics2D for java) + set(fig,'Units','pixels'); % All data in the svg-file is saved in pixels + printArgs = {renderer}; + if ~isempty(options.resolution) + printArgs{end+1} = sprintf('-r%d', options.resolution); + end + try + print(fig, '-dsvg', printArgs{:}, filename); + catch + % built-in print() failed, try saveas() + % Note: saveas() currently just calls print(fig,filename,'-dsvg') + % so since print() failed, saveas() will probably also fail + saveas(fig, filename); + end + if ~options.silent + warning('export_fig:SVG:print', 'export_fig used Matlab''s built-in SVG output engine. Better results may be gotten via the fig2svg utility (https://github.com/kupiqu/fig2svg).'); + end + catch %else % built-in print()/saveas() failed - maybe an old Matlab release (no -dsvg) + % Try using the fig2svg/plot2svg utilities + try + try + fig2svg(filename, fig); %https://github.com/kupiqu/fig2svg + catch + plot2svg(filename, fig); %https://github.com/jschwizer99/plot2svg + if ~options.silent + warning('export_fig:SVG:plot2svg', 'export_fig used the plot2svg utility for SVG output. Better results may be gotten via the fig2svg utility (https://github.com/kupiqu/fig2svg).'); + end + end + catch err + filename = strrep(filename,'export_fig_out','filename'); + msg = ['SVG output is not supported for your figure: ' err.message '\n' ... + 'Try one of the following alternatives:\n' ... + ' 1. saveas(gcf,''' filename ''')\n' ... + ' 2. fig2svg utility: https://github.com/kupiqu/fig2svg\n' ... % Note: replaced defunct https://github.com/jschwizer99/plot2svg with up-to-date fork on https://github.com/kupiqu/fig2svg + ' 3. export_fig to EPS/PDF, then convert to SVG using non-Matlab tools\n']; + error('export_fig:SVG:error',msg); + end + end + % SVG output was successful if we reached this point + % Add warning about unsupported export_fig options with SVG output + if ~options.silent && (any(~isnan(options.crop_amounts)) || any(options.bb_padding)) + warning('export_fig:SVG:options', 'export_fig''s SVG output does not [currently] support cropping/padding.'); + end + + % Fix the generated SVG file, based on Cris Luengo's SVG_FIX_VIEWBOX: + % https://www.mathworks.com/matlabcentral/fileexchange/49617-svg_fix_viewbox-in_name-varargin + try + % Read SVG file + s = read_write_entire_textfile(filename); + % Fix fonts #1: 'SansSerif' doesn't work on my browser, the correct CSS is 'sans-serif' + s = regexprep(s,'font-family:SansSerif;|font-family:''SansSerif'';','font-family:''sans-serif'';'); + % Fix fonts #1: The document-wide default font is 'Dialog'. What is this anyway? + s = regexprep(s,'font-family:''Dialog'';','font-family:''sans-serif'';'); + % Replace 'width="xxx" height="yyy"' with 'width="100%" viewBox="0 0 xxx yyy"' + t = regexp(s,' 1e-6 + warning('export_fig:EMF:Magnify', 'export_fig -m option is ignored for EMF export.'); + end + if ~isequal(options.bb_padding,0) || ~isempty(options.quality) + warning('export_fig:EMF:Options', 'export_fig cropping, padding and quality options are ignored for EMF export.'); + end + if ~anythingChanged + warning('export_fig:EMF:print', 'For a figure without background transparency, export_fig uses Matlab''s built-in print(''-dmeta'') function without any extra processing, so try using it directly.'); + end + end + printArgs = {renderer}; + if ~isempty(options.resolution) + printArgs{end+1} = sprintf('-r%d', options.resolution); + end + filename = [options.name '.emf']; + print(fig, '-dmeta', printArgs{:}, filename); + catch err % built-in print() failed - maybe an old Matlab release (no -dsvg) + msg = ['EMF output is not supported: ' err.message '\n' ... + 'Try to use export_fig with other formats, such as PDF or EPS.\n']; + error('export_fig:EMF:error',msg); + end + end + + % Revert the figure or close it (if requested) + if cls || options.closeFig + % Close the created figure + close(fig); + else + % Reset the hardcopy mode + try set(fig, 'InvertHardcopy', old_mode); catch, end % fail silently in uifigures + % Reset the axes limit and tick modes + for a = 1:numel(Hlims) + try + set(Hlims(a), 'XLimMode', Xlims{a}, 'YLimMode', Ylims{a}, 'ZLimMode', Zlims{a},... + 'XTickMode', Xtick{a}, 'YTickMode', Ytick{a}, 'ZTickMode', Ztick{a},... + 'XTickLabelMode', Xlabel{a}, 'YTickLabelMode', Ylabel{a}, 'ZTickLabelMode', Zlabel{a}); + try % only in R2021a+ + set(Hlims(a), 'XTickLabelRotationMode', Xtkrot{a}, ... + 'YTickLabelRotationMode', Ytkrot{a}, ... + 'ZTickLabelRotationMode', Ztkrot{a}); + catch + % ignore - possibly R2020b or earlier + end + catch + % ignore - fix issue #4 (using HG2 on R2014a and earlier) + end + end + % Revert the tex-labels font weights + try set(texLabels, 'FontWeight','bold'); catch, end + % Revert annotation units + for handleIdx = 1 : numel(annotationHandles) + try + oldUnits = originalUnits{handleIdx}; + catch + oldUnits = originalUnits; + end + try set(annotationHandles(handleIdx),'Units',oldUnits); catch, end + end + % Revert figure properties in case they were changed + try set(fig, 'Units',oldFigUnits, 'Position',pos, 'Color',tcol_orig); catch, end + end + + % Output to clipboard (if requested) + if options.clipboard + % Use Java clipboard by default + if strcmpi(options.clipformat,'image') + % Save the image in the system clipboard + % credit: Jiro Doke's IMCLIPBOARD: http://www.mathworks.com/matlabcentral/fileexchange/28708-imclipboard + try + error(javachk('awt', 'export_fig -clipboard output')); + catch + if ~options.silent + warning('export_fig:clipboardJava', 'export_fig -clipboard output failed: requires Java to work'); + end + return + end + try + % Import necessary Java classes + import java.awt.Toolkit %#ok + import java.awt.image.BufferedImage %#ok + import java.awt.datatransfer.DataFlavor %#ok + + % Get System Clipboard object (java.awt.Toolkit) + cb = Toolkit.getDefaultToolkit.getSystemClipboard(); + + % Add java class (ImageSelection) to the path + if ~exist('ImageSelection', 'class') + javaaddpath(fileparts(which(mfilename)), '-end'); + end + + % Get image size + ht = size(imageData, 1); + wd = size(imageData, 2); + + % Convert to Blue-Green-Red format + try + imageData2 = imageData(:, :, [3 2 1]); + catch + % Probably gray-scaled image (2D, without the 3rd [RGB] dimension) + imageData2 = imageData(:, :, [1 1 1]); + end + + % Convert to 3xWxH format + imageData2 = permute(imageData2, [3, 2, 1]); + + % Append Alpha data (unused - transparency is not supported in clipboard copy) + alphaData2 = uint8(permute(255*alpha,[3,2,1])); %=255*ones(1,wd,ht,'uint8') + imageData2 = cat(1, imageData2, alphaData2); + + % Create image buffer + imBuffer = BufferedImage(wd, ht, BufferedImage.TYPE_INT_RGB); + imBuffer.setRGB(0, 0, wd, ht, typecast(imageData2(:), 'int32'), 0, wd); + + % Create ImageSelection object from the image buffer + imSelection = ImageSelection(imBuffer); + + % Set clipboard content to the image + cb.setContents(imSelection, []); + catch + if ~options.silent + warning('export_fig:clipboardFailed', 'export_fig -clipboard output failed: %s', lasterr); %#ok + end + end + else % use one of print()'s builtin clipboard formats + % Remove background if requested (EMF format only) + if options.transparent && strcmpi(options.clipformat,'meta') + % Set figure bgcolor to none + originalBgColor = get(fig, 'Color'); + set(fig,'Color','none'); + + % Set axes bgcolor to none + hAxes = findall(fig, 'Type','axes'); + originalAxColor = get(hAxes, 'Color'); + set(hAxes,'Color','none'); + + drawnow; %repaint before export + end + + % Call print() to create the clipboard output + clipformat = ['-d' options.clipformat]; + printArgs = {renderer}; + if ~isempty(options.resolution) + printArgs{end+1} = sprintf('-r%d', options.resolution); + end + print(fig, '-clipboard', clipformat, printArgs{:}); + + % Restore the original background color + try set(fig, 'Color',originalBgColor); catch, end + try set(hAxes, 'Color',originalAxColor); catch, end + drawnow; + end + end + + % Delete the output file if unchanged from the default name ('export_fig_out.png') + % and clipboard, toolbar, and/or menubar were requested + if options.clipboard || options.toolbar || options.menubar + if strcmpi(options.name,'export_fig_out') + try + fileInfo = dir('export_fig_out.png'); + if ~isempty(fileInfo) + timediff = now - fileInfo.datenum; + ONE_SEC = 1/24/60/60; + if timediff < ONE_SEC + delete('export_fig_out.png'); + end + end + catch + % never mind... + end + end + end + + % Don't output the data to console unless requested + if ~nargout + clear imageData alpha + end + catch err + % Revert figure properties in case they were changed + try set(fig,'Units',oldFigUnits, 'Position',pos, 'Color',tcol_orig); catch, end + % Display possible workarounds before the error message + if ~isempty(regexpi(err.message,'setopacityalpha')) %#ok + % Alert the user that transparency is not supported (issue #285) + try + [unused, msg] = ghostscript('-v'); %#ok + verStr = regexprep(msg, '.*hostscript ([\d.]+).*', '$1'); + if isempty(verStr) || any(verStr==' ') + verStr = ''; + else + verStr = [' (' verStr ')']; + end + catch + verStr = ''; + end + url = 'https://github.com/altmany/export_fig/issues/285#issuecomment-815008561'; + urlStr = hyperlink(url,'details'); + errMsg = sprintf('Transparancy is not supported by your export_fig (%s) and Ghostscript%s versions. \nInstall GS version 9.28 or earlier to use transparency (%s).', num2str(currentVersion), verStr, urlStr); + %fprintf(2,'%s\n',errMsg); + error('export_fig:setopacityalpha',errMsg) %#ok + elseif displaySuggestedWorkarounds && ~strcmpi(err.message,'export_fig error') + isNewerVersionAvailable = checkForNewerVersion(currentVersion); % alert if a newer version exists + if isempty(regexpi(err.message,'Ghostscript')) %#ok + fprintf(2, 'export_fig error. '); + end + fprintf(2, 'Please ensure:\n'); + fprintf(2, ' * that the function you used (%s.m) version %s is from the expected location\n', mfilename('fullpath'), num2str(currentVersion)); + paths = which(mfilename,'-all'); + if iscell(paths) && numel(paths) > 1 + fprintf(2, ' (you appear to have %s of export_fig installed)\n', hyperlink('matlab:which export_fig -all','multiple versions')); + end + if isNewerVersionAvailable + fprintf(2, ' * and that you are using the %s of export_fig (you are not: run %s to update it)\n', ... + hyperlink('https://github.com/altmany/export_fig/archive/master.zip','latest version'), ... + hyperlink('matlab:export_fig(''-update'')','export_fig(''-update'')')); + end + fprintf(2, ' * and that you did not made a mistake in export_fig''s %s\n', hyperlink('matlab:help export_fig','expected input arguments')); + if isvector(options) + if ismac + url = 'http://pages.uoregon.edu/koch'; + else + url = 'http://ghostscript.com'; + end + fpath = user_string('ghostscript'); + fprintf(2, ' * and that %s is properly installed in %s\n', ... + hyperlink(url,'ghostscript'), ... + hyperlink(['matlab:winopen(''' fileparts(fpath) ''')'], fpath)); + end + try + if options.eps + fpath = user_string('pdftops'); + fprintf(2, ' * and that %s is properly installed in %s\n', ... + hyperlink('http://xpdfreader.com/download.html','pdftops'), ... + hyperlink(['matlab:winopen(''' fileparts(fpath) ''')'], fpath)); + end + catch + % ignore - probably an error in parse_args + end + try + % Alert per issue #149 + if ~strncmpi(get(0,'Units'),'pixel',5) + fprintf(2, ' * or try to set groot''s Units property back to its default value of ''pixels'' (%s)\n', hyperlink('https://github.com/altmany/export_fig/issues/149','details')); + end + catch + % ignore - maybe an old MAtlab release + end + fprintf(2, '\nIf the problem persists, then please %s.\n', hyperlink('https://github.com/altmany/export_fig/issues','report a new issue')); + if existFile(tmp_nam) + fprintf(2, 'In your report, please upload the problematic EPS file: %s (you can then delete this file).\n', tmp_nam); + end + fprintf(2, '\n'); + end + rethrow(err) + end +end + +function options = default_options() + % Default options used by export_fig + options = struct(... + 'name', 'export_fig_out', ... + 'crop', true, ... + 'crop_amounts', nan(1,4), ... % auto-crop all 4 image sides + 'transparent', false, ... + 'renderer', 0, ... % 0: default, 1: OpenGL, 2: ZBuffer, 3: Painters + 'pdf', false, ... + 'eps', false, ... + 'emf', false, ... + 'svg', false, ... + 'png', false, ... + 'tif', false, ... + 'jpg', false, ... + 'bmp', false, ... + 'gif', false, ... + 'clipboard', false, ... + 'clipformat', 'image', ... + 'colourspace', 0, ... % 0: RGB/gray, 1: CMYK, 2: gray + 'append', false, ... + 'im', false, ... + 'alpha', false, ... + 'aa_factor', 0, ... + 'bb_padding', 0, ... + 'magnify', [], ... + 'resolution', [], ... + 'bookmark', false, ... + 'closeFig', false, ... + 'quality', [], ... + 'update', false, ... + 'version', false, ... + 'fontswap', true, ... + 'font_space', '', ... + 'linecaps', false, ... + 'invert_hardcopy', true, ... + 'format_options', struct, ... + 'preserve_size', false, ... + 'silent', false, ... + 'regexprep', [], ... + 'toolbar', false, ... + 'menubar', false, ... + 'gs_options', {{}}); +end + +function [fig, options] = parse_args(nout, fig, argNames, varargin) + % Parse the input arguments + + % Convert strings => chars + varargin = cellfun(@str2char,varargin,'un',false); + + % Set the defaults + native = false; % Set resolution to native of an image + defaultOptions = default_options(); + options = defaultOptions; + options.im = (nout == 1); % user requested imageData output + options.alpha = (nout == 2); % user requested alpha output + options.handleName = ''; % default handle name + + % Go through the other arguments + skipNext = 0; + for a = 1:nargin-3 % only process varargin, no other parse_args() arguments + if skipNext > 0 + skipNext = skipNext-1; + continue; + end + thisArg = varargin{a}; + if all(ishandle(thisArg)) + fig = thisArg; + options.handleName = argNames{a}; + elseif ischar(thisArg) && ~isempty(thisArg) + if thisArg(1) == '-' + switch lower(thisArg(2:end)) + case 'nocrop' + options.crop = false; + options.crop_amounts = [0,0,0,0]; + case {'trans', 'transparent'} + options.transparent = true; + case 'opengl' + options.renderer = 1; + case 'zbuffer' + options.renderer = 2; + case 'painters' + options.renderer = 3; + case 'pdf' + options.pdf = true; + case 'eps' + options.eps = true; + case {'emf','meta'} + options.emf = true; + case 'svg' + options.svg = true; + case 'png' + options.png = true; + case {'tif', 'tiff'} + options.tif = true; + case {'jpg', 'jpeg'} + options.jpg = true; + case 'bmp' + options.bmp = true; + case 'rgb' + options.colourspace = 0; + case 'cmyk' + options.colourspace = 1; + case {'gray', 'grey'} + options.colourspace = 2; + case {'a1', 'a2', 'a3', 'a4'} + options.aa_factor = str2double(thisArg(3)); + case 'append' + options.append = true; + case 'bookmark' + options.bookmark = true; + case 'native' + native = true; + case {'clipboard','clipboard:image'} + options.clipboard = true; + options.clipformat = 'image'; + options.im = true; %ensure that imageData is created + options.alpha = true; + case 'clipboard:bitmap' + options.clipboard = true; + options.clipformat = 'bitmap'; + case {'clipboard:emf','clipboard:meta'} + options.clipboard = true; + options.clipformat = 'meta'; + case 'clipboard:pdf' + options.clipboard = true; + options.clipformat = 'pdf'; + case 'update' + updateInstalledVersion(); + fig = -1; % silent bail-out + case 'version' + options.version = true; + return % ignore any additional args + case 'nofontswap' + options.fontswap = false; + case 'font_space' + options.font_space = varargin{a+1}; + skipNext = 1; + case 'linecaps' + options.linecaps = true; + case 'noinvert' + options.invert_hardcopy = false; + case 'preserve_size' + options.preserve_size = true; + case 'options' + % Issue #269: format-specific options + inputOptions = varargin{a+1}; + %options.format_options = inputOptions; + if isempty(inputOptions), continue, end + if iscell(inputOptions) + fields = inputOptions(1:2:end)'; + values = inputOptions(2:2:end)'; + options.format_options.all = cell2struct(values, fields); + elseif isstruct(inputOptions) + formats = fieldnames(inputOptions(1)); + for idx = 1 : numel(formats) + optionsStruct = inputOptions.(formats{idx}); + %optionsCells = [fieldnames(optionsStruct) struct2cell(optionsStruct)]'; + formatName = regexprep(lower(formats{idx}),{'tiff','jpeg'},{'tif','jpg'}); + options.format_options.(formatName) = optionsStruct; %=optionsCells(:)'; + end + else + warning('export_fig:options','export_fig -options argument is not in the expected format - ignored'); + end + skipNext = 1; + case 'silent' + options.silent = true; + case 'regexprep' + options.regexprep = varargin(a+1:a+2); + skipNext = 2; + case 'toolbar' + options.toolbar = true; + case 'menubar' + options.menubar = true; + otherwise + try + wasError = false; + if strcmpi(thisArg(1:2),'-d') + thisArg(2) = 'd'; % ensure lowercase 'd' + options.gs_options{end+1} = thisArg; + elseif strcmpi(thisArg(1:2),'-c') + if strncmpi(thisArg,'-clipboard:',11) + wasError = true; + error('export_fig:BadOptionValue','option ''%s'' cannot be parsed: only image, bitmap, emf and pdf formats are supported',thisArg); + end + if numel(thisArg)==2 + skipNext = 1; + vals = str2num(varargin{a+1}); %#ok + else + vals = str2num(thisArg(3:end)); %#ok + end + if numel(vals)~=4 + wasError = true; + error('export_fig:BadOptionValue','option -c cannot be parsed: must be a 4-element numeric vector'); + end + options.crop_amounts = vals; + options.crop = true; + else % scalar parameter value + val = str2double(regexp(thisArg, '(?<=-(m|M|r|R|q|Q|p|P))-?\d*.?\d+', 'match')); + if isempty(val) || isnan(val) + % Issue #51: improved processing of input args (accept space between param name & value) + val = str2double(varargin{a+1}); + if isscalar(val) && ~isnan(val) + skipNext = 1; + end + end + if ~isscalar(val) || isnan(val) + wasError = true; + error('export_fig:BadOptionValue','option %s is not recognised or cannot be parsed', thisArg); + end + switch lower(thisArg(2)) + case 'm' + % Magnification may never be negative + if val <= 0 + wasError = true; + error('export_fig:BadMagnification','Bad magnification value: %g (must be positive)', val); + end + options.magnify = val; + case 'r' + options.resolution = val; + case 'q' + options.quality = max(val, 0); + case 'p' + options.bb_padding = val; + end + end + catch err + % We might have reached here by raising an intentional error + if wasError % intentional raise + rethrow(err) + else % unintentional + error('export_fig:BadOption',['Unrecognized export_fig input option: ''' thisArg '''']); + end + end + end + else + % test for case of figure name rather than export filename + isFigName = false; + if isempty(options.handleName) + try + if strncmpi(thisArg,'Figure',6) + [~,~,~,~,e] = regexp(thisArg,'figure\s*(\d+)\s*(:\s*(.*))?','ignorecase'); + figNumber = str2double(e{1}{1}); + figName = regexprep(e{1}{2},':\s*',''); + findProps = {'Number',figNumber}; + if ~isempty(figName) + findProps = [findProps,'Name',figName]; %#ok + end + else + findProps = {'Name',thisArg}; + end + possibleFig = findall(0,'-depth',1,'Type','figure',findProps{:}); + if ~isempty(possibleFig) + fig = possibleFig(1); % return the 1st figure found + if ~strcmpi(options.name, defaultOptions.name) + continue % export fname was already specified + else + isFigName = true; %use figure name as export fname + end + end + catch + % ignore - treat as export filename, not figure name + end + end + % parse the input as a filename, alert if requested folder does not exist + [p, options.name, ext] = fileparts(thisArg); + if ~isempty(p) % export folder name/path was specified + % Issue #221: alert if the requested folder does not exist + if exist(p,'dir') + options.name = fullfile(p, options.name); + elseif ~isFigName + error('export_fig:BadPath','Folder %s does not exist, nor is it the name of any active figure!',p); + else % isFigName + % specified a figure name so ignore the bad folder part + end + end + switch lower(ext) + case {'.tif', '.tiff'} + options.tif = true; + case {'.jpg', '.jpeg'} + options.jpg = true; + case '.png' + options.png = true; + case '.bmp' + options.bmp = true; + case '.eps' + options.eps = true; + case '.emf' + options.emf = true; + case '.pdf' + options.pdf = true; + case '.fig' + % If no open figure, then load the specified .fig file and continue + figFilename = thisArg; + if isempty(fig) + fig = openfig(figFilename,'invisible'); + %varargin{a} = fig; + options.closeFig = true; + options.handleName = ['openfig(''' figFilename ''')']; + else + % save the current figure as the specified .fig file and exit + saveas(fig(1),figFilename); + fig = -1; + return + end + case '.svg' + options.svg = true; + case '.gif' + options.gif = true; + otherwise + options.name = thisArg; + end + end + end + end + + % Quick bail-out if no figure found + if isempty(fig), return; end + + % Do border padding with repsect to a cropped image + if options.bb_padding + options.crop = true; + end + + % Set default anti-aliasing now we know the renderer + try isAA = strcmp(get(ancestor(fig, 'figure'), 'GraphicsSmoothing'), 'on'); catch, isAA = false; end + if isAA + if options.aa_factor > 1 && ~options.silent + warning('export_fig:AntiAliasing','You requested anti-aliased export_fig output of a figure that is already anti-aliased - your -a option in export_fig is ignored.') + end + options.aa_factor = 1; % ignore -a option when the figure is already anti-aliased (HG2) + elseif options.aa_factor == 0 % default + %options.aa_factor = 1 + 2 * (~(using_hg2(fig) && isAA) | (options.renderer == 3)); + options.aa_factor = 1 + 2 * (~using_hg2(fig)); % =1 in HG2, =3 in HG1 + end + if options.aa_factor > 1 && ~isAA && using_hg2(fig) && ~options.silent + warning('export_fig:AntiAliasing','You requested anti-aliased export_fig output of an aliased figure (''GraphicsSmoothing''=''off''). You will see better results if you set your figure''s GraphicsSmoothing property to ''on'' before calling export_fig.') + end + + % Convert user dir '~' to full path + if numel(options.name) > 2 && options.name(1) == '~' && (options.name(2) == '/' || options.name(2) == '\') + options.name = fullfile(char(java.lang.System.getProperty('user.home')), options.name(2:end)); + end + + % Compute the magnification and resolution + if isempty(options.magnify) + if isempty(options.resolution) + options.magnify = 1; + options.resolution = 864; + else + options.magnify = options.resolution ./ get(0, 'ScreenPixelsPerInch'); + end + elseif isempty(options.resolution) + options.resolution = 864; + end + + % Set the format to PNG, if no other format was specified + if ~isvector(options) && ~isbitmap(options) && ~options.svg && ~options.emf + options.png = true; + end + + % Check whether transparent background is wanted (old way) + if isequal(get(ancestor(fig(1), 'figure'), 'Color'), 'none') + options.transparent = true; + end + + % If requested, set the resolution to the native vertical resolution of the + % first suitable image found + if native + if isbitmap(options) + % Find a suitable image + list = findall(fig, 'Type','image', 'Tag','export_fig_native'); + if isempty(list) + list = findall(fig, 'Type','image', 'Visible','on'); + end + for hIm = list(:)' + % Check height is >= 2 + height = size(get(hIm, 'CData'), 1); + if height < 2 + continue + end + % Account for the image filling only part of the axes, or vice versa + yl = get(hIm, 'YData'); + if isscalar(yl) + yl = [yl(1)-0.5 yl(1)+height+0.5]; + else + yl = [min(yl), max(yl)]; % fix issue #151 (case of yl containing more than 2 elements) + if ~diff(yl) + continue + end + yl = yl + [-0.5 0.5] * (diff(yl) / (height - 1)); + end + hAx = get(hIm, 'Parent'); + yl2 = get(hAx, 'YLim'); + % Find the pixel height of the axes + oldUnits = get(hAx, 'Units'); + set(hAx, 'Units', 'pixels'); + pos = get(hAx, 'Position'); + set(hAx, 'Units', oldUnits); + if ~pos(4) + continue + end + % Found a suitable image + % Account for stretch-to-fill being disabled + pbar = get(hAx, 'PlotBoxAspectRatio'); + pos = min(pos(4), pbar(2)*pos(3)/pbar(1)); + % Set the magnification to give native resolution + options.magnify = abs((height * diff(yl2)) / (pos * diff(yl))); % magnification must never be negative: issue #103 + break + end + elseif options.resolution == 864 % don't use -r864 in vector mode if user asked for -native + options.resolution = []; % issue #241 (internal Matlab bug produces black lines with -r864) + end + end +end + +% Convert a possible string => char (issue #245) +function value = str2char(value) + if isa(value,'string') + value = char(value); + end +end + +function A = downsize(A, factor) + % Downsample an image + if factor <= 1 || isempty(A) %issue #310 + % Nothing to do + return + end + try + % Faster, but requires image processing toolbox + A = imresize(A, 1/factor, 'bilinear'); + catch + % No image processing toolbox - resize manually + % Lowpass filter - use Gaussian as is separable, so faster + % Compute the 1d Gaussian filter + filt = (-factor-1:factor+1) / (factor * 0.6); + filt = exp(-filt .* filt); + % Normalize the filter + filt = single(filt / sum(filt)); + % Filter the image + padding = floor(numel(filt) / 2); + if padding < 1 || isempty(A), return, end %issue #310 + onesPad = ones(1, padding); + for a = 1:size(A,3) + A2 = single(A([onesPad 1:end repmat(end,1,padding)], ... + [onesPad 1:end repmat(end,1,padding)], a)); + A(:,:,a) = conv2(filt, filt', A2, 'valid'); + end + % Subsample + A = A(1+floor(mod(end-1, factor)/2):factor:end,1+floor(mod(end-1, factor)/2):factor:end,:); + end +end + +function A = rgb2grey(A) + A = cast(reshape(reshape(single(A), [], 3) * single([0.299; 0.587; 0.114]), size(A, 1), size(A, 2)), class(A)); % #ok +end + +function A = check_greyscale(A) + % Check if the image is greyscale + if size(A, 3) == 3 && ... + all(reshape(A(:,:,1) == A(:,:,2), [], 1)) && ... + all(reshape(A(:,:,2) == A(:,:,3), [], 1)) + A = A(:,:,1); % Save only one channel for 8-bit output + end +end + +function eps_remove_background(fname, count) + % Remove the background of an eps file + % Open the file + fh = fopen(fname, 'r+'); + if fh == -1 + error('export_fig:EPS:open','Cannot open file %s.', fname); + end + % Read the file line by line + while count + % Get the next line + l = fgets(fh); + if isequal(l, -1) + break; % Quit, no rectangle found + end + % Check if the line contains the background rectangle + if isequal(regexp(l, ' *0 +0 +\d+ +\d+ +r[fe] *[\n\r]+', 'start'), 1) + % Set the line to whitespace and quit + l(1:regexp(l, '[\n\r]', 'start', 'once')-1) = ' '; + fseek(fh, -numel(l), 0); + fprintf(fh, l); + % Reduce the count + count = count - 1; + end + end + % Close the file + fclose(fh); +end + +function b = isvector(options) % this only includes EPS-based vector formats (so not SVG,EMF) + b = options.pdf || options.eps; +end + +function b = isbitmap(options) + b = options.png || options.tif || options.jpg || options.bmp || ... + options.gif || options.im || options.alpha; +end + +function [A, tcol, alpha] = getFigImage(fig, magnify, renderer, options, pos) + if options.transparent + % MATLAB "feature": figure size can change when changing color in -nodisplay mode + % Note: figure background is set to off-white, not 'w', to handle common white elements (issue #330) + set(fig, 'Color',254/255*[1,1,1], 'Position',pos); + % repaint figure, otherwise Java screencapture will see black bgcolor + % Yair 19/12/21 - unnecessary: drawnow is called at top of print2array + %drawnow; + end + % Print large version to array + try + % The following code might cause out-of-memory errors + [A, tcol, alpha] = print2array(fig, magnify, renderer); + catch + % This is more conservative in memory, but perhaps kills transparency(?) + [A, tcol, alpha] = print2array(fig, magnify/options.aa_factor, renderer, 'retry'); + end + % In transparent mode, set the bgcolor to white + if options.transparent + % Note: tcol should already be [255,255,255] here, but just in case it's not... + tcol = uint8(254*[1,1,1]); %=off-white + end +end + +function A = make_cell(A) + if ~iscell(A) + A = {A}; + end +end + +function add_bookmark(fname, bookmark_text) + % Adds a bookmark to the temporary EPS file after %%EndPageSetup + % Read in the file + fh = fopen(fname, 'r'); + if fh == -1 + error('export_fig:bookmark:FileNotFound','File %s not found.', fname); + end + try + fstrm = fread(fh, '*char')'; + catch ex + fclose(fh); + rethrow(ex); + end + fclose(fh); + + % Include standard pdfmark prolog to maximize compatibility + fstrm = strrep(fstrm, '%%BeginProlog', sprintf('%%%%BeginProlog\n/pdfmark where {pop} {userdict /pdfmark /cleartomark load put} ifelse')); + % Add page bookmark + fstrm = strrep(fstrm, '%%EndPageSetup', sprintf('%%%%EndPageSetup\n[ /Title (%s) /OUT pdfmark',bookmark_text)); + + % Write out the updated file + fh = fopen(fname, 'w'); + if fh == -1 + error('export_fig:bookmark:permission','Unable to open %s for writing.', fname); + end + try + fwrite(fh, fstrm, 'char*1'); + catch ex + fclose(fh); + rethrow(ex); + end + fclose(fh); +end + +function set_manual_axes_modes(Hlims, ax) + % Set the axes limits mode to manual + set(Hlims, [ax 'LimMode'], 'manual'); + + % Set the tick mode of linear axes to manual + % Leave log axes alone as these are tricky + M = get(Hlims, [ax 'Scale']); + if ~iscell(M) + M = {M}; + end + %idx = cellfun(@(c) strcmp(c, 'linear'), M); + idx = find(strcmp(M,'linear')); + %set(Hlims(idx), [ax 'TickMode'], 'manual'); % issue #187 + %set(Hlims(idx), [ax 'TickLabelMode'], 'manual'); % this hides exponent label in HG2! + for idx2 = 1 : numel(idx) + try + % Fix for issue #187 - only set manual ticks when no exponent is present + hAxes = Hlims(idx(idx2)); + props = {[ax 'TickMode'],'manual', [ax 'TickLabelMode'],'manual'}; + tickVals = get(hAxes,[ax 'Tick']); + tickStrs = get(hAxes,[ax 'TickLabel']); + try % TickLabelRotation is available since R2021a + propName = [ax,'TickLabelRotationMode']; + if ~isempty(get(hAxes,propName)) %this will croak in R2020b- + props = [props, propName,'manual']; %#ok + end + catch + % ignore - probably R2020b or older + end + try % Fix issue #236 + exponents = [hAxes.([ax 'Axis']).SecondaryLabel]; + catch + exponents = [hAxes.([ax 'Ruler']).SecondaryLabel]; + end + if isempty([exponents.String]) + % Fix for issue #205 - only set manual ticks when the Ticks number match the TickLabels number + if numel(tickVals) == numel(tickStrs) + set(hAxes, props{:}); % no exponent and matching ticks, so update both ticks and tick labels to manual + end + end + catch % probably HG1 + % Fix for issue #220 - exponent is removed in HG1 when TickMode is 'manual' (internal Matlab bug) + if isequal(tickVals, str2num(tickStrs)') %#ok + set(hAxes, props{:}); % revert back to old behavior + end + end + end +end + +function change_rgb_to_cmyk(fname) % convert RGB => CMYK within an EPS file + % Do post-processing on the eps file + try + % Read the EPS file into memory + fstrm = read_write_entire_textfile(fname); + + % Replace all gray-scale colors + fstrm = regexprep(fstrm, '\n([\d.]+) +GC\n', '\n0 0 0 ${num2str(1-str2num($1))} CC\n'); + + % Replace all RGB colors + fstrm = regexprep(fstrm, '\n[0.]+ +[0.]+ +[0.]+ +RC\n', '\n0 0 0 1 CC\n'); % pure black + fstrm = regexprep(fstrm, '\n([\d.]+) +([\d.]+) +([\d.]+) +RC\n', '\n${sprintf(''%.4g '',[1-[str2num($1),str2num($2),str2num($3)]/max([str2num($1),str2num($2),str2num($3)]),1-max([str2num($1),str2num($2),str2num($3)])])} CC\n'); + + % Overwrite the file with the modified contents + read_write_entire_textfile(fname, fstrm); + catch + % never mind - leave as is... + end +end + +function [hBlackAxles, hBlackRulers] = fixBlackAxle(hAxes, axleName) + hBlackAxles = []; + hBlackRulers = []; + for idx = 1 : numel(hAxes) + ax = hAxes(idx); + axleColor = get(ax, axleName); + if isequal(axleColor,[0,0,0]) || isequal(axleColor,'k') + hBlackAxles(end+1) = ax; %#ok + try % Fix issue #306 - black yyaxis + if strcmpi(axleName,'Color'), continue, end %ruler, not axle + rulerName = strrep(axleName,'Color','Axis'); + hRulers = get(ax, rulerName); + newBlackRulers = fixBlackAxle(hRulers,'Color'); + hBlackRulers = [hBlackRulers newBlackRulers]; %#ok + catch + end + end + end + set(hBlackAxles, axleName, [0,0,0.01]); % off-black +end + +% Issue #269: format-specific options +function [optionsCells, bitDepth] = getFormatOptions(options, formatName) + bitDepth = []; + try + optionsStruct = options.format_options.(lower(formatName)); + catch + try + % Perhaps user specified the options in cell array format + optionsStruct = options.format_options.all; + catch + % User did not specify any extra parameters for this format + optionsCells = {}; + return + end + end + optionNames = fieldnames(optionsStruct); + optionVals = struct2cell(optionsStruct); + optionsCells = [optionNames, optionVals]'; + if nargout < 2, return, end % bail out if BitDepth is not required + try + idx = find(strcmpi(optionNames,'BitDepth'), 1, 'last'); + if ~isempty(idx) + bitDepth = optionVals{idx}; + end + catch + % never mind - ignore + end +end + +% Check for newer version (only once a day) +function isNewerVersionAvailable = checkForNewerVersion(currentVersion) + persistent lastCheckTime lastVersion + isNewerVersionAvailable = false; + if nargin < 1 || isempty(lastCheckTime) || now - lastCheckTime > 1 + url = 'https://raw.githubusercontent.com/altmany/export_fig/master/export_fig.m'; + try + str = readURL(url); + [unused,unused,unused,unused,latestVerStrs] = regexp(str, '\n[^:]+: \(([^)]+)\) ([^%]+)(?=\n)'); %#ok + latestVersion = str2double(latestVerStrs{end}{1}); + if nargin < 1 + currentVersion = lastVersion; + else + currentVersion = currentVersion + 1e3*eps; + end + isNewerVersionAvailable = latestVersion > currentVersion; + if isNewerVersionAvailable + try + verStrs = strtrim(reshape([latestVerStrs{:}],2,[])); + verNums = arrayfun(@(c)str2double(c{1}),verStrs(1,:)); + isValid = verNums > currentVersion; + versionDesc = strjoin(flip(verStrs(2,isValid)),';'); + catch + % Something bad happened - only display the latest version description + versionDesc = latestVerStrs{1}{2}; + end + try versionDesc = strjoin(strrep(strcat(' ***', strtrim(strsplit(versionDesc,';'))),'***','* '), char(10)); catch, end %#ok + msg = sprintf(['You are using version %.2f of export_fig. ' ... + 'A newer version (%g) is available, with the following improvements/fixes:\n' ... + '%s\n' ... + 'A change-log of recent releases is available here; the complete change-log is included at the top of the export_fig.m file.\n' ... % issue #322 + 'You can download the new version from GitHub or Matlab File Exchange, ' ... + 'or run export_fig(''-update'') to install it directly.' ... + ], currentVersion, latestVersion, versionDesc); + msg = hyperlink('https://github.com/altmany/export_fig', 'GitHub', msg); + msg = hyperlink('https://www.mathworks.com/matlabcentral/fileexchange/23629-export_fig', 'Matlab File Exchange', msg); + msg = hyperlink('matlab:export_fig(''-update'')', 'export_fig(''-update'')', msg); + msg = hyperlink('https://github.com/altmany/export_fig/releases', 'available here', msg); + msg = hyperlink('https://github.com/altmany/export_fig/blob/master/export_fig.m#L300', 'export_fig.m file', msg); + warning('export_fig:version',msg); + end + catch + % ignore + end + lastCheckTime = now; + lastVersion = currentVersion; + end +end + +% Update the installed version of export_fig from the latest version online +function updateInstalledVersion() + % Download the latest version of export_fig into the export_fig folder + zipFileName = 'https://github.com/altmany/export_fig/archive/master.zip'; + fprintf('Downloading latest version of %s from %s...\n', mfilename, zipFileName); + folderName = fileparts(which(mfilename('fullpath'))); + targetFileName = fullfile(folderName, datestr(now,'yyyy-mm-dd.zip')); + try + folder = hyperlink(['matlab:winopen(''' folderName ''')'], folderName); + catch % hyperlink.m is not properly installed + folder = folderName; + end + try + urlwrite(zipFileName,targetFileName); %#ok + catch err + error('export_fig:update:download','Error downloading %s into %s: %s\n',zipFileName,targetFileName,err.message); + end + + % Unzip the downloaded zip file in the export_fig folder + fprintf('Extracting %s...\n', targetFileName); + try + unzip(targetFileName,folderName); + % Fix issue #302 - zip file uses an internal folder export_fig-master + subFolder = fullfile(folderName,'export_fig-master'); + try movefile(fullfile(subFolder,'*.*'),folderName, 'f'); catch, end %All OSes + try movefile(fullfile(subFolder,'*'), folderName, 'f'); catch, end %MacOS/Unix + try movefile(fullfile(subFolder,'.*'), folderName, 'f'); catch, end %MacOS/Unix + try rmdir(subFolder); catch, end + catch err + error('export_fig:update:unzip','Error unzipping %s: %s\n',targetFileName,err.message); + end + + % Notify the user and rehash + fprintf('Successfully installed the latest %s version in %s\n', mfilename, folder); + clear functions %#ok + rehash +end + +% Read a file from the web +function str = readURL(url) + try + str = char(webread(url)); + catch err %if isempty(which('webread')) + if isempty(strfind(err.message,'404')) + v = version; % '9.6.0.1072779 (R2019a)' + if v(1) >= '8' % '8.0 (R2012b)' https://www.mathworks.com/help/matlab/release-notes.html?rntext=urlread&searchHighlight=urlread&startrelease=R2012b&endrelease=R2012b + str = urlread(url, 'Timeout',5); %#ok + else + str = urlread(url); %#ok % R2012a or older (no Timeout parameter) + end + else + rethrow(err) + end + end + if size(str,1) > 1 % ensure a row-wise string + str = str'; + end +end + +% Display a promo message in the Matlab console +function displayPromoMsg(msg, url) + %msg = [msg url]; + msg = strrep(msg,'<$>',url); + link = ['$0']); + %msg = regexprep(msg,{'consulting','training'},[link '/$0">$0']); + %warning('export_fig:promo',msg); + disp(['[' 8 msg ']' 8]); +end + +% Cross-check existance of other programs +function programsCrossCheck() + try + % IQ + hasTaskList = false; + if ispc && ~exist('IQML','file') + hasIQ = exist('C:/Progra~1/DTN/IQFeed','dir') || ... + exist('C:/Progra~2/DTN/IQFeed','dir'); + if ~hasIQ + [status,tasksStr] = system('tasklist'); %#ok + tasksStr = lower(tasksStr); + hasIQ = ~isempty(strfind(tasksStr,'iqconnect')) || ... + ~isempty(strfind(tasksStr,'iqlink')); %#ok + hasTaskList = true; + end + if hasIQ + displayPromoMsg('To connect Matlab to IQFeed, try the IQML connector <$>', 'https://UndocumentedMatlab.com/IQML'); + end + end + + % IB + if ~exist('IBMatlab','file') + hasIB = false; + possibleFolders = {'C:/Jts','C:/Programs/Jts','C:/Progra~1/Jts','C:/Progra~2/Jts','~/IBJts','~/IBJts/IBJts'}; + for folderIdx = 1 : length(possibleFolders) + if exist(possibleFolders{folderIdx},'dir') + hasIB = true; + break + end + end + if ~hasIB + if ~hasTaskList + if ispc % Windows + [status,tasksStr] = system('tasklist'); %#ok + else % Linux/MacOS + [status,tasksStr] = system('ps -e'); %#ok + end + tasksStr = lower(tasksStr); + end + hasIB = ~isempty(strfind(tasksStr,'tws')) || ... + ~isempty(strfind(tasksStr,'ibgateway')); %#ok + end + if hasIB + displayPromoMsg('To connect Matlab to IB try the IB-Matlab connector <$>', 'https://UndocumentedMatlab.com/IB-Matlab'); + end + end + catch + % never mind - ignore error + end +end + +% Hint to users to use exportgraphics/copygraphics in certain cases +function alertForExportOrCopygraphics(options) + %matlabVerNum = str2num(regexprep(version,'(\d+\.\d+).*','$1')); + try + % Bail out on R2019b- (copygraphics/exportgraphics not available/reliable) + if verLessThan('matlab','9.8') % 9.8 = R2020a + return + end + + isNoRendererSpecified = options.renderer == 0; + isPainters = options.renderer == 3; + noResolutionSpecified = isempty(options.resolution) || isequal(options.resolution,864); + + % First check for copygraphics compatibility (export to clipboard) + params = ','; + if options.clipboard + if options.transparent % -transparent was requested + if isPainters || isNoRendererSpecified % painters or default renderer + if noResolutionSpecified + params = '''BackgroundColor'',''none'',''ContentType'',''vector'','; + else % exception: no message + params = ','; + end + else % opengl/zbuffer renderer + if options.invert_hardcopy % default + params = '''BackgroundColor'',''white'','; + else % -noinvert was requested + params = '''BackgroundColor'',''current'','; % 'none' is 'white' when ContentType='image' + end + params = [params '''ContentType'',''image'',']; + if ~noResolutionSpecified + params = [params '''Resolution'',' num2str(options.resolution) ',']; + else + % don't add a resolution param + end + end + else % no -transparent + if options.invert_hardcopy % default + params = '''BackgroundColor'',''white'','; + else % -noinvert was requested + params = '''BackgroundColor'',''current'','; + end + if isPainters % painters (but not default!) renderer + if noResolutionSpecified + params = [params '''ContentType'',''vector'',']; + else % exception: no message + params = ','; + end + else % opengl/zbuffer/default renderer + params = [params '''ContentType'',''image'',']; + if ~noResolutionSpecified + params = [params '''Resolution'',' num2str(options.resolution) ',']; + else + % don't add a resolution param + end + end + end + + % If non-RGB colorspace was requested on R2021a+ + if ~verLessThan('matlab','9.10') % 9.10 = R2021a + if options.colourspace == 2 % gray + params = [params '''Colorspace'',''gray'',']; + end + end + end + displayMsg(params, 'copygraphics', 'clipboard', ''); + + % Next check for exportgraphics compatibility (export to file) + % Note: not , since -clipboard can be combined with file export + params = ','; + if ~options.clipboard + if options.transparent % -transparent was requested + if isvector(options) % vector output + if isPainters || isNoRendererSpecified % painters or default renderer + if noResolutionSpecified + params = '''BackgroundColor'',''none'',''ContentType'',''vector'','; + else % exception: no message + params = ','; + end + else % opengl/zbuffer renderer + params = '''BackgroundColor'',''none'',''ContentType'',''vector'','; + end + else % non-vector output + params = ','; + end + else % no -transparent + if options.invert_hardcopy % default + params = '''BackgroundColor'',''white'','; + else % -noinvert was requested + params = '''BackgroundColor'',''current'','; + end + if isvector(options) % vector output + if isPainters || isNoRendererSpecified % painters or default renderer + if noResolutionSpecified + params = [params '''ContentType'',''vector'',']; + else % exception: no message + params = ','; + end + else % opengl/zbuffer renderer + if noResolutionSpecified + params = [params '''ContentType'',''image'',']; + else % exception: no message + params = ','; + end + end + else % non-vector output + if isPainters % painters (but not default!) renderer + % exception: no message + params = ','; + else % opengl/zbuffer/default renderer + if ~noResolutionSpecified + params = [params '''Resolution'',' num2str(options.resolution) ',']; + end + end + end + end + + % If non-RGB colorspace was requested on R2021a+ + if ~verLessThan('matlab','9.10') % 9.10 = R2021a + if options.colourspace == 2 % gray + params = [params '''Colorspace'',''gray'',']; + elseif options.colourspace == 1 && options.eps % cmyk (eps only) + params = [params '''Colorspace'',''cmyk'',']; + end + end + end + filenameParam = 'filename,'; %=[options.name ',']; + displayMsg(params, 'exportgraphics', 'file', filenameParam); + catch + % Ignore errors - do not stop export_fig processing + end + + % Utility function to display an alert message + function displayMsg(params, funcName, type, filenameParam) + if length(params) > 1 + % strip default param values from the message + params = strrep(params, '''BackgroundColor'',''white'',', ''); + % strip the trailing , + if ~isempty(params) && params(end)==',', params(end)=''; end + % if this message was not already displayed + try prevParams = getpref('export_fig',funcName); catch, prevParams = ''; end + if ~strcmpi(params, prevParams) + % display the message (TODO: perhaps replace warning() with fprintf()?) + if ~isempty([filenameParam params]) + filenameParam = [',' filenameParam]; + end + if ~isempty(filenameParam) && filenameParam(end)==',' && isempty(params) + filenameParam(end) = ''; + end + handleName = options.handleName; + if isempty(options.handleName) % handle was either not specified, or via gca()/gcf() etc. [i.e. not by variable] + handleName = 'hFigure'; + end + msg = ['In Matlab R2020a+ you can also use ' funcName '(' handleName filenameParam params ') for simple ' type ' export']; + if ~isempty(strfind(params,'''vector''')) %#ok + msg = [msg ', which could also improve image vectorization, solving rasterization/pixelization problems.']; + end + oldWarn = warning('on','verbose'); + warning(['export_fig:' funcName], msg); + warning(oldWarn); + setpref('export_fig',funcName,params); + end + end + end +end + +% Does a file exist? +function flag = existFile(filename) + try + % isfile() is faster than exist(), but does not report files on path + flag = isfile(filename); + catch + flag = exist(filename,'file') ~= 0; + end +end + +% Add interactive export button to the figure's toolbar +function addToolbarButton(hFig, options) + % Ensure we have a valid toolbar handle + if isempty(hFig) + if options.silent + return + else + error('export_fig:noFigure','not a valid GUI handle'); + end + end + set(hFig,'ToolBar','figure'); + hToolbar = findall(hFig, 'type','uitoolbar', '-depth',1); + if isempty(hToolbar) + if ~options.silent + warning('export_fig:noToolbar','cannot add toolbar button to the specified figure'); + end + end + hToolbar = hToolbar(1); % just in case there are several toolbars... - use only the first + + % Bail out silently if the export_fig button already exists + hButton = findall(hToolbar, 'Tag','export_fig'); + if ~isempty(hButton) + return + end + + % Prepare the camera icon + icon = ['3333333333333333'; ... + '3333333333333333'; ... + '3333300000333333'; ... + '3333065556033333'; ... + '3000000000000033'; ... + '3022222222222033'; ... + '3022220002222033'; ... + '3022203110222033'; ... + '3022201110222033'; ... + '3022204440222033'; ... + '3022220002222033'; ... + '3022222222222033'; ... + '3000000000000033'; ... + '3333333333333333'; ... + '3333333333333333'; ... + '3333333333333333']; + cm = [ 0 0 0; ... % black + 0 0.60 1; ... % light blue + 0.53 0.53 0.53; ... % light gray + NaN NaN NaN; ... % transparent + 0 0.73 0; ... % light green + 0.27 0.27 0.27; ... % gray + 0.13 0.13 0.13]; % dark gray + cdata = ind2rgb(uint8(icon-'0'),cm); + + % If the button does not already exit + tooltip = 'Export this figure'; + + % Add the button with the icon to the figure's toolbar + props = {'Parent',hToolbar, 'CData',cdata, 'Tag','export_fig', ... + 'Tooltip',tooltip, 'ClickedCallback',@interactiveExport}; + try + hButton = []; % just in case we croak below + + % Create a new split-button with the open-file button's data + oldWarn = warning('off','MATLAB:uisplittool:DeprecatedFunction'); + hButton = uisplittool(props{:}); + warning(oldWarn); + + % Add the split-button's menu items + drawnow; pause(0.01); % allow the buttom time to render + jButton = get(hButton,'JavaContainer'); %#ok + jButtonMenu = jButton.getMenuComponent; + + tooltip = [tooltip ' (specify filename/format)']; + try jButtonMenu.setToolTipText(tooltip); catch, end + try jButton.getComponentPeer.getComponent(1).setToolTipText(tooltip); catch, end + + defaultFname = get(hFig,'Name'); + if isempty(defaultFname), defaultFname = 'figure'; end + imFormats = {'pdf','eps','emf','svg','png','tif','jpg','bmp','gif'}; + for idx = 1 : numel(imFormats) + thisFormat = imFormats{idx}; + filename = [defaultFname '.' thisFormat]; + label = [upper(thisFormat) ' image file (' filename ')']; + jMenuItem = handle(jButtonMenu.add(label),'CallbackProperties'); + set(jMenuItem,'ActionPerformedCallback',@(h,e)export_fig(hFig,filename)); + end + jButtonMenu.addSeparator(); + cbFormats = {'image','bitmap','meta','pdf'}; + for idx = 1 : numel(cbFormats) + thisFormat = cbFormats{idx}; + exFormat = ['-clipboard:' thisFormat]; + label = ['Clipboard (' thisFormat ' format)']; + jMenuItem = handle(jButtonMenu.add(label),'CallbackProperties'); + set(jMenuItem,'ActionPerformedCallback',@(h,e)export_fig(hFig,exFormat)); + end + jButtonMenu.addSeparator(); + jMenuItem = handle(jButtonMenu.add('Select filename and format'),'CallbackProperties'); + set(jMenuItem,'ActionPerformedCallback',@(h,e)interactiveExport(hFig)); + catch % revert to a simple documented toolbar pushbutton + warning(oldWarn); + if isempty(hButton) %avoid duplicate toolbar buttons (keep the splittool) + hButton = uipushtool(props{:}); %#ok + end + end +end + +% Add interactive export menu to the figure's menubar +function addMenubarMenu(hFig, options) + % Ensure we have a valid figure handle + if isempty(hFig) + if options.silent + return + else + error('export_fig:noFigure','not a valid GUI handle'); + end + end + set(hFig,'MenuBar','figure'); + + % Bail out silently if the export_fig menu already exists + hMainMenu = findall(hFig, '-depth',1, 'type','uimenu', 'Tag','export_fig'); + if ~isempty(hMainMenu) + return + end + + % Add the export_fig menu to the figure's menubar + hMainMenu = uimenu(hFig, 'Text','E&xport', 'Tag','export_fig'); + defaultFname = get(hFig,'Name'); + if isempty(defaultFname), defaultFname = 'figure'; end + imFormats = {'pdf','eps','emf','svg','png','tif','jpg','bmp','gif'}; + for idx = 1 : numel(imFormats) + thisFormat = imFormats{idx}; + filename = [defaultFname '.' thisFormat]; + label = [upper(thisFormat) ' image file (' filename ')']; + uimenu(hMainMenu, 'Text',label, 'MenuSelectedFcn',@(h,e)export_fig(hFig,filename)); + end + cbFormats = {'image','bitmap','meta','pdf'}; + for idx = 1 : numel(cbFormats) + thisFormat = cbFormats{idx}; + exFormat = ['-clipboard:' thisFormat]; + label = ['Clipboard (' thisFormat ' format)']; + sep = 'off'; if idx==1, sep = 'on'; end + uimenu(hMainMenu, 'Text',label, 'Separator',sep, ... + 'MenuSelectedFcn',@(h,e)export_fig(hFig,exFormat)); + end + uimenu(hMainMenu, 'Text','Select filename and format', 'Separator','on', ... + 'MenuSelectedFcn',@interactiveExport); +end + +% Callback functions for toolbar/menubar actions +function interactiveExport(hObject, varargin) + % Get the exported figure handle + hFig = gcbf; + if isempty(hFig) + hFig = ancestor(hObject, 'figure'); + end + if isempty(hFig) + return % bail out silently if no figure is available + end + + % Display a Save-as dialog to let the user select the export name & type + defaultFname = get(hFig,'Name'); + if isempty(defaultFname), defaultFname = 'figure'; end + %formats = imformats; + formats = {'pdf','eps','emf','svg','png','tif','jpg','bmp','gif', ... + 'clipboard:image','clipboard:bitmap','clipboard:meta','clipboard:pdf'}; + for idx = 1 : numel(formats) + thisFormat = formats{idx}; + ext = sprintf('*.%s',thisFormat); + if ~any(thisFormat==':') % image file format + description = [upper(thisFormat) ' image file (' ext ')']; + format(idx,1:2) = {ext, description}; %#ok + else % clipboard format + description = [strrep(thisFormat,':',' (') ' format *.)']; + format(idx,1:2) = {'*.*', description}; %#ok + end + end + %format + [filename,pathname,idx] = uiputfile(format,'Save figure export as',defaultFname); + drawnow; pause(0.01); % prevent a Matlab hang + if ~isequal(filename,0) + thisFormat = formats{idx}; + if ~any(thisFormat==':') % export to image file + filename = fullfile(pathname,filename); + export_fig(hFig, filename); + else % export to clipboard + export_fig(hFig, ['-' thisFormat]); + end + else + % User canceled the dialog - bail out silently + end +end diff --git a/matlab/export_fig/fix_lines.m b/matlab/export_fig/fix_lines.m new file mode 100644 index 0000000..b160fd8 --- /dev/null +++ b/matlab/export_fig/fix_lines.m @@ -0,0 +1,151 @@ +%FIX_LINES Improves the line style of eps files generated by print +% +% Examples: +% fix_lines fname +% fix_lines fname fname2 +% fstrm_out = fixlines(fstrm_in) +% +% This function improves the style of lines in eps files generated by +% MATLAB's print function, making them more similar to those seen on +% screen. Grid lines are also changed from a dashed style to a dotted +% style, for greater differentiation from dashed lines. +% +% The function also places embedded fonts after the postscript header, in +% versions of MATLAB which place the fonts first (R2006b and earlier), in +% order to allow programs such as Ghostscript to find the bounding box +% information. +% +%IN: +% fname - Name or path of source eps file. +% fname2 - Name or path of destination eps file. Default: same as fname. +% fstrm_in - File contents of a MATLAB-generated eps file. +% +%OUT: +% fstrm_out - Contents of the eps file with line styles fixed. + +% Copyright: (C) Oliver Woodford, 2008-2014 + +% The idea of editing the EPS file to change line styles comes from Jiro +% Doke's FIXPSLINESTYLE (fex id: 17928) +% The idea of changing dash length with line width came from comments on +% fex id: 5743, but the implementation is mine :) + +% Thank you to Sylvain Favrot for bringing the embedded font/bounding box +% interaction in older versions of MATLAB to my attention. +% Thank you to D Ko for bringing an error with eps files with tiff previews +% to my attention. +% Thank you to Laurence K for suggesting the check to see if the file was +% opened. + +% 01/03/15: Issue #20: warn users if using this function in HG2 (R2014b+) +% 27/03/15: Fixed out of memory issue with enormous EPS files (generated by print() with OpenGL renderer), related to issue #39 + +function fstrm = fix_lines(fstrm, fname2) + +% Issue #20: warn users if using this function in HG2 (R2014b+) +if using_hg2 + warning('export_fig:hg2','The fix_lines function should not be used in this Matlab version.'); +end + +if nargout == 0 || nargin > 1 + if nargin < 2 + % Overwrite the input file + fname2 = fstrm; + end + % Read in the file + fstrm = read_write_entire_textfile(fstrm); +end + +% Move any embedded fonts after the postscript header +if strcmp(fstrm(1:15), '%!PS-AdobeFont-') + % Find the start and end of the header + ind = regexp(fstrm, '[\n\r]%!PS-Adobe-'); + [ind2, ind2] = regexp(fstrm, '[\n\r]%%EndComments[\n\r]+'); + % Put the header first + if ~isempty(ind) && ~isempty(ind2) && ind(1) < ind2(1) + fstrm = fstrm([ind(1)+1:ind2(1) 1:ind(1) ind2(1)+1:end]); + end +end + +% Make sure all line width commands come before the line style definitions, +% so that dash lengths can be based on the correct widths +% Find all line style sections +ind = [regexp(fstrm, '[\n\r]SO[\n\r]'),... % This needs to be here even though it doesn't have dots/dashes! + regexp(fstrm, '[\n\r]DO[\n\r]'),... + regexp(fstrm, '[\n\r]DA[\n\r]'),... + regexp(fstrm, '[\n\r]DD[\n\r]')]; +ind = sort(ind); +% Find line width commands +[ind2, ind3] = regexp(fstrm, '[\n\r]\d* w[\n\r]'); +% Go through each line style section and swap with any line width commands +% near by +b = 1; +m = numel(ind); +n = numel(ind2); +for a = 1:m + % Go forwards width commands until we pass the current line style + while b <= n && ind2(b) < ind(a) + b = b + 1; + end + if b > n + % No more width commands + break; + end + % Check we haven't gone past another line style (including SO!) + if a < m && ind2(b) > ind(a+1) + continue; + end + % Are the commands close enough to be confident we can swap them? + if (ind2(b) - ind(a)) > 8 + continue; + end + % Move the line style command below the line width command + fstrm(ind(a)+1:ind3(b)) = [fstrm(ind(a)+4:ind3(b)) fstrm(ind(a)+1:ind(a)+3)]; + b = b + 1; +end + +% Find any grid line definitions and change to GR format +% Find the DO sections again as they may have moved +ind = int32(regexp(fstrm, '[\n\r]DO[\n\r]')); +if ~isempty(ind) + % Find all occurrences of what are believed to be axes and grid lines + ind2 = int32(regexp(fstrm, '[\n\r] *\d* *\d* *mt *\d* *\d* *L[\n\r]')); + if ~isempty(ind2) + % Now see which DO sections come just before axes and grid lines + ind2 = repmat(ind2', [1 numel(ind)]) - repmat(ind, [numel(ind2) 1]); + ind2 = any(ind2 > 0 & ind2 < 12); % 12 chars seems about right + ind = ind(ind2); + % Change any regions we believe to be grid lines to GR + fstrm(ind+1) = 'G'; + fstrm(ind+2) = 'R'; + end +end + +% Define the new styles, including the new GR format +% Dot and dash lengths have two parts: a constant amount plus a line width +% variable amount. The constant amount comes after dpi2point, and the +% variable amount comes after currentlinewidth. If you want to change +% dot/dash lengths for a one particular line style only, edit the numbers +% in the /DO (dotted lines), /DA (dashed lines), /DD (dot dash lines) and +% /GR (grid lines) lines for the style you want to change. +new_style = {'/dom { dpi2point 1 currentlinewidth 0.08 mul add mul mul } bdef',... % Dot length macro based on line width + '/dam { dpi2point 2 currentlinewidth 0.04 mul add mul mul } bdef',... % Dash length macro based on line width + '/SO { [] 0 setdash 0 setlinecap } bdef',... % Solid lines + '/DO { [1 dom 1.2 dom] 0 setdash 0 setlinecap } bdef',... % Dotted lines + '/DA { [4 dam 1.5 dam] 0 setdash 0 setlinecap } bdef',... % Dashed lines + '/DD { [1 dom 1.2 dom 4 dam 1.2 dom] 0 setdash 0 setlinecap } bdef',... % Dot dash lines + '/GR { [0 dpi2point mul 4 dpi2point mul] 0 setdash 1 setlinecap } bdef'}; % Grid lines - dot spacing remains constant + +% Construct the output +% This is the original (memory-intensive) code: +%first_sec = strfind(fstrm, '% line types:'); % Isolate line style definition section +%[second_sec, remaining] = strtok(fstrm(first_sec+1:end), '/'); +%[remaining, remaining] = strtok(remaining, '%'); +%fstrm = [fstrm(1:first_sec) second_sec sprintf('%s\r', new_style{:}) remaining]; +fstrm = regexprep(fstrm,'(% line types:.+?)/.+?%',['$1',sprintf('%s\r',new_style{:}),'%']); + +% Write the output file +if nargout == 0 || nargin > 1 + read_write_entire_textfile(fname2, fstrm); +end +end diff --git a/matlab/export_fig/ghostscript.m b/matlab/export_fig/ghostscript.m new file mode 100644 index 0000000..d0200a7 --- /dev/null +++ b/matlab/export_fig/ghostscript.m @@ -0,0 +1,208 @@ +function varargout = ghostscript(cmd) +%GHOSTSCRIPT Calls a local GhostScript executable with the input command +% +% Example: +% [status result] = ghostscript(cmd) +% +% Attempts to locate a ghostscript executable, finally asking the user to +% specify the directory ghostcript was installed into. The resulting path +% is stored for future reference. +% +% Once found, the executable is called with the input command string. +% +% This function requires a Ghostscript installation on your system. +% You can download Ghostscript from http://ghostscript.com (Windows/Linux) +% or http://pages.uoregon.edu/koch (MacOS). +% +% IN: +% cmd - Command string to be passed into ghostscript. +% +% OUT: +% status - 0 iff command ran without problem. +% result - Output from ghostscript. + +% Copyright: Oliver Woodford, 2009-2015, Yair Altman 2015- +%{ +% Thanks to Jonas Dorn for the fix for the title of the uigetdir window on Mac OS. +% Thanks to Nathan Childress for the fix to default location on 64-bit Windows systems. +% 27/04/11 - Find 64-bit Ghostscript on Windows. Thanks to Paul Durack and +% Shaun Kline for pointing out the issue +% 04/05/11 - Thanks to David Chorlian for pointing out an alternative +% location for gs on linux. +% 12/12/12 - Add extra executable name on Windows. Thanks to Ratish +% Punnoose for highlighting the issue. +% 28/06/13 - Fix error using GS 9.07 in Linux. Many thanks to Jannick +% Steinbring for proposing the fix. +% 24/10/13 - Fix error using GS 9.07 in Linux. Many thanks to Johannes +% for the fix. +% 23/01/14 - Add full path to ghostscript.txt in warning. Thanks to Koen +% Vermeer for raising the issue. +% 27/02/15 - If Ghostscript croaks, display suggested workarounds +% 30/03/15 - Improved performance by caching status of GS path check, if ok +% 14/05/15 - Clarified warning message in case GS path could not be saved +% 29/05/15 - Avoid cryptic error in case the ghostscipt path cannot be saved (issue #74) +% 10/11/15 - Custom GS installation webpage for MacOS. Thanks to Andy Hueni via FEX +% 15/01/20 - Various message cleanups/fixes in case of errors +%} + + try + % Call ghostscript + [varargout{1:nargout}] = system([gs_command(gs_path()) cmd]); + catch err + % Display possible workarounds for Ghostscript croaks + url1 = 'https://github.com/altmany/export_fig/issues/12#issuecomment-61467998'; % issue #12 + url2 = 'https://github.com/altmany/export_fig/issues/20#issuecomment-63826270'; % issue #20 + hg2_str = ''; if using_hg2, hg2_str = ' or Matlab R2014a'; end + fprintf(2, 'Ghostscript error. Rolling back to GS 9.10%s may possibly solve this:\n * %s ', hg2_str, hyperlink(url1)); + if using_hg2 + fprintf(2, '(GS 9.10)\n * %s (R2014a)', hyperlink(url2)); + end + fprintf('\n\n'); + if ismac || isunix + url3 = 'https://github.com/altmany/export_fig/issues/27'; % issue #27 + fprintf(2, 'Alternatively, this may possibly be due to a font path issue:\n * %s\n\n', hyperlink(url3)); + % issue #20 + % TODO: in Unix/Mac, find a way to automatically determine whether to use "export" (bash) or "setenv" (csh/tcsh) + if isdeployed + url = [mfilename '.m']; + else + fpath = which(mfilename); + if isempty(fpath), fpath = [mfilename('fullpath') '.m']; end + url = ['' fpath '']; + end + fprintf(2, 'Alternatively, if you are using csh, modify shell_cmd from "export ..." to "setenv ..."\nat the bottom of %s\n\n', url); + end + rethrow(err); + end +end + +function path_ = gs_path + % Return a valid path + % Start with the currently set path + path_ = user_string('ghostscript'); + % Check the path works + if check_gs_path(path_) + return + end + % Check whether the binary is on the path + if ispc + bin = {'gswin32c.exe', 'gswin64c.exe', 'gs'}; + else + bin = {'gs'}; + end + for a = 1:numel(bin) + path_ = bin{a}; + if check_store_gs_path(path_) + return + end + end + % Search the obvious places + if ispc + default_location = 'C:\Program Files\gs\'; + dir_list = dir(default_location); + if isempty(dir_list) + default_location = 'C:\Program Files (x86)\gs\'; % Possible location on 64-bit systems + dir_list = dir(default_location); + end + executable = {'\bin\gswin32c.exe', '\bin\gswin64c.exe'}; + ver_num = 0; + % If there are multiple versions, use the newest + for a = 1:numel(dir_list) + ver_num2 = sscanf(dir_list(a).name, 'gs%g'); + if ~isempty(ver_num2) && ver_num2 > ver_num + for b = 1:numel(executable) + path2 = [default_location dir_list(a).name executable{b}]; + if exist(path2, 'file') == 2 + path_ = path2; + ver_num = ver_num2; + end + end + end + end + if check_store_gs_path(path_) + return + end + else + executable = {'/usr/bin/gs', '/usr/local/bin/gs'}; + for a = 1:numel(executable) + path_ = executable{a}; + if check_store_gs_path(path_) + return + end + end + end + % Ask the user to enter the path + while true + if strncmp(computer, 'MAC', 3) % Is a Mac + % Give separate warning as the uigetdir dialogue box doesn't have a + % title on MacOS + uiwait(warndlg('Ghostscript installation not found - please locate the program.', 'Ghostscript')) + base = uigetdir('/', 'Ghostcript program location'); + else + base = uigetdir('/', 'Ghostcript program not found - please locate it'); + end + if isequal(base, 0) + % User hit cancel or closed window + break; + end + base = [base filesep]; %#ok + bin_dir = {'', ['bin' filesep], ['lib' filesep]}; + for a = 1:numel(bin_dir) + for b = 1:numel(bin) + path_ = [base bin_dir{a} bin{b}]; + if exist(path_, 'file') == 2 + if check_store_gs_path(path_) + return + end + end + end + end + end + if ismac + url = 'http://pages.uoregon.edu/koch'; + else + url = 'http://ghostscript.com'; + end + error('Ghostscript:NotFound', 'Ghostscript not found. Have you installed it from %s ?', hyperlink(url)); +end + +function good = check_store_gs_path(path_) + % Check the path is valid + good = check_gs_path(path_); + if ~good + return + end + % Update the current default path to the path found + if ~user_string('ghostscript', path_) + %filename = fullfile(fileparts(which('user_string.m')), '.ignore', 'ghostscript.txt'); + [unused, filename] = user_string('ghostscript'); %#ok + warning('Ghostscript:path', 'Path to ghostscript installation could not be saved in %s (perhaps a permissions issue). You can manually create this file and set its contents to %s, to improve performance in future invocations (this warning is safe to ignore).', filename, path_); + return + end +end + +function good = check_gs_path(path_) + persistent isOk + if isempty(path_) + isOk = false; + elseif ~isequal(isOk,true) + % Check whether the path is valid + [status, message] = system([gs_command(path_) '-h']); %#ok + isOk = status == 0; + end + good = isOk; +end + +function cmd = gs_command(path_) + % Initialize any required system calls before calling ghostscript + % TODO: in Unix/Mac, find a way to automatically determine whether to use "export" (bash) or "setenv" (csh/tcsh) + shell_cmd = ''; + if isunix + shell_cmd = 'export LD_LIBRARY_PATH=""; '; % Avoids an error on Linux with GS 9.07 + end + if ismac + shell_cmd = 'export DYLD_LIBRARY_PATH=""; '; % Avoids an error on Mac with GS 9.07 + end + % Construct the command string + cmd = sprintf('%s"%s" ', shell_cmd, path_); +end diff --git a/matlab/export_fig/hyperlink.m b/matlab/export_fig/hyperlink.m new file mode 100644 index 0000000..c89fa3d --- /dev/null +++ b/matlab/export_fig/hyperlink.m @@ -0,0 +1,53 @@ +function str = hyperlink(url, label, msg) +%HYPERLINK create a string that is displayable as hyperlink in Matlab console +% +% Usage examples: +% fprintf('Search on %s\n', hyperlink('http://google.com','Google')); +% fprintf(hyperlink('http://google.com','Google','Search on Google\n')); +% +% HYPERLINK converts the specified URL and text label into a string that is +% displayed as a hyperlink in the Matlab console (Command Window). +% In a deployed (compiled) program, the URL and text label (if different +% from the URL) are displayed in a non-hyperlinked plain-text manner. +% If the optional 3rd input argument (msg) is specified, then all instances of +% the specified label within msg will be handled as above (hyperlinked etc.) +% +% IN: +% url - (mandatory) URL of webpage or Matlab command (e.g., 'matlab:which(...') +% label - (optional) text label of the hyperlink. Default: url +% msg - (optional) string in which all label instances should be hyperlinked +% +% OUT: +% str - string output + +% Copyright: Yair Altman 2020- +%{ +% 15/01/20 - Initial version +%} + + error(nargchk(1,3,nargin)); %#ok narginchk is only available in R2011b+ + if nargin > 2 % msg was specified + % replace all instances of label within msg with corresponding hyperlink + str = strrep(msg, label, hyperlink(url,label)); + return + end + if nargin < 2, label = url; end + isWebpage = strncmpi(url,'http',4); + + % Only hyperlink in interactive Matlab sessions, not in a deployed program + if ~isdeployed % interactive Matlab session + if isWebpage % open in a web browser + str = ['' label '']; + else % Matlab command e.g. 'matlab:which(...' + str = ['' label '']; + end + else % deployed (compiled) + if isWebpage && ~strcmp(label,url) % display label next to url + str = [label ' (' url ')']; + elseif isWebpage % text==url - display only the url + str = url; + else % Matlab command (not a webpage) - just display the label + str = label; + end + end +end diff --git a/matlab/export_fig/im2gif.m b/matlab/export_fig/im2gif.m new file mode 100644 index 0000000..4c0ff3d --- /dev/null +++ b/matlab/export_fig/im2gif.m @@ -0,0 +1,205 @@ +%IM2GIF Convert a multiframe image to an animated GIF file +% +% Examples: +% im2gif infile +% im2gif infile outfile +% im2gif(A, outfile) +% im2gif(..., '-nocrop') +% im2gif(..., '-nodither') +% im2gif(..., '-ncolors', n) +% im2gif(..., '-loops', n) +% im2gif(..., '-delay', n) +% +% This function converts a multiframe image to an animated GIF. +% +% To create an animation from a series of figures, export to a multiframe +% TIFF file using export_fig, then convert to a GIF, as follows: +% +% for a = 2 .^ (3:6) +% peaks(a); +% export_fig test.tif -nocrop -append +% end +% im2gif('test.tif', '-delay', 0.5); +% +%IN: +% infile - string containing the name of the input image. +% outfile - string containing the name of the output image (must have the +% .gif extension). Default: infile, with .gif extension. +% A - HxWxCxN array of input images, stacked along fourth dimension, to +% be converted to gif. +% -nocrop - option indicating that the borders of the output are not to +% be cropped. +% -nodither - option indicating that dithering is not to be used when +% converting the image. +% -ncolors - option pair, the value of which indicates the maximum number +% of colors the GIF can have. This can also be a quantization +% tolerance, between 0 and 1. Default/maximum: 256. +% -loops - option pair, the value of which gives the number of times the +% animation is to be looped. Default: 65535. +% -delay - option pair, the value of which gives the time, in seconds, +% between frames. Default: 1/15. + +% Copyright (C) Oliver Woodford 2011 + +%{ +% 14/02/18: Merged issue #235: reduced memory usage, improved performance (thanks to @numb7rs) +% 30/11/19: Merged issue #288: Fix im2gif.m for greyscale TIFF images (thanks @Blackbelt1221) +%} + +function im2gif(A, varargin) + + % Parse the input arguments + [A, options] = parse_args(A, varargin{:}); + + if options.crop ~= 0 + % Crop + A = crop_borders(A, A(ceil(end/2),1,:,1)); + end + + % Convert to indexed image + [h, w, c, n] = size(A); + + % Issue #235: Using unique(A,'rows') on the whole image stack at once causes + % massive memory usage when dealing with large images (at least on Matlab 2017b). + % Running unique(...) on individual frames, then again on the results drastically + % reduces the memory usage & slightly improves the execution time (@numb7rs). + uns = cell(1,size(A,4)); + for nn=1:size(A,4) + uns{nn}=unique(reshape(A(:,:,:,nn), h*w, c),'rows'); + end + map=unique(cell2mat(uns'),'rows'); + + A = reshape(permute(A, [1 2 4 3]), h, w*n, c); + + if size(map, 1) > 256 + dither_str = {'dither', 'nodither'}; + dither_str = dither_str{1+(options.dither==0)}; + if options.ncolors <= 1 + [B, map] = rgb2ind(A, options.ncolors, dither_str); + if size(map, 1) > 256 + [B, map] = rgb2ind(A, 256, dither_str); + end + else + [B, map] = rgb2ind(A, min(round(options.ncolors), 256), dither_str); + end + else + if max(map(:)) > 1 + map = double(map) / 255; + A = double(A) / 255; + end + B = rgb2ind(im2double(A), map); + end + B = reshape(B, h, w, 1, n); + + % Bug fix to rgb2ind + map(B(1)+1,:) = im2double(A(1,1,:)); + + % Save as a gif + imwrite(B, map, options.outfile, 'LoopCount', round(options.loops(1)), 'DelayTime', options.delay); +end + +%% Parse the input arguments +function [A, options] = parse_args(A, varargin) + % Set the defaults + options = struct('outfile', '', ... + 'dither', true, ... + 'crop', true, ... + 'ncolors', 256, ... + 'loops', 65535, ... + 'delay', 1/15); + + % Go through the arguments + a = 0; + n = numel(varargin); + while a < n + a = a + 1; + if ischar(varargin{a}) && ~isempty(varargin{a}) + if varargin{a}(1) == '-' + opt = lower(varargin{a}(2:end)); + switch opt + case 'nocrop' + options.crop = false; + case 'nodither' + options.dither = false; + otherwise + if ~isfield(options, opt) + error('Option %s not recognized', varargin{a}); + end + a = a + 1; + if ischar(varargin{a}) && ~ischar(options.(opt)) + options.(opt) = str2double(varargin{a}); + else + options.(opt) = varargin{a}; + end + end + else + options.outfile = varargin{a}; + end + end + end + + if isempty(options.outfile) + if ~ischar(A) + error('No output filename given.'); + end + % Generate the output filename from the input filename + [path, outfile] = fileparts(A); + options.outfile = fullfile(path, [outfile '.gif']); + end + + if ischar(A) + % Read in the image + A = imread_rgb(A); + end +end + +%% Read image to uint8 rgb array +function [A, alpha] = imread_rgb(name) + % Get file info + info = imfinfo(name); + % Special case formats + switch lower(info(1).Format) + case 'gif' + [A, map] = imread(name, 'frames', 'all'); + if ~isempty(map) + map = uint8(map * 256 - 0.5); % Convert to uint8 for storage + A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0 + A = permute(A, [1 2 5 4 3]); + end + case {'tif', 'tiff'} + A = cell(numel(info), 1); + for a = 1:numel(A) + [A{a}, map] = imread(name, 'Index', a, 'Info', info); + if ~isempty(map) + map = uint8(map * 256 - 0.5); % Convert to uint8 for storage + A{a} = reshape(map(uint32(A{a})+1,:), [size(A) size(map, 2)]); % Assume indexed from 0 + end + if size(A{a}, 3) == 4 + % TIFF in CMYK colourspace - convert to RGB + if isfloat(A{a}) + A{a} = A{a} * 255; + else + A{a} = single(A{a}); + end + A{a} = 255 - A{a}; + A{a}(:,:,4) = A{a}(:,:,4) / 255; + A{a} = uint8(A(:,:,1:3) .* A{a}(:,:,[4 4 4])); + elseif size(A{a}, 3) < 3 %Check whether TIFF has been read in as greyscale + %Convert from greyscale to RGB colorspace (issue #288) + A{a} = cat(3, A{a}, A{a}, A{a}); + end + end + A = cat(4, A{:}); + otherwise + [A, map, alpha] = imread(name); + A = A(:,:,:,1); % Keep only first frame of multi-frame files + if ~isempty(map) + map = uint8(map * 256 - 0.5); % Convert to uint8 for storage + A = reshape(map(uint32(A)+1,:), [size(A) size(map, 2)]); % Assume indexed from 0 + elseif size(A, 3) == 4 + % Assume 4th channel is an alpha matte + alpha = A(:,:,4); + A = A(:,:,1:3); + end + end +end diff --git a/matlab/export_fig/isolate_axes.m b/matlab/export_fig/isolate_axes.m new file mode 100644 index 0000000..fe3ada3 --- /dev/null +++ b/matlab/export_fig/isolate_axes.m @@ -0,0 +1,155 @@ +function fh = isolate_axes(ah, vis) +%ISOLATE_AXES Isolate the specified axes in a figure on their own +% +% Examples: +% fh = isolate_axes(ah) +% fh = isolate_axes(ah, vis) +% +% This function will create a new figure containing the axes/uipanels +% specified, and also their associated legends and colorbars. The objects +% specified must all be in the same figure, but they will generally only be +% a subset of the objects in the figure. +% +% IN: +% ah - An array of axes and uipanel handles, which must come from the +% same figure. +% vis - A boolean indicating whether the new figure should be visible. +% Default: false. +% +% OUT: +% fh - The handle of the created figure. + +% Copyright (C) Oliver Woodford 2011-2014, Yair Altman 2015- +%{ +% Thank you to Rosella Blatt for reporting a bug to do with axes in GUIs +% 16/03/12: Moved copyfig to its own function. Thanks to Bob Fratantonio +% for pointing out that the function is also used in export_fig.m +% 12/12/12: Add support for isolating uipanels. Thanks to michael for suggesting it +% 08/10/13: Bug fix to allchildren suggested by Will Grant (many thanks!) +% 05/12/13: Bug fix to axes having different units. Thanks to Remington Reid for reporting +% 21/04/15: Bug fix for exporting uipanels with legend/colorbar on HG1 (reported by Alvaro +% on FEX page as a comment on 24-Apr-2014); standardized indentation & help section +% 22/04/15: Bug fix: legends and colorbars were not exported when exporting axes handle in HG2 +% 02/02/21: Fix axes, figure size to preserve input axes image resolution (thanks @Optecks) +% 25/10/21: Bug fix: subplots were not isolated properly leading to print error (issue #347) +%} + + % Make sure we have an array of handles + if ~all(ishandle(ah)) + error('ah must be an array of handles'); + end + + % Check that the handles are all for axes or uipanels, and are all in the same figure + fh = ancestor(ah(1), 'figure'); + nAx = numel(ah); + for a = 1:nAx + if ~ismember(get(ah(a), 'Type'), {'axes', 'uipanel'}) + error('All handles must be axes or uipanel handles.'); + end + if ~isequal(ancestor(ah(a), 'figure'), fh) + error('Axes must all come from the same figure.'); + end + end + + % Tag the objects so we can find them in the copy + old_tag = get(ah, 'Tag'); + if nAx == 1 + old_tag = {old_tag}; + end + set(ah, 'Tag', 'ObjectToCopy'); + + % Create a new figure exactly the same as the old one + fh = copyfig(fh); %copyobj(fh, 0); + + % Fix Axes & Figure size for image catpuring to have almost exact resolution + % of the Input Axes (thanks @Optecks) + allaxes = findall(fh, 'type', 'axes'); + if ~isempty(ah) + sz = get(ah(1), 'OuterPosition'); + un = get(ah(1), 'Units'); + set(allaxes(1), 'Units',un, 'OuterPosition', [0 0 sz(3) sz(4)]); + set(allaxes(1), 'Units','pixels'); + sz = get(allaxes(1), 'OuterPosition'); + set(fh, 'Units','pixels', 'Position',[0 0 sz(3) sz(4)]+1); + end + + if nargin < 2 || ~vis + set(fh, 'Visible', 'off'); + end + + % Reset the object tags + for a = 1:nAx + set(ah(a), 'Tag', old_tag{a}); + end + + % Find the objects to save + ah = findall(fh, 'Tag', 'ObjectToCopy'); + if numel(ah) ~= nAx + close(fh); + error('Incorrect number of objects found.'); + end + + % Set the axes tags to what they should be + for a = 1:nAx + set(ah(a), 'Tag', old_tag{a}); + end + + % Keep any legends and colorbars which overlap the subplots + % Note: in HG1 these are axes objects; in HG2 they are separate objects, therefore we + % don't test for the type, only the tag (hopefully nobody but Matlab uses them!) + lh = findall(fh, 'Tag','legend', '-or', 'Tag','Colorbar'); + nLeg = numel(lh); + if nLeg > 0 + set([ah(:); lh(:)], 'Units', 'normalized'); + try + ax_pos = get(ah, 'OuterPosition'); % axes and figures have the OuterPosition property + catch + ax_pos = get(ah, 'Position'); % uipanels only have Position, not OuterPosition + end + if nAx > 1 + ax_pos = cell2mat(ax_pos(:)); + end + ax_pos(:,3:4) = ax_pos(:,3:4) + ax_pos(:,1:2); + try + leg_pos = get(lh, 'OuterPosition'); + catch + leg_pos = get(lh, 'Position'); % No OuterPosition in HG2, only in HG1 + end + if nLeg > 1 + leg_pos = cell2mat(leg_pos); + end + leg_pos(:,3:4) = leg_pos(:,3:4) + leg_pos(:,1:2); + ax_pos = shiftdim(ax_pos, -1); + % Overlap test + M = bsxfun(@lt, leg_pos(:,1), ax_pos(:,:,3)) & ... + bsxfun(@lt, leg_pos(:,2), ax_pos(:,:,4)) & ... + bsxfun(@gt, leg_pos(:,3), ax_pos(:,:,1)) & ... + bsxfun(@gt, leg_pos(:,4), ax_pos(:,:,2)); + ah = [ah; lh(any(M, 2))]; + end + + % Get all the objects in the figure + axs = findall(fh); + + % Delete everything except for the input objects and associated items + delete(axs(~ismember(axs, [ah; allchildren(ah); allancestors(ah)]))); +end + +function ah = allchildren(ah) + ah = findall(ah); + if iscell(ah) + ah = cell2mat(ah); + end + ah = ah(:); +end + +function ph = allancestors(ah) + ph = []; + for a = 1:numel(ah) + h = get(ah(a), 'parent'); + while h ~= 0 + ph = [ph; h]; %#ok + h = get(h, 'parent'); + end + end +end diff --git a/matlab/export_fig/pdf2eps.m b/matlab/export_fig/pdf2eps.m new file mode 100644 index 0000000..8010b2a --- /dev/null +++ b/matlab/export_fig/pdf2eps.m @@ -0,0 +1,55 @@ +%PDF2EPS Convert a pdf file to eps format using pdftops +% +% Examples: +% pdf2eps source dest +% +% This function converts a pdf file to eps format. +% +% This function requires that you have pdftops, from the Xpdf suite of +% functions, installed on your system. This can be downloaded from: +% http://xpdfreader.com +% +% Inputs: +% source - filename of the source pdf file to convert. The filename is +% assumed to already have the extension ".pdf". +% dest - filename of the destination eps file. The filename is assumed to +% already have the extension ".eps". + +% Copyright (C) Oliver Woodford 2009-2010, Yair Altman 2015- + +% Thanks to Aldebaro Klautau for reporting a bug when saving to +% non-existant directories. + +% 22/09/2018 - Xpdf website changed to xpdfreader.com + +function pdf2eps(source, dest) + % Construct the options string for pdftops + options = ['-q -paper match -eps -level2 "' source '" "' dest '"']; + + % Convert to eps using pdftops + [status, message] = pdftops(options); + + % Check for error + if status + % Report error + if isempty(message) + error('Unable to generate eps. Check destination directory is writable.'); + else + error(message); + end + end + + % Fix the DSC error created by pdftops + fid = fopen(dest, 'r+'); + if fid == -1 + % Cannot open the file + return + end + fgetl(fid); % Get the first line + str = fgetl(fid); % Get the second line + if strcmp(str(1:min(13, end)), '% Produced by') + fseek(fid, -numel(str)-1, 'cof'); + fwrite(fid, '%'); % Turn ' ' into '%' + end + fclose(fid); +end diff --git a/matlab/export_fig/pdftops.m b/matlab/export_fig/pdftops.m new file mode 100644 index 0000000..076dd75 --- /dev/null +++ b/matlab/export_fig/pdftops.m @@ -0,0 +1,186 @@ +function varargout = pdftops(cmd) +%PDFTOPS Calls a local pdftops executable with the input command +% +% Example: +% [status result] = pdftops(cmd) +% +% Attempts to locate a pdftops executable, finally asking the user to +% specify the directory pdftops was installed into. The resulting path is +% stored for future reference. +% +% Once found, the executable is called with the input command string. +% +% This function requires that you have pdftops (from the Xpdf package) +% installed on your system. You can download this from: http://xpdfreader.com +% +% IN: +% cmd - Command string to be passed into pdftops (e.g. '-help'). +% +% OUT: +% status - 0 iff command ran without problem. +% result - Output from pdftops. + +% Copyright: Oliver Woodford, 2009-2010 + +% Thanks to Jonas Dorn for the fix for the title of the uigetdir window on Mac OS. +% Thanks to Christoph Hertel for pointing out a bug in check_xpdf_path under linux. +% 23/01/2014 - Add full path to pdftops.txt in warning. +% 27/05/2015 - Fixed alert in case of missing pdftops; fixed code indentation +% 02/05/2016 - Added possible error explanation suggested by Michael Pacer (issue #137) +% 02/05/2016 - Search additional possible paths suggested by Jonas Stein (issue #147) +% 03/05/2016 - Display the specific error message if pdftops fails for some reason (issue #148) +% 22/09/2018 - Xpdf website changed to xpdfreader.com; improved popup logic +% 03/02/2019 - Fixed one-off 'pdftops not found' error after install (Mac/Linux) (issue #266) +% 15/01/2020 - Fixed reported path of pdftops.txt file in case of error; added warning ID +% 23/07/2020 - Fixed issue #311 (confusion regarding Xpdf-tools download/installation); silent check of pdftops installation in case no input arg specified + + % If no command parameter specified, just check pdftops installation and bail out + if nargin < 1 + xpdf_path(); % this will error if pdftops is not found + return % silent bail-out if pdftops was successfully located + end + + % Call pdftops + [varargout{1:nargout}] = system([xpdf_command(xpdf_path()) cmd]); +end + +function path_ = xpdf_path + % Return a valid path + % Start with the currently set path + path_ = user_string('pdftops'); + % Check the path works + if check_xpdf_path(path_) + return + end + % Check whether the binary is on the path + if ispc + bin = 'pdftops.exe'; + else + bin = 'pdftops'; + end + if check_store_xpdf_path(bin) + path_ = bin; + return + end + % Search the obvious places + if ispc + paths = {'C:\Program Files\xpdf\pdftops.exe', 'C:\Program Files (x86)\xpdf\pdftops.exe'}; + else + paths = {'/usr/bin/pdftops', '/usr/local/bin/pdftops'}; + end + for a = 1:numel(paths) + path_ = paths{a}; + if check_store_xpdf_path(path_) + return + end + end + + % Ask the user to enter the path + errMsg1 = 'Pdftops utility not found. Please locate the program, or install xpdf-tools from '; + url1 = 'http://xpdfreader.com/download.html'; %='http://foolabs.com/xpdf'; + fprintf(2, '%s%s ("Xpdf command line tools" section)\n', errMsg1, hyperlink(url1)); + errMsg1 = [errMsg1 url1]; + %if strncmp(computer,'MAC',3) % Is a Mac + % % Give separate warning as the MacOS uigetdir dialogue box doesn't have a title + % uiwait(warndlg(errMsg1)) + %end + + % Provide an alternative possible explanation as per issue #137 + errMsg2 = 'If pdftops is installed, maybe Matlab is shaddowing it, as described in '; + url2 = 'https://github.com/altmany/export_fig/issues/137'; + fprintf(2, '%s%s\n', errMsg2, hyperlink(url2,'issue #137')); + errMsg2 = [errMsg2 url2]; + + % Provide an alternative possible explanation as per issue #311 + errMsg3 = 'Or perhaps you installed XpdfReader but not xpdf-tools, as described in '; + url3 = 'https://github.com/altmany/export_fig/issues/311'; + fprintf(2, '%s%s\n', errMsg3, hyperlink(url3,'issue #311')); + errMsg3 = [errMsg3 url3]; + + state = 1; + while 1 + if state + option1 = 'Install pdftops'; + else + option1 = 'Issue #137'; + end + answer = questdlg({errMsg1,'',errMsg2,'',errMsg3},'Pdftops error',option1,'Locate pdftops','Cancel','Cancel'); + drawnow; % prevent a Matlab hang: http://undocumentedmatlab.com/blog/solving-a-matlab-hang-problem + switch answer + case 'Install pdftops' + web('-browser',url1); + state = 0; + case 'Issue #137' + web('-browser',url2); + state = 1; + case 'Locate pdftops' + base = uigetdir('/', errMsg1); + if isequal(base, 0) + % User hit cancel or closed window + break + end + base = [base filesep]; %#ok + bin_dir = {'', ['bin' filesep], ['lib' filesep]}; + for a = 1:numel(bin_dir) + path_ = [base bin_dir{a} bin]; + if exist(path_, 'file') == 2 + break + end + end + if check_store_xpdf_path(path_) + return + end + + otherwise % User hit Cancel or closed window + break + end + end + error('pdftops executable not found.'); +end + +function good = check_store_xpdf_path(path_) + % Check the path is valid + good = check_xpdf_path(path_); + if ~good + return + end + % Update the current default path to the path found + if ~user_string('pdftops', path_) + %filename = fullfile(fileparts(which('user_string.m')), '.ignore', 'pdftops.txt'); + [unused, filename] = user_string('pdftops'); %#ok + warning('export_fig:pdftops','Path to pdftops executable could not be saved. Enter it manually in %s.', filename); + return + end +end + +function good = check_xpdf_path(path_) + % Check the path is valid + [good, message] = system([xpdf_command(path_) '-h']); %#ok + % system returns good = 1 even when the command runs + % Look for something distinct in the help text + good = ~isempty(strfind(message, 'PostScript')); %#ok + + % Display the error message if the pdftops executable exists but fails for some reason + % Note: on Mac/Linux, exist('pdftops','file') will always return 2 due to pdftops.m => check for '/','.' (issue #266) + if ~good && exist(path_,'file') && ~isempty(regexp(path_,'[/.]')) %#ok % file exists but generates an error + fprintf('Error running %s:\n', path_); + fprintf(2,'%s\n\n',message); + end +end + +function cmd = xpdf_command(path_) + % Initialize any required system calls before calling ghostscript + % TODO: in Unix/Mac, find a way to determine whether to use "export" (bash) or "setenv" (csh/tcsh) + shell_cmd = ''; + if isunix + % Avoids an error on Linux with outdated MATLAB lib files + % R20XXa/bin/glnxa64/libtiff.so.X + % R20XXa/sys/os/glnxa64/libstdc++.so.X + shell_cmd = 'export LD_LIBRARY_PATH=""; '; + end + if ismac + shell_cmd = 'export DYLD_LIBRARY_PATH=""; '; + end + % Construct the command string + cmd = sprintf('%s"%s" ', shell_cmd, path_); +end diff --git a/matlab/export_fig/print2array.m b/matlab/export_fig/print2array.m new file mode 100644 index 0000000..91cf719 --- /dev/null +++ b/matlab/export_fig/print2array.m @@ -0,0 +1,381 @@ +function [A, bcol, alpha] = print2array(fig, res, renderer, gs_options) +%PRINT2ARRAY Exports a figure to a bitmap RGB image array +% +% Examples: +% A = print2array +% A = print2array(figure_handle) +% A = print2array(figure_handle, resolution) +% A = print2array(figure_handle, resolution, renderer) +% A = print2array(figure_handle, resolution, renderer, gs_options) +% [A, bcol, alpha] = print2array(...) +% +% This function outputs a bitmap image of a figure, at the desired resolution. +% +% When resolution==1, fast Java screen-capture is attempted first. +% If the Java screen-capture fails or if resolution~=1, the builtin print() +% function is used to create a temp TIF file, which is then loaded and reported. +% If this fails, print() is used to create a temp EPS file which is converted to +% a TIF file using Ghostcript (http://www.ghostscript.com), loaded and reported. +% +% Inputs: +% figure_handle - The handle of the figure to be exported. Default: gcf. +% resolution - Output resolution as a factor of screen resolution. Default: 1 +% Note: resolution ~= 1 uses a slow print to/from image file +% renderer - The renderer to be used by print() function. Default: '-opengl' +% Note: only used when resolution ~= 1 +% gs_options - optional ghostscript parameters (e.g.: '-dNoOutputFonts'). +% Enclose multiple options in a cell array, e.g. {'-a','-b'} +% Note: only used when resolution ~= 1 and basic print() fails +% +% Outputs: +% A - MxNx3 uint8 bitmap image of the figure (MxN pixels x 3 RGB values) +% bcol - 1x3 uint8 vector of the background RGB color +% alpha - MxN uint8 array of alpha values (between 0=transparent, 255=opaque) + +% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015- +%{ +% 05/09/11: Set EraseModes to normal when using opengl or zbuffer +% renderers. Thanks to Pawel Kocieniewski for reporting the issue. +% 21/09/11: Bug fix: unit8 -> uint8! Thanks to Tobias Lamour for reporting it. +% 14/11/11: Bug fix: stop using hardcopy(), as it interfered with figure size +% and erasemode settings. Makes it a bit slower, but more reliable. +% Thanks to Phil Trinh and Meelis Lootus for reporting the issues. +% 09/12/11: Pass font path to ghostscript. +% 27/01/12: Bug fix affecting painters rendering tall figures. Thanks to +% Ken Campbell for reporting it. +% 03/04/12: Bug fix to median input. Thanks to Andy Matthews for reporting it. +% 26/10/12: Set PaperOrientation to portrait. Thanks to Michael Watts for +% reporting the issue. +% 26/02/15: If temp dir is not writable, use the current folder for temp +% EPS/TIF files (Javier Paredes) +% 27/02/15: Display suggested workarounds to internal print() error (issue #16) +% 28/02/15: Enable users to specify optional ghostscript options (issue #36) +% 10/03/15: Fixed minor warning reported by Paul Soderlind; fixed code indentation +% 28/05/15: Fixed issue #69: patches with LineWidth==0.75 appear wide (internal bug in Matlab's print() func) +% 07/07/15: Fixed issue #83: use numeric handles in HG1 +% 11/12/16: Fixed cropping issue reported by Harry D. +% 29/09/18: Fixed issue #254: error in print2array>read_tif_img +% 22/03/20: Alert if ghostscript.m is required but not found on Matlab path +% 24/05/20: Significant performance speedup; added alpha values (where possible) +% 07/07/20: Fixed issue #308: bug in R2019a and earlier +% 07/10/20: Use JavaFrame_I where possible, to avoid evoking a JavaFrame warning +% 07/03/21: Fixed edge-case in case a non-figure handle was provided as input arg +% 10/03/21: Forced a repaint at top of function to ensure accurate image snapshot (issue #211) +% 26/08/21: Added a short pause to avoid unintended image cropping (issue #318) +% 25/10/21: Avoid duplicate error message when retrying print2array with different resolution; display internal print error message +% 19/12/21: Speedups; fixed exporting non-current figure (hopefully fixes issue #318) +% 22/12/21: Avoid memory leak during screen-capture +%} + + % Generate default input arguments, if needed + if nargin < 1, fig = gcf; end + if nargin < 2, res = 1; end + + % Force a repaint to ensure we get an accurate snapshot image (issue #211) + drawnow + + % Get the figure size in pixels + old_mode = get(fig, 'Units'); + set(fig, 'Units', 'pixels'); + px = get(fig, 'Position'); + set(fig, 'Units', old_mode); + + pause(0.02); % add a short pause to avoid unintended cropping (issue #318) + + % Retrieve the background colour + bcol = get(fig, 'Color'); + try + % Try a direct Java screen-capture first - *MUCH* faster than print() to file + % Note: we could also use A=matlab.graphics.internal.getframeWithDecorations(fig,false) but it (1) returns no alpha and (2) does not exist in older Matlabs + if res == 1 + [A, alpha] = getJavaImage(fig); + else + error('magnify/downscale via print() to image file and then import'); + end + catch err %#ok + % Warn if output is large + npx = prod(px(3:4)*res)/1e6; + if npx > 30 + % 30M pixels or larger! + warning('MATLAB:LargeImage', 'print2array generating a %.1fM pixel image. This could be slow and might also cause memory problems.', npx); + end + % Set the resolution parameter + res_str = ['-r' num2str(ceil(get(0, 'ScreenPixelsPerInch')*res))]; + % Generate temporary file name + tmp_nam = [tempname '.tif']; + try + % Ensure that the temp dir is writable (Javier Paredes 26/2/15) + fid = fopen(tmp_nam,'w'); + fwrite(fid,1); + fclose(fid); + delete(tmp_nam); % cleanup + isTempDirOk = true; + catch + % Temp dir is not writable, so use the current folder + [dummy,fname,fext] = fileparts(tmp_nam); %#ok + fpath = pwd; + tmp_nam = fullfile(fpath,[fname fext]); + isTempDirOk = false; + end + % Enable users to specify optional ghostscript options (issue #36) + isRetry = false; + if nargin > 3 && ~isempty(gs_options) + if isequal(gs_options,'retry') + isRetry = true; + gs_options = ''; + elseif iscell(gs_options) + gs_options = sprintf(' %s',gs_options{:}); + elseif ~ischar(gs_options) + error('gs_options input argument must be a string or cell-array of strings'); + else + gs_options = [' ' gs_options]; + end + else + gs_options = ''; + end + if nargin > 2 && strcmp(renderer, '-painters') + % First try to print directly to image file + try + % Print the file into a temporary image file and read it into array A + [A, alpha, err, ex] = getPrintImage(fig, res_str, renderer, tmp_nam); + if err, rethrow(ex); end + catch % error - try to print to EPS and then using Ghostscript to TIF + % Ensure that ghostscript() exists on the Matlab path + if ~exist('ghostscript','file') && isempty(which('ghostscript')) + error('export_fig:print2array:ghostscript', 'The ghostscript.m function is required by print2array.m. Install the complete export_fig package from https://www.mathworks.com/matlabcentral/fileexchange/23629-export_fig or https://github.com/altmany/export_fig') + end + % Print to eps file + if isTempDirOk + tmp_eps = [tempname '.eps']; + else + tmp_eps = fullfile(fpath,[fname '.eps']); + end + print2eps(tmp_eps, fig, 0, renderer, '-loose'); + try + % Initialize the command to export to tiff using ghostscript + cmd_str = ['-dEPSCrop -q -dNOPAUSE -dBATCH ' res_str ' -sDEVICE=tiff24nc']; + % Set the font path + fp = font_path(); + if ~isempty(fp) + cmd_str = [cmd_str ' -sFONTPATH="' fp '"']; + end + % Add the filenames + cmd_str = [cmd_str ' -sOutputFile="' tmp_nam '" "' tmp_eps '"' gs_options]; + % Execute the ghostscript command + ghostscript(cmd_str); + catch me + % Delete the intermediate file + delete(tmp_eps); + rethrow(me); + end + % Delete the intermediate file + delete(tmp_eps); + % Read in the generated bitmap + A = imread(tmp_nam); + % Delete the temporary bitmap file + delete(tmp_nam); + end + else + if nargin < 3 + renderer = '-opengl'; + end + % Print the file into a temporary image file and read it into array A + [A, alpha, err, ex] = getPrintImage(fig, res_str, renderer, tmp_nam); + % Throw any error that occurred + if err + % Display suggested workarounds to internal print() error (issue #16) + if ~isRetry + fprintf(2, 'An error occurred in Matlab''s builtin print function:\n%s\nTry setting the figure Renderer to ''painters'' or use opengl(''software'').\n\n', ex.message); + end + rethrow(ex); + end + end + end + + % Set the background color + if isequal(bcol, 'none') + bcol = squeeze(A(1,1,:)); + if ~all(bcol==0) %if not black + bcol = [255,255,255]; %=white %=[]; + end + else + if all(bcol <= 1) + bcol = bcol * 255; + end + if ~isequal(bcol, round(bcol)) + bcol = squeeze(A(1,1,:)); + %{ + % Set border pixels to the correct colour + for l = 1:size(A, 2) + if ~all(reshape(A(:,l,:) == 255, [], 1)) + break; + end + end + for r = size(A, 2):-1:l + if ~all(reshape(A(:,r,:) == 255, [], 1)) + break; + end + end + for t = 1:size(A, 1) + if ~all(reshape(A(t,:,:) == 255, [], 1)) + break; + end + end + for b = size(A, 1):-1:t + if ~all(reshape(A(b,:,:) == 255, [], 1)) + break; + end + end + bcol = median(single([reshape(A(:,[l r],:), [], size(A, 3)); ... + reshape(A([t b],:,:), [], size(A, 3))]), 1)); + for c = 1:size(A, 3) + A(:,[1:l-1, r+1:end],c) = bcol(c); + A([1:t-1, b+1:end],:,c) = bcol(c); + end + %} + end + end + bcol = uint8(bcol); + + % Ensure that the output size is correct + if isequal(res, round(res)) + px = round([px([4 3])*res 3]); % round() to avoid an indexing warning below + if any(size(A) > px) %~isequal(size(A), px) + A = A(1:min(end,px(1)),1:min(end,px(2)),:); + end + if any(size(alpha) > px(1:2)) + alpha = alpha(1:min(end,px(1)),1:min(end,px(2))); + end + end +end + +% Get the Java-based screen-capture of the figure's JFrame content-panel +function [imgData, alpha] = getJavaImage(hFig) + % Get the figure's underlying Java frame + oldWarn = warning('off','MATLAB:HandleGraphics:ObsoletedProperty:JavaFrame'); + warning('off','MATLAB:ui:javaframe:PropertyToBeRemoved'); + try + jf = get(handle(hFig),'JavaFrame_I'); + catch + jf = get(handle(hFig),'JavaFrame'); %#ok + end + warning(oldWarn); + + % Get the Java frame's root frame handle + %jframe = jf.getFigurePanelContainer.getComponent(0).getRootPane.getParent; + try + jClient = jf.fHG2Client; % This works from R2014b and up + catch + try + jClient = jf.fHG1Client; % This works from R2008b-R2014a + catch + jClient = jf.fFigureClient; % This works up to R2011a + end + end + + % Get the content-pane + try + jPanel = jClient.getContentPane; + catch + jPanel = jClient.getFigurePanelContainer; + end + jPanel.repaint; + w = jPanel.getWidth; + h = jPanel.getHeight; + + % Create a BufferedImage and paint the content-pane into it + % (https://coderanch.com/t/470601/java/screenshot-JPanel) + % Note: contrary to documentation and common-sense, it turns out that TYPE_INT_RGB + % ^^^^ returns non-opaque alpha, while TYPE_INT_ARGB only returns 255s in the alpha channel + jOriginalGraphics = jPanel.getGraphics; + import java.awt.image.BufferedImage + try TYPE_INT_RGB = BufferedImage.TYPE_INT_RGB; catch, TYPE_INT_RGB = 1; end + jImage = BufferedImage(w, h, TYPE_INT_RGB); + jGraphics = jImage.createGraphics; + jPanel.paint(jGraphics); + jPanel.paint(jOriginalGraphics); % repaint original figure to avoid a blank window + + % Extract the RGB pixels from the BufferedImage (see screencapture.m) + pixelsData = reshape(typecast(jImage.getData.getDataStorage, 'uint8'), 4, w, h); + imgData = cat(3, ... + transpose(reshape(pixelsData(3, :, :), w, h)), ... + transpose(reshape(pixelsData(2, :, :), w, h)), ... + transpose(reshape(pixelsData(1, :, :), w, h))); + + % And now also the alpha channel (if available) + alpha = transpose(reshape(pixelsData(4, :, :), w, h)); + + % Avoid memory leaks (see \toolbox\matlab\toolstrip\+matlab\+ui\+internal\+toolstrip\Icon.m>localFromImgToURL) + jGraphics.dispose(); + + % Ensure that the results are the expected size, otherwise raise an error + figSize = getpixelposition(hFig); + expectedSize = [figSize(4), figSize(3), 3]; + if ~isequal(expectedSize, size(imgData)) + error('bad Java screen-capture size!') + end +end + +% Export an image file of the figure using print() and then read it into an array +function [imgData, alpha, err, ex] = getPrintImage(fig, res_str, renderer, tmp_nam) + imgData = []; % fix for issue #254 + err = false; + ex = []; + alpha = []; + % Temporarily set the paper size + fig = ancestor(fig, 'figure'); % just in case it's not a figure... + old_pos_mode = get(fig, 'PaperPositionMode'); + old_orientation = get(fig, 'PaperOrientation'); + set(fig, 'PaperPositionMode','auto', 'PaperOrientation','portrait'); + try + % Workaround for issue #69: patches with LineWidth==0.75 appear wide (internal bug in Matlab's print() function) + fp = []; % in case we get an error below + fp = findall(fig, 'Type','patch', 'LineWidth',0.75); + set(fp, 'LineWidth',0.5); + try %if using_hg2(fig) % HG2 (R2014b or newer) + % Use print('-RGBImage') directly (a bit faster than via temp image file) + imgData = print(fig, renderer, res_str, '-RGBImage'); + catch %else % HG1 (R2014a or older) + % Fix issue #83: use numeric handles in HG1 + fig = double(fig); + % Print to image file + print(fig, renderer, res_str, '-dtiff', tmp_nam); + imgData = imread(tmp_nam); + % Delete the temporary file + delete(tmp_nam); + end + imgSize = size(imgData); imgSize = imgSize([1,2]); % Fix issue #308 + alpha = 255 * ones(imgSize, 'uint8'); % =all pixels opaque + catch ex + err = true; + end + if ~isempty(fp) % this check is not really needed, but makes the code cleaner + set(fp, 'LineWidth',0.75); % restore original figure appearance + end + % Reset the paper size + set(fig, 'PaperPositionMode',old_pos_mode, 'PaperOrientation',old_orientation); +end + +% Return (and create, where necessary) the font path (for use by ghostscript) +function fp = font_path() + fp = user_string('gs_font_path'); + if ~isempty(fp) + return + end + % Create the path + % Start with the default path + fp = getenv('GS_FONTPATH'); + % Add on the typical directories for a given OS + if ispc + if ~isempty(fp) + fp = [fp ';']; + end + fp = [fp getenv('WINDIR') filesep 'Fonts']; + else + if ~isempty(fp) + fp = [fp ':']; + end + fp = [fp '/usr/share/fonts:/usr/local/share/fonts:/usr/share/fonts/X11:/usr/local/share/fonts/X11:/usr/share/fonts/truetype:/usr/local/share/fonts/truetype']; + end + user_string('gs_font_path', fp); +end diff --git a/matlab/export_fig/print2eps.m b/matlab/export_fig/print2eps.m new file mode 100644 index 0000000..8f42fef --- /dev/null +++ b/matlab/export_fig/print2eps.m @@ -0,0 +1,672 @@ +function print2eps(name, fig, export_options, varargin) +%PRINT2EPS Prints figures to eps with improved line styles +% +% Examples: +% print2eps filename +% print2eps(filename, fig_handle) +% print2eps(filename, fig_handle, export_options) +% print2eps(filename, fig_handle, export_options, print_options) +% +% This function saves a figure as an eps file, with two improvements over +% MATLAB's print command. First, it improves the line style, making dashed +% lines more like those on screen and giving grid lines a dotted line style. +% Secondly, it substitutes original font names back into the eps file, +% where these have been changed by MATLAB, for up to 11 different fonts. +% +% Inputs: +% filename - string containing the name (optionally including full or +% relative path) of the file the figure is to be saved as. A +% ".eps" extension is added if not there already. If a path is +% not specified, the figure is saved in the current directory. +% fig_handle - The handle of the figure to be saved. Default: gcf(). +% export_options - array or struct of optional values: +% bb_padding - Scalar value of amount of padding to add to border around +% the cropped image, in points (if >1) or percent (if <1). +% Can be negative as well as positive; Default: 0 +% crop - Cropping flag. Deafult: 0 +% fontswap - Whether to swap non-default fonts in figure. Default: true +% preserve_size - Whether to preserve the figure's PaperSize. Default: false +% font_space - Character used to separate font-name terms in the EPS output +% e.g. "Courier New" => "Courier-New". Default: '' +% (available only via the struct alternative) +% renderer - Renderer used to generate bounding-box. Default: 'opengl' +% (available only via the struct alternative) +% crop_amounts - 4-element vector of crop amounts: [top,right,bottom,left] +% (available only via the struct alternative) +% regexprep - 2-element cell-array of regular-expression replacement in the +% generated EPS. 1st element is the replaced string(s), 2nd is +% the replacement(s) (available only via the struct alternative) +% print_options - Additional parameter strings to be passed to the print command + +%{ +% Copyright (C) Oliver Woodford 2008-2014, Yair Altman 2015- + +% The idea of editing the EPS file to change line styles comes from Jiro +% Doke's FIXPSLINESTYLE (fex id: 17928) +% The idea of changing dash length with line width came from comments on +% fex id: 5743, but the implementation is mine :) +%} +%{ +% 14/11/11: Fix a MATLAB bug rendering black or white text incorrectly. +% Thanks to Mathieu Morlighem for reporting the issue and +% obtaining a fix from TMW. +% 08/12/11: Added ability to correct fonts. Several people have requested +% this at one time or another, and also pointed me to printeps +% (fex id: 7501), so thank you to them. My implementation (which +% was not inspired by printeps - I'd already had the idea for my +% approach) goes slightly further in that it allows multiple +% fonts to be swapped. +% 14/12/11: Fix bug affecting font names containing spaces. Thanks to David +% Szwer for reporting the issue. +% 25/01/12: Add a font not to be swapped. Thanks to Anna Rafferty and Adam +% Jackson for reporting the issue. Also fix a bug whereby using a +% font alias can lead to another font being swapped in. +% 10/04/12: Make the font swapping case insensitive. +% 26/10/12: Set PaperOrientation to portrait. Thanks to Michael Watts for +% reporting the issue. +% 26/10/12: Fix issue to do with swapping fonts changing other fonts and +% sizes we don't want, due to listeners. Thanks to Malcolm Hudson +% for reporting the issue. +% 22/03/13: Extend font swapping to axes labels. Thanks to Rasmus Ischebeck +% for reporting the issue. +% 23/07/13: Bug fix to font swapping. Thanks to George for reporting the +% issue. +% 13/08/13: Fix MATLAB feature of not exporting white lines correctly. +% Thanks to Sebastian Hesslinger for reporting it. +% 24/02/15: Fix for Matlab R2014b bug (issue #31): LineWidths<0.75 are not +% set in the EPS (default line width is used) +% 25/02/15: Fixed issue #32: BoundingBox problem caused uncropped EPS/PDF files +% 05/03/15: Fixed issue #43: Inability to perform EPS file post-processing +% 06/03/15: Improved image padding & cropping thanks to Oscar Hartogensis +% 21/03/15: Fixed edge-case of missing handles having a 'FontName' property +% 26/03/15: Attempt to fix issue #45: white lines in subplots do not print correctly +% 27/03/15: Attempt to fix issue #44: white artifact lines appearing in patch exports +% 30/03/15: Fixed issue #52: improved performance on HG2 (R2014b+) +% 09/04/15: Comment blocks consolidation and minor code cleanup (no real code change) +% 12/04/15: Fixed issue #56: bad cropping +% 14/04/15: Workaround for issue #45: lines in image subplots are exported in invalid color +% 07/07/15: Added option to avoid font-swapping in EPS/PDF +% 07/07/15: Fixed issue #83: use numeric handles in HG1 +% 22/07/15: Fixed issue #91 (thanks to Carlos Moffat) +% 28/09/15: Fixed issue #108 (thanks to JacobD10) +% 01/11/15: Fixed issue #112: optional renderer for bounding-box computation (thanks to Jesús Pestana Puerta) +% 21/02/16: Enabled specifying non-automated crop amounts +% 22/02/16: Better support + backward compatibility for transparency (issue #108) +% 10/06/16: Fixed issue #159: text handles get cleared by Matlab in the print() command +% 12/06/16: Improved the fix for issue #159 (in the previous commit) +% 12/06/16: Fixed issue #158: transparent patch color in PDF/EPS +% 18/09/17: Fixed issue #194: incorrect fonts in EPS/PDF output +% 18/09/17: Fixed issue #195: relaxed too-tight cropping in EPS/PDF +% 14/11/17: Workaround for issue #211: dashed/dotted lines in 3D axes appear solid +% 15/11/17: Updated issue #211: only set SortMethod='ChildOrder' in HG2, and when it looks the same onscreen; support multiple figure axes +% 18/11/17: Fixed issue #225: transparent/translucent dashed/dotted lines appear solid in EPS/PDF +% 24/03/18: Fixed issue #239: black title meshes with temporary black background figure bgcolor, causing bad cropping +% 21/03/19: Improvement for issue #258: missing fonts in output EPS/PDF (still *NOT* fully solved) +% 21/03/19: Fixed issues #166,#251: Arial font is no longer replaced with Helvetica but rather treated as a non-standard user font +% 14/05/19: Made Helvetica the top default font-swap, replacing Courier +% 12/06/19: Issue #277: Enabled preservation of figure's PaperSize in output PDF/EPS file +% 06/08/19: Issue #281: only fix patch/textbox color if it's not opaque +% 15/01/20: Added warning ID for easier suppression by users +% 20/01/20: Added comment about unsupported patch transparency in some Ghostscript versions (issue #285) +% 10/12/20: Enabled user-specified regexp replacements in the generated EPS file (issue #324) +% 11/03/21: Added documentation about export_options.regexprep; added sanity check (issue #324) +% 21/07/21: Fixed misleading warning message about regexprep field when it's empty (issue #338) +% 26/08/21: Added a short pause to avoid unintended image cropping (issue #318) +% 16/03/22: Fixed occasional empty files due to excessive cropping (issues #350, #351) +% 15/05/22: Fixed EPS bounding box (issue #356) +%} + + options = {'-loose'}; + if nargin > 3 + options = [options varargin]; + elseif nargin < 3 + export_options = 0; + if nargin < 2 + fig = gcf(); + end + end + + % Retrieve padding, crop & font-swap values + crop_amounts = nan(1,4); % auto-crop all 4 sides by default + if isstruct(export_options) + try preserve_size = export_options.preserve_size; catch, preserve_size = false; end + try fontswap = export_options.fontswap; catch, fontswap = true; end + try font_space = export_options.font_space; catch, font_space = ''; end + font_space(2:end) = ''; + try bb_crop = export_options.crop; catch, bb_crop = 0; end + try crop_amounts = export_options.crop_amounts; catch, end + try bb_padding = export_options.bb_padding; catch, bb_padding = 0; end + try renderer = export_options.rendererStr; catch, renderer = 'opengl'; end % fix for issue #110 + if renderer(1)~='-', renderer = ['-' renderer]; end + else + if numel(export_options) > 3 % preserve_size + preserve_size = export_options(4); + else + preserve_size = false; + end + if numel(export_options) > 2 % font-swapping + fontswap = export_options(3); + else + fontswap = true; + end + if numel(export_options) > 1 % cropping + bb_crop = export_options(2); + else + bb_crop = 0; % scalar value, so use default bb_crop value of 0 + end + if numel(export_options) > 0 % padding + bb_padding = export_options(1); + else + bb_padding = 0; + end + renderer = '-opengl'; + font_space = ''; + end + + % Construct the filename + if numel(name) < 5 || ~strcmpi(name(end-3:end), '.eps') + name = [name '.eps']; % Add the missing extension + end + + % Set paper size + old_pos_mode = get(fig, 'PaperPositionMode'); + old_orientation = get(fig, 'PaperOrientation'); + old_paper_units = get(fig, 'PaperUnits'); + set(fig, 'PaperPositionMode','auto', 'PaperOrientation','portrait', 'PaperUnits','points'); + + % Find all the used fonts in the figure + font_handles = findall(fig, '-property', 'FontName'); + fonts = get(font_handles, 'FontName'); + if isempty(fonts) + fonts = {}; + elseif ~iscell(fonts) + fonts = {fonts}; + end + + % Map supported font aliases onto the correct name + fontsl = lower(fonts); + for a = 1:numel(fonts) + f = fontsl{a}; + f(f==' ') = []; + switch f + case {'times', 'timesnewroman', 'times-roman'} + fontsl{a} = 'times'; + %case {'arial', 'helvetica'} % issues #166, #251 + % fontsl{a} = 'helvetica'; + case {'newcenturyschoolbook', 'newcenturyschlbk'} + fontsl{a} = 'newcenturyschlbk'; + otherwise + end + end + fontslu = unique(fontsl); + + % Determine the font swap table + if fontswap + % Issue #258: Rearrange standard fonts list based on decending "problematicness" + % The issue is still *NOT* fully solved because I cannot figure out how to force + % the EPS postscript engine to look for the user's font on disk + % Also see: https://stat.ethz.ch/pipermail/r-help/2005-January/064374.html + matlab_fonts = {'Helvetica', 'Times', 'Courier', 'Symbol', 'ZapfDingbats', ... + 'Palatino', 'Bookman', 'ZapfChancery', 'AvantGarde', ... + 'NewCenturySchlbk', 'Helvetica-Narrow'}; + matlab_fontsl = lower(matlab_fonts); + require_swap = find(~ismember(fontslu, matlab_fontsl)); + unused_fonts = find(~ismember(matlab_fontsl, fontslu)); + font_swap = cell(3, min(numel(require_swap), numel(unused_fonts))); + fonts_new = fonts; + for a = 1:size(font_swap, 2) + font_swap{1,a} = find(strcmp(fontslu{require_swap(a)}, fontsl)); + font_swap{2,a} = matlab_fonts{unused_fonts(a)}; + font_swap{3,a} = fonts{font_swap{1,a}(1)}; + fonts_new(font_swap{1,a}) = font_swap(2,a); + end + else + font_swap = []; + end + + % Swap the fonts + if ~isempty(font_swap) + fonts_size = get(font_handles, 'FontSize'); + if iscell(fonts_size) + fonts_size = cell2mat(fonts_size); + end + M = false(size(font_handles)); + + % Loop because some changes may not stick first time, due to listeners + c = 0; + update = zeros(1000, 1); + for b = 1:10 % Limit number of loops to avoid infinite loop case + for a = 1:numel(M) + M(a) = ~isequal(get(font_handles(a), 'FontName'), fonts_new{a}) || ~isequal(get(font_handles(a), 'FontSize'), fonts_size(a)); + if M(a) + set(font_handles(a), 'FontName', fonts_new{a}, 'FontSize', fonts_size(a)); + c = c + 1; + update(c) = a; + end + end + if ~any(M) + break; + end + end + + % Compute the order to revert fonts later, without the need of a loop + [update, M] = unique(update(1:c)); + [dummy, M] = sort(M); %#ok + update = reshape(update(M), 1, []); + end + + % MATLAB bug fix - black and white text can come out inverted sometimes + % Find the white and black text + black_text_handles = findall(fig, 'Type', 'text', 'Color', [0 0 0]); + white_text_handles = findall(fig, 'Type', 'text', 'Color', [1 1 1]); + % Set the font colors slightly off their correct values + set(black_text_handles, 'Color', [0 0 0] + eps); + set(white_text_handles, 'Color', [1 1 1] - eps); + + % MATLAB bug fix - white lines can come out funny sometimes + % Find the white lines + white_line_handles = findall(fig, 'Type', 'line', 'Color', [1 1 1]); + % Set the line color slightly off white + set(white_line_handles, 'Color', [1 1 1] - 0.00001); + + % MATLAB bug fix (issue #211): dashed/dotted lines in 3D axes appear solid + % Note: this "may limit other functionality in plotting such as hidden line/surface removal" + % reference: Technical Support Case #02838114, https://mail.google.com/mail/u/0/#inbox/15fb7659f70e7bd8 + hAxes = findall(fig, 'Type', 'axes'); + if using_hg2 && ~isempty(hAxes) % issue #211 presumably happens only in HG2, not HG1 + try + % If there are any axes using SortMethod~='ChildOrder' + oldSortMethods = get(hAxes,{'SortMethod'}); % use {'SortMethod'} to ensure we get a cell array, even for single axes + if any(~strcmpi('ChildOrder',oldSortMethods)) % i.e., any oldSortMethods=='depth' + % Check if the axes look visually different onscreen when SortMethod='ChildOrder' + imgBefore = print2array(fig); + set(hAxes,'SortMethod','ChildOrder'); + imgAfter = print2array(fig); + if isequal(imgBefore, imgAfter) + % They look the same, so use SortMethod='ChildOrder' when generating the EPS + else + % They look different, so revert SortMethod and issue a warning message + warning('YMA:export_fig:issue211', ... + ['You seem to be using axes that have overlapping/hidden graphic elements. ' 10 ... + 'Setting axes.SortMethod=''ChildOrder'' may solve potential problems in EPS/PDF export. ' 10 ... + 'Additional info: https://github.com/altmany/export_fig/issues/211']) + set(hAxes,{'SortMethod'},oldSortMethods); + end + end + catch err + % ignore + a=err; %#ok % debug breakpoint + end + end + + % Workaround for issue #45: lines in image subplots are exported in invalid color + % In this case the -depsc driver solves the problem, but then all the other workarounds + % below (for all the other issues) will fail, so it's better to let the user decide by + % just issuing a warning and accepting the '-depsc' input parameter + epsLevel2 = ~any(strcmpi(options,'-depsc')); + if epsLevel2 + % Use -depsc2 (EPS color level-2) if -depsc (EPS color level-3) was not specifically requested + options{end+1} = '-depsc2'; + % Issue a warning if multiple images & lines were found in the figure, and HG1 with painters renderer is used + isPainters = any(strcmpi(options,'-painters')); + if isPainters && ~using_hg2 && numel(findall(fig,'Type','image'))>1 && ~isempty(findall(fig,'Type','line')) + warning('YMA:export_fig:issue45', ... + ['Multiple images & lines detected. In such cases, the lines might \n' ... + 'appear with an invalid color due to an internal MATLAB bug (fixed in R2014b). \n' ... + 'Possible workaround: add a ''-depsc'' or ''-opengl'' parameter to the export_fig command.']); + end + end + + % Fix issue #83: use numeric handles in HG1 + if ~using_hg2(fig), fig = double(fig); end + + % Workaround for when transparency is lost through conversion fig>EPS>PDF (issue #108) + % Replace transparent patch RGB values with an ID value (rare chance that ID color is being used already) + if using_hg2 + origAlphaColors = eps_maintainAlpha(fig); + end + + % Ensure that everything is fully rendered, to avoid cropping (issue #318) + drawnow; pause(0.02); + + % Print to eps file + print(fig, options{:}, name); + + % Restore the original axes SortMethods (if updated) + try set(hAxes,{'SortMethod'},oldSortMethods); catch, end + + % Do post-processing on the eps file + try + % Read the EPS file into memory + fstrm = read_write_entire_textfile(name); + catch + fstrm = ''; + end + + % Restore colors for transparent patches/lines and apply the + % setopacityalpha setting in the EPS file (issue #108) + if using_hg2 + [~,fstrm,foundFlags] = eps_maintainAlpha(fig, fstrm, origAlphaColors); + + % If some of the transparencies were not found in the EPS file, then rerun the + % export with only the found transparencies modified (backward compatibility) + if ~isempty(fstrm) && ~all(foundFlags) + foundIdx = find(foundFlags); + for objIdx = 1 : sum(foundFlags) + colorsIdx = foundIdx(objIdx); + colorsData = origAlphaColors{colorsIdx}; + hObj = colorsData{1}; + propName = colorsData{2}; + newColor = colorsData{4}; + hObj.(propName).ColorData = newColor; + end + delete(name); + print(fig, options{:}, name); + fstrm = read_write_entire_textfile(name); + [~,fstrm] = eps_maintainAlpha(fig, fstrm, origAlphaColors(foundFlags)); + end + end + + % Bail out if EPS post-processing is not possible + if isempty(fstrm) + warning('YMA:export_fig:EPS','Loading EPS file failed, so unable to perform post-processing. This is usually because the figure contains a large number of patch objects. Consider exporting to a bitmap format in this case.'); + return + end + + % Fix for Matlab R2014b bug (issue #31): LineWidths<0.75 are not set in the EPS (default line width is used) + try + if using_hg2(fig) + % Convert miter joins to line joins + %fstrm = regexprep(fstrm, '\n10.0 ML\n', '\n1 LJ\n'); + % This is faster (the original regexprep could take many seconds when the axes contains many lines): + fstrm = strrep(fstrm, sprintf('\n10.0 ML\n'), sprintf('\n1 LJ\n')); + + % In HG2, grid lines and axes Ruler Axles have a default LineWidth of 0.5 => replace en-bulk (assume that 1.0 LineWidth = 1.333 LW) + % hAxes=gca; hAxes.YGridHandle.LineWidth, hAxes.YRuler.Axle.LineWidth + %fstrm = regexprep(fstrm, '(GC\n2 setlinecap\n1 LJ)\nN', '$1\n0.667 LW\nN'); + % This is faster: + fstrm = strrep(fstrm, sprintf('GC\n2 setlinecap\n1 LJ\nN'), sprintf('GC\n2 setlinecap\n1 LJ\n0.667 LW\nN')); + + % This is more accurate but *MUCH* slower (issue #52) + %{ + % Modify all thin lines in the figure to have 10x LineWidths + hLines = findall(fig,'Type','line'); + hThinLines = []; + for lineIdx = 1 : numel(hLines) + thisLine = hLines(lineIdx); + if thisLine.LineWidth < 0.75 && strcmpi(thisLine.Visible,'on') + hThinLines(end+1) = thisLine; %#ok + thisLine.LineWidth = thisLine.LineWidth * 10; + end + end + + % If any thin lines were found + if ~isempty(hThinLines) + % Prepare an EPS with large-enough line widths + print(fig, options{:}, name); + % Restore the original LineWidths in the figure + for lineIdx = 1 : numel(hThinLines) + thisLine = handle(hThinLines(lineIdx)); + thisLine.LineWidth = thisLine.LineWidth / 10; + end + + % Compare the original and the new EPS files and correct the original stream's LineWidths + fstrm_new = read_write_entire_textfile(name); + idx = 500; % skip heading with its possibly-different timestamp + markerStr = sprintf('10.0 ML\nN'); + markerLen = length(markerStr); + while ~isempty(idx) && idx < length(fstrm) + lastIdx = min(length(fstrm), length(fstrm_new)); + delta = fstrm(idx+1:lastIdx) - fstrm_new(idx+1:lastIdx); + idx = idx + find(delta,1); + if ~isempty(idx) && ... + isequal(fstrm(idx-markerLen+1:idx), markerStr) && ... + ~isempty(regexp(fstrm_new(idx-markerLen+1:idx+12),'10.0 ML\n[\d\.]+ LW\nN')) %#ok + value = str2double(regexprep(fstrm_new(idx:idx+12),' .*','')); + if isnan(value), break; end % something's wrong... - bail out + newStr = sprintf('%0.3f LW\n',value/10); + fstrm = [fstrm(1:idx-1) newStr fstrm(idx:end)]; + idx = idx + 12; + else + break; + end + end + end + %} + + % This is much faster although less accurate: fix all non-gray lines to have a LineWidth of 0.75 (=1 LW) + % Note: This will give incorrect LineWidth of 075 for lines having LineWidth<0.75, as well as for non-gray grid-lines (if present) + % However, in practice these edge-cases are very rare indeed, and the difference in LineWidth should not be noticeable + %fstrm = regexprep(fstrm, '([CR]C\n2 setlinecap\n1 LJ)\nN', '$1\n1 LW\nN'); + % This is faster (the original regexprep could take many seconds when the axes contains many lines): + fstrm = strrep(fstrm, sprintf('\n2 setlinecap\n1 LJ\nN'), sprintf('\n2 setlinecap\n1 LJ\n1 LW\nN')); + end + catch err + fprintf(2, 'Error fixing LineWidths in EPS file: %s\n at %s:%d\n', err.message, err.stack(1).file, err.stack(1).line); + end + + % Reset the font and line colors + try + set(black_text_handles, 'Color', [0 0 0]); + set(white_text_handles, 'Color', [1 1 1]); + catch + % Fix issue #159: redo findall() '*text_handles' + black_text_handles = findall(fig, 'Type', 'text', 'Color', [0 0 0]+eps); + white_text_handles = findall(fig, 'Type', 'text', 'Color', [1 1 1]-eps); + set(black_text_handles, 'Color', [0 0 0]); + set(white_text_handles, 'Color', [1 1 1]); + end + set(white_line_handles, 'Color', [1 1 1]); + + % Preserve the figure's PaperSize in the output file, if requested (issue #277) + if preserve_size + % https://stackoverflow.com/questions/19646329/postscript-document-size + paper_size = get(fig, 'PaperSize'); % in [points] + fstrm = sprintf('<< /PageSize [%d %d] >> setpagedevice\n%s', paper_size, fstrm); + end + + % Reset paper size + set(fig, 'PaperPositionMode',old_pos_mode, 'PaperOrientation',old_orientation, 'PaperUnits',old_paper_units); + + % Reset the font names in the figure + if ~isempty(font_swap) + for a = update + set(font_handles(a), 'FontName', fonts{a}, 'FontSize', fonts_size(a)); + end + + for a = 1:size(font_swap, 2) + fontName = font_swap{3,a}; + %fontName = fontName(~isspace(font_swap{3,a})); + if length(fontName) > 29 + warning('YMA:export_fig:font_name','Font name ''%s'' is longer than 29 characters. This might cause problems in some EPS/PDF readers. Consider using a different font.',fontName); + end + if isempty(font_space) + fontName(fontName==' ') = ''; + else + fontName(fontName==' ') = char(font_space); + end + + % Replace all instances of the standard Matlab fonts with the original user's font names + %fstrm = regexprep(fstrm, [font_swap{1,a} '-?[a-zA-Z]*\>'], fontName); + %fstrm = regexprep(fstrm, [font_swap{2,a} '([ \n])'], [fontName '$1']); + %fstrm = regexprep(fstrm, font_swap{2,a}, fontName); % also replace -Bold, -Italic, -BoldItalic + + % Times-Roman's Bold/Italic fontnames don't include '-Roman' + fstrm = regexprep(fstrm, [font_swap{2,a} '(\-Roman)?'], fontName); + end + end + + % Move the bounding box to the top of the file (HG2 only), or fix the line styles (HG1 only) + if using_hg2(fig) + % Move the bounding box to the top of the file (HG2 only) + [s, e] = regexp(fstrm, '%%BoundingBox: [^%]*%%'); + if numel(s) == 2 + fstrm = fstrm([1:s(1)-1 s(2):e(2)-2 e(1)-1:s(2)-1 e(2)-1:end]); + end + else + % Fix the line styles (HG1 only) + fstrm = fix_lines(fstrm); + end + + % Apply the bounding box padding & cropping, replacing Matlab's print()'s bounding box + if bb_crop + % Calculate a new bounding box based on a bitmap print using crop_border.m + % 1. Determine the Matlab BoundingBox and PageBoundingBox + [s,e] = regexp(fstrm, '%%BoundingBox: [^%]*%%'); % location BB in eps file + if numel(s)==2, s=s(2); e=e(2); end + aa = fstrm(s+15:e-3); % dimensions bb - STEP1 + bb_matlab = cell2mat(textscan(aa,'%f32%f32%f32%f32')); % dimensions bb - STEP2 + + [s,e] = regexp(fstrm, '%%PageBoundingBox: [^%]*%%'); % location bb in eps file + if numel(s)==2, s=s(2); e=e(2); end + aa = fstrm(s+19:e-3); % dimensions bb - STEP1 + pagebb_matlab = cell2mat(textscan(aa,'%f32%f32%f32%f32')); % dimensions bb - STEP2 + + % 1b. Fix issue #239: black title meshes with temporary black background figure bgcolor, causing bad cropping + hTitles = []; + if isequal(get(fig,'Color'),'none') + hAxes = findall(fig,'type','axes'); + for idx = 1 : numel(hAxes) + hAx = hAxes(idx); + try + hTitle = hAx.Title; + oldColor = hTitle.Color; + if all(oldColor < 5*eps) || (ischar(oldColor) && lower(oldColor(1))=='k') + hTitles(end+1) = hTitle; %#ok + hTitle.Color = [0,0,.01]; + end + catch + end + end + end + + % 2. Create a bitmap image and use crop_borders to create the relative + % bb with respect to the PageBoundingBox + drawnow; pause(0.05); % avoid unintended cropping (issue #318) + [A, bcol] = print2array(fig, 1, renderer); + [aa, aa, aa, bb_rel] = crop_borders(A, bcol, bb_padding, crop_amounts); %#ok + if any(bb_rel>1) || any(bb_rel<=0) % invalid cropping - retry after prolonged pause + pause(0.15); % avoid unintended cropping (issues #350, #351) + [A, bcol] = print2array(fig, 1, renderer); + [aa, aa, aa, bb_rel] = crop_borders(A, bcol, bb_padding, crop_amounts); %#ok + end + bb_rel(bb_rel>1) = 1; % ignore invalid values + bb_rel(bb_rel<0) = 1; % ignore invalid values (fix issue #356) + + try set(hTitles,'Color','k'); catch, end + + % 3. Calculate the new Bounding Box + pagew = pagebb_matlab(3)-pagebb_matlab(1); + pageh = pagebb_matlab(4)-pagebb_matlab(2); + %bb_new = [pagebb_matlab(1)+pagew*bb_rel(1) pagebb_matlab(2)+pageh*bb_rel(2) ... + % pagebb_matlab(1)+pagew*bb_rel(3) pagebb_matlab(2)+pageh*bb_rel(4)]; + bb_new = pagebb_matlab([1,2,1,2]) + [pagew,pageh,pagew,pageh].*bb_rel; % clearer + bb_offset = (bb_new-bb_matlab) + [-2,-2,2,2]; % 2px margin so that cropping is not TOO tight (issue #195) + + % Apply the bounding box padding + if bb_padding + if abs(bb_padding)<1 + bb_padding = round((mean([bb_new(3)-bb_new(1) bb_new(4)-bb_new(2)])*bb_padding)/0.5)*0.5; % ADJUST BB_PADDING + end + add_padding = @(n1, n2, n3, n4) sprintf(' %.0f', str2double({n1, n2, n3, n4}) + bb_offset + bb_padding*[-1,-1,1,1]); %#ok + else + add_padding = @(n1, n2, n3, n4) sprintf(' %.0f', str2double({n1, n2, n3, n4}) + bb_offset); %#ok % fix small but noticeable bounding box shift + end + fstrm = regexprep(fstrm, '%%BoundingBox:[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)[ ]+([-]?\d+)', '%%BoundingBox:${add_padding($1, $2, $3, $4)}'); + end + + % Fix issue #44: white artifact lines appearing in patch exports + % Note: the problem is due to the fact that Matlab's print() function exports patches + % as a combination of filled triangles, and a white line appears where the triangles touch + % In the workaround below, we will modify such dual-triangles into a filled rectangle. + % We are careful to only modify regexps that exactly match specific patterns - it's better to not + % correct some white-line artifacts than to change the geometry of a patch, or to corrupt the EPS. + % e.g.: '0 -450 937 0 0 450 3 MP PP 937 0 0 -450 0 450 3 MP PP' => '0 -450 937 0 0 450 0 0 4 MP' + fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\2 \1 \3 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n'); + fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\2 \3 \1 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n'); + fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\3 \1 \2 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n'); + fstrm = regexprep(fstrm, '\n([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) ([-\d.]+ [-\d.]+) 3 MP\nPP\n\3 \2 \1 3 MP\nPP\n','\n$1 $2 $3 0 0 4 MP\nPP\n'); + + % If user requested a regexprep replacement of string(s), do this now (issue #324) + if isstruct(export_options) && isfield(export_options,'regexprep') && ~isempty(export_options.regexprep) %issue #338 + try + oldStrOrRegexp = export_options.regexprep{1}; + newStrOrRegexp = export_options.regexprep{2}; + fstrm = regexprep(fstrm, oldStrOrRegexp, newStrOrRegexp); + catch err + warning('YMA:export_fig:regexprep', 'Error parsing regexprep: %s', err.message); + end + end + + % Write out the fixed eps file + read_write_entire_textfile(name, fstrm); + + drawnow; pause(0.01); +end + +function [StoredColors, fstrm, foundFlags] = eps_maintainAlpha(fig, fstrm, StoredColors) + if nargin == 1 % in: convert transparency in Matlab figure into unique RGB colors + hObjs = findall(fig); %findobj(fig,'Type','Area'); + StoredColors = {}; + propNames = {'Face','Edge'}; + for objIdx = 1:length(hObjs) + hObj = hObjs(objIdx); + for propIdx = 1 : numel(propNames) + try + propName = propNames{propIdx}; + if strcmp(hObj.(propName).ColorType, 'truecoloralpha') + oldColor = hObj.(propName).ColorData; + if numel(oldColor)>3 && oldColor(4)~=255 % issue #281: only fix patch/textbox color if it's not opaque + nColors = length(StoredColors); + newColor = uint8([101; 102+floor(nColors/255); mod(nColors,255); 255]); + StoredColors{end+1} = {hObj, propName, oldColor, newColor}; %#ok + hObj.(propName).ColorData = newColor; + end + end + catch + % Never mind - ignore (either doesn't have the property or cannot change it) + end + end + end + else % restore transparency in Matlab figure by converting back from the unique RGBs + %Find the transparent patches + wasError = false; + nColors = length(StoredColors); + foundFlags = false(1,nColors); + for objIdx = 1 : nColors + colorsData = StoredColors{objIdx}; + hObj = colorsData{1}; + propName = colorsData{2}; + origColor = colorsData{3}; + newColor = colorsData{4}; + try + %Restore the EPS files patch color + colorID = num2str(round(double(newColor(1:3)') /255,3),'%.3g %.3g %.3g'); %ID for searching + origRGB = num2str(round(double(origColor(1:3)')/255,3),'%.3g %.3g %.3g'); %Replace with original color + origAlpha = num2str(round(double(origColor(end)) /255,3),'%.3g'); %Convert alpha value for EPS + + %Find and replace the RGBA values within the EPS text fstrm + %Note: .setopacityalpha is an unsupported PS extension that croaks in some GS versions (issue #285, https://bugzilla.redhat.com/show_bug.cgi?id=1632030) + % (such cases are caught in eps2pdf.m and corrected by adding the -dNOSAFER Ghosscript option or by removing the .setopacityalpha line) + if strcmpi(propName,'Face') + oldStr = sprintf(['\n' colorID ' RC\n']); % ...N\n (removed to fix issue #225) + newStr = sprintf(['\n' origRGB ' RC\n' origAlpha ' .setopacityalpha true\n']); % ...N\n + else %'Edge' + oldStr = sprintf(['\n' colorID ' RC\n']); % ...1 LJ\n (removed to fix issue #225) + newStr = sprintf(['\n' origRGB ' RC\n' origAlpha ' .setopacityalpha true\n']); + end + foundFlags(objIdx) = ~isempty(strfind(fstrm, oldStr)); %#ok + fstrm = strrep(fstrm, oldStr, newStr); + + %Restore the figure object's original color + hObj.(propName).ColorData = origColor; + catch err + % something is wrong - cannot restore transparent color... + if ~wasError + fprintf(2, 'Error maintaining transparency in EPS file: %s\n at %s:%d\n', err.message, err.stack(1).file, err.stack(1).line); + wasError = true; + end + end + end + end +end diff --git a/matlab/export_fig/read_write_entire_textfile.m b/matlab/export_fig/read_write_entire_textfile.m new file mode 100644 index 0000000..9fabb22 --- /dev/null +++ b/matlab/export_fig/read_write_entire_textfile.m @@ -0,0 +1,37 @@ +%READ_WRITE_ENTIRE_TEXTFILE Read or write a whole text file to/from memory +% +% Read or write an entire text file to/from memory, without leaving the +% file open if an error occurs. +% +% Reading: +% fstrm = read_write_entire_textfile(fname) +% Writing: +% read_write_entire_textfile(fname, fstrm) +% +%IN: +% fname - Pathname of text file to be read in. +% fstrm - String to be written to the file, including carriage returns. +% +%OUT: +% fstrm - String read from the file. If an fstrm input is given the +% output is the same as that input. + +function fstrm = read_write_entire_textfile(fname, fstrm) +modes = {'rt', 'wt'}; +writing = nargin > 1; +fh = fopen(fname, modes{1+writing}); +if fh == -1 + error('Unable to open file %s.', fname); +end +try + if writing + fwrite(fh, fstrm, 'char*1'); + else + fstrm = fread(fh, '*char')'; + end +catch ex + fclose(fh); + rethrow(ex); +end +fclose(fh); +end diff --git a/matlab/export_fig/resources/project/Extensions.type.Root/DependencyAnalysis.type.Extension/ExternalFiles.type.Extension.xml b/matlab/export_fig/resources/project/Extensions.type.Root/DependencyAnalysis.type.Extension/ExternalFiles.type.Extension.xml new file mode 100644 index 0000000..91869b6 --- /dev/null +++ b/matlab/export_fig/resources/project/Extensions.type.Root/DependencyAnalysis.type.Extension/ExternalFiles.type.Extension.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Project.xml b/matlab/export_fig/resources/project/Project.xml new file mode 100644 index 0000000..4a9e34e --- /dev/null +++ b/matlab/export_fig/resources/project/Project.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/ProjectData.type.Info.xml b/matlab/export_fig/resources/project/ProjectData.type.Info.xml new file mode 100644 index 0000000..de0b14e --- /dev/null +++ b/matlab/export_fig/resources/project/ProjectData.type.Info.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category.xml b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category.xml new file mode 100644 index 0000000..ef38945 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/artifact.type.Label.xml b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/artifact.type.Label.xml new file mode 100644 index 0000000..b56f659 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/artifact.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/convenience.type.Label.xml b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/convenience.type.Label.xml new file mode 100644 index 0000000..5272801 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/convenience.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/derived.type.Label.xml b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/derived.type.Label.xml new file mode 100644 index 0000000..5a873c8 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/derived.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/design.type.Label.xml b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/design.type.Label.xml new file mode 100644 index 0000000..59cb0be --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/design.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/none.type.Label.xml b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/none.type.Label.xml new file mode 100644 index 0000000..27ca3e7 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/none.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/other.type.Label.xml b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/other.type.Label.xml new file mode 100644 index 0000000..14d104f --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/other.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/test.type.Label.xml b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/test.type.Label.xml new file mode 100644 index 0000000..5a6f802 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Categories/FileClassCategory.type.Category/test.type.Label.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/.gitignore.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/.gitignore.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/.gitignore.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/ImageSelection.class.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/ImageSelection.class.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/ImageSelection.class.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/ImageSelection.java.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/ImageSelection.java.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/ImageSelection.java.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/LICENSE.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/LICENSE.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/LICENSE.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/README.md.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/README.md.type.File.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/README.md.type.File.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/append_pdfs.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/append_pdfs.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/append_pdfs.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/copyfig.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/copyfig.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/copyfig.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/crop_borders.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/crop_borders.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/crop_borders.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/eps2pdf.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/eps2pdf.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/eps2pdf.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/export_fig.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/export_fig.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/export_fig.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/fix_lines.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/fix_lines.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/fix_lines.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/ghostscript.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/ghostscript.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/ghostscript.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/im2gif.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/im2gif.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/im2gif.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/isolate_axes.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/isolate_axes.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/isolate_axes.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/pdf2eps.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/pdf2eps.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/pdf2eps.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/pdftops.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/pdftops.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/pdftops.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/print2array.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/print2array.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/print2array.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/print2eps.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/print2eps.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/print2eps.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/read_write_entire_textfile.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/read_write_entire_textfile.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/read_write_entire_textfile.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/user_string.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/user_string.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/user_string.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.Files/using_hg2.m.type.File.xml b/matlab/export_fig/resources/project/Root.type.Files/using_hg2.m.type.File.xml new file mode 100644 index 0000000..80b5b16 --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.Files/using_hg2.m.type.File.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/Root.type.ProjectPath/a533e478-c90b-4a1f-a45b-f8877af57bee.type.Reference.xml b/matlab/export_fig/resources/project/Root.type.ProjectPath/a533e478-c90b-4a1f-a45b-f8877af57bee.type.Reference.xml new file mode 100644 index 0000000..59b7a5d --- /dev/null +++ b/matlab/export_fig/resources/project/Root.type.ProjectPath/a533e478-c90b-4a1f-a45b-f8877af57bee.type.Reference.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/resources/project/uuid-cc21a9b0-026d-4b70-9821-3eb23d2abf81.xml b/matlab/export_fig/resources/project/uuid-cc21a9b0-026d-4b70-9821-3eb23d2abf81.xml new file mode 100644 index 0000000..1c0844e --- /dev/null +++ b/matlab/export_fig/resources/project/uuid-cc21a9b0-026d-4b70-9821-3eb23d2abf81.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/matlab/export_fig/user_string.m b/matlab/export_fig/user_string.m new file mode 100644 index 0000000..315a675 --- /dev/null +++ b/matlab/export_fig/user_string.m @@ -0,0 +1,117 @@ +function [string, file_name] = user_string(string_name, string) +%USER_STRING Get/set a user specific string +% +% Examples: +% string = user_string(string_name) +% isSaved = user_string(string_name, new_string) +% [value, file_name] = user_string(...) +% +% Function to get and set a string in a system or user specific file. This +% enables, for example, system specific paths to binaries to be saved. +% +% The specified string will be saved in a file named .txt, +% either in a subfolder named .ignore under this file's folder, or in the +% user's prefdir folder (in case this file's folder is non-writable). +% +% IN: +% string_name - String containing the name of the string required, which +% sets the filename storing the string: .txt +% new_string - The new string to be saved in the .txt file +% +% OUT: +% string - The currently saved string. Default: '' +% isSaved - Boolean indicating whether the save was succesful +% file_name - path of the .txt file used to contain the requested string + +% Copyright (C) Oliver Woodford 2011-2014, Yair Altman 2015- + +% This method of saving paths avoids changing .m files which might be in a +% version control system. Instead it saves the user dependent paths in +% separate files with a .txt extension, which need not be checked in to +% the version control system. Thank you to Jonas Dorn for suggesting this +% approach. + +% 10/01/2013 - Access files in text, not binary mode, as latter can cause +% errors. Thanks to Christian for pointing this out. +% 29/05/2015 - Save file in prefdir if current folder is non-writable (issue #74) +% 09/01/2018 - Fix issue #232: if the string looks like a file/folder path, ensure it actually exists +% 15/01/2020 - Added file_name output argument + + if ~ischar(string_name) + error('string_name must be a string.'); + end + % Create the full filename + fname = [string_name '.txt']; + dname = fullfile(fileparts(mfilename('fullpath')), '.ignore'); + file_name = fullfile(dname, fname); + default_file_name = file_name; + if nargin > 1 + % Set string + if ~ischar(string) + error('new_string must be a string.'); + end + % Make sure the save directory exists + %dname = fileparts(file_name); + if ~exist(dname, 'dir') + % Create the directory + try + if ~mkdir(dname) + string = false; + return + end + catch + string = false; + return + end + % Make it hidden + try + fileattrib(dname, '+h'); + catch + end + end + % Write the file + fid = fopen(file_name, 'wt'); + if fid == -1 + % file cannot be created/updated - use prefdir if file does not already exist + % (if file exists but is simply not writable, don't create a duplicate in prefdir) + if ~exist(file_name,'file') + file_name = fullfile(prefdir, fname); + fid = fopen(file_name, 'wt'); + end + if fid == -1 + string = false; + file_name = default_file_name; + return + end + end + try + fprintf(fid, '%s', string); + catch + fclose(fid); + string = false; + return + end + fclose(fid); + string = true; + else + % Get string + fid = fopen(file_name, 'rt'); + if fid == -1 + % file cannot be read, try to read the file in prefdir + file_name = fullfile(prefdir, fname); + fid = fopen(file_name, 'rt'); + if fid == -1 + string = ''; + file_name = default_file_name; + return + end + end + string = fgetl(fid); + fclose(fid); + + % Fix issue #232: if the string looks like a file/folder path, ensure it actually exists + if ~isempty(string) && any(string=='\' | string=='/') && ~exist(string) %#ok + string = ''; + end + end +end diff --git a/matlab/export_fig/using_hg2.m b/matlab/export_fig/using_hg2.m new file mode 100644 index 0000000..ba72228 --- /dev/null +++ b/matlab/export_fig/using_hg2.m @@ -0,0 +1,36 @@ +%USING_HG2 Determine if the HG2 graphics engine is used +% +% tf = using_hg2(fig) +% +%IN: +% fig - handle to the figure in question. +% +%OUT: +% tf - boolean indicating whether the HG2 graphics engine is being used +% (true) or not (false). + +% 19/06/2015 - Suppress warning in R2015b; cache result for improved performance +% 06/06/2016 - Fixed issue #156 (bad return value in R2016b) + +function tf = using_hg2(fig) + persistent tf_cached + if isempty(tf_cached) + try + if nargin < 1, fig = figure('visible','off'); end + oldWarn = warning('off','MATLAB:graphicsversion:GraphicsVersionRemoval'); + try + % This generates a [supressed] warning in R2015b: + tf = ~graphicsversion(fig, 'handlegraphics'); + catch + tf = ~verLessThan('matlab','8.4'); % =R2014b + end + warning(oldWarn); + catch + tf = false; + end + if nargin < 1, delete(fig); end + tf_cached = tf; + else + tf = tf_cached; + end +end diff --git a/matlab/helper_classes/h5parts.m b/matlab/helper_classes/h5parts.m index 19a01fc..10f541a 100644 --- a/matlab/helper_classes/h5parts.m +++ b/matlab/helper_classes/h5parts.m @@ -1,241 +1,241 @@ classdef h5parts properties fullpath R Z THET VR VZ VTHET Rindex Zindex partindex partepot nlclassical q m weight tpart it2 nbparts rgrid zgrid vnorm rindex zindex parent end methods function obj=h5parts(filename,hdf5group,parent) obj.fullpath=filename; obj.nlclassical=parent.nlclassical; obj.it2=parent.it2; obj.rgrid=parent.rgrid; obj.zgrid=parent.zgrid; obj.vnorm=parent.vnorm; obj.tpart = h5read(obj.fullpath,sprintf('%s/time',hdf5group)); obj.nbparts = h5read(obj.fullpath,sprintf('%s/Nparts',hdf5group)); obj.parent=parent; if sum(obj.nbparts)>0 obj.R = h5partsquantity(obj.fullpath,hdf5group,'R'); obj.Z = h5partsquantity(obj.fullpath,hdf5group,'Z'); obj.THET = h5partsquantity(obj.fullpath,hdf5group,'THET'); obj.VR = h5partsquantity(obj.fullpath,hdf5group,'UR',obj.vnorm); obj.VZ = h5partsquantity(obj.fullpath,hdf5group,'UZ',obj.vnorm); obj.VTHET= h5partsquantity(obj.fullpath,hdf5group,'UTHET',obj.vnorm); obj.q= h5readatt(obj.fullpath,hdf5group,'q'); obj.m= h5readatt(obj.fullpath,hdf5group,'m'); obj.weight= h5readatt(obj.fullpath,hdf5group,'weight'); obj.partepot = h5partsquantity(filename,hdf5group,'pot',obj.q); obj.rindex=1:length(obj.rgrid); obj.zindex=1:length(obj.zgrid); try obj.Rindex=h5partsquantity(obj.fullpath,hdf5group,'Rindex'); obj.Zindex=h5partsquantity(obj.fullpath,hdf5group,'Zindex'); obj.partindex=h5partsquantity(obj.fullpath,hdf5group,'partindex'); catch end end % try % obj.partindex = h5read(obj.fullpath,sprintf('%s/partindex',hdf5group)); % partindex=obj.partindex; % partindex(partindex==-1)=NaN; % %[~,Indices]=sort(partindex,'ascend'); % Indices=obj.partindex; % for i=1:size(Indices,2) % obj.H(Indices(:,i),i)=obj.H(:,i); % obj.P(Indices(:,i),i)=obj.P(:,i); % % obj.R(Indices(:,i),i)=obj.R(:,i); % obj.Z(Indices(:,i),i)=obj.Z(:,i); % obj.Rindex(Indices(:,i),i)=obj.Rindex(:,i); % obj.Zindex(Indices(:,i),i)=obj.Zindex(:,i); % obj.VR(Indices(:,i),i)=obj.VR(:,i); % obj.VZ(Indices(:,i),i)=obj.VZ(:,i); % obj.VTHET(Indices(:,i),i)=obj.VTHET(:,i); % obj.THET(Indices(:,i),i)=obj.THET(:,i); % end % catch % end % clear partindex; end function quantity=H(obj,varargin) if(~iscell(varargin)) indices=mat2cell(varargin); else indices=varargin; end if strcmp(indices{1},':') p=1:obj.VR.nparts; else p=indices{1}; end if strcmp(indices{2},':') t=1:length(obj.tpart); else t=indices{2}; end if size(indices,2)>2 track=indices{3}; else track=false; end quantity=0.5*obj.m*(obj.VR(p,t,track).^2+obj.VTHET(p,t,track).^2+obj.VZ(p,t,track).^2)+obj.partepot(p,t,track); end function quantity=P(obj,varargin) if(~iscell(varargin)) indices=mat2cell(varargin); else indices=varargin; end if strcmp(indices{1},':') p=1:obj.R.nparts; else p=indices{1}; end if strcmp(indices{2},':') t=1:length(obj.tpart); else t=indices{2}; end if size(indices,2)>2 track=indices{3}; else track=false; end quantity=obj.R(p,t,track).*(obj.VTHET(p,t,track)*obj.m+obj.q*obj.parent.Atheta(obj.R(p,t,track),obj.Z(p,t,track))); end function quantity=Vpar(obj,varargin) %Vpar Computes the parallel velocity for the particle indices{1} at time indices{2} if(~iscell(varargin)) indices=mat2cell(varargin); else indices=varargin; end if strcmp(indices{1},':') p=1:obj.R.nparts; else p=indices{1}; end if strcmp(indices{2},':') t=1:length(obj.tpart); else t=indices{2}; end if size(indices,2)>2 track=indices{3}; else track=false; end Zp=obj.Z(p,t,track); Rp=obj.R(p,t,track); Bzp=interp2(obj.zgrid,obj.rgrid,obj.parent.Bz',Zp,Rp); Brp=interp2(obj.zgrid,obj.rgrid,obj.parent.Br',Zp,Rp); Bp=interp2(obj.zgrid,obj.rgrid,obj.parent.B',Zp,Rp); costhet=Bzp./Bp; sinthet=Brp./Bp; quantity=obj.VR(p,t,track).*sinthet+obj.VZ(p,t,track).*costhet; end function quantity=Vperp(obj,varargin) %Vperp Computes the perpendicular velocity in the guidind center reference frame, % for the main specie particle indices{1} at time indices{2} if(~iscell(varargin)) indices=mat2cell(varargin); else indices=varargin; end if strcmp(indices{1},':') p=1:obj.R.nparts; else p=indices{1}; end if strcmp(indices{2},':') t=1:length(obj.tpart); else t=indices{2}; end if size(indices,2)>2 track=indices{3}; else track=false; end if size(indices,2)>3 gcs=indices{4}; else gcs=false; end Zp=obj.Z(p,t,track); Rp=obj.R(p,t,track); Bzp=interp2(obj.zgrid,obj.rgrid,obj.parent.Bz',Zp,Rp); Brp=interp2(obj.zgrid,obj.rgrid,obj.parent.Br',Zp,Rp); Bp=interp2(obj.zgrid,obj.rgrid,obj.parent.B',Zp,Rp); costhet=Bzp./Bp; sinthet=Brp./Bp; Vdrift=zeros(size(Zp)); if gcs for j=1:length(t) [~, tfield]=min(abs(obj.parent.t2d-obj.tpart(t(j)))); timeEr=obj.parent.Er(:,:,tfield); timeEz=obj.parent.Ez(:,:,tfield); %posindE=sub2ind(size(timeEr),Rind(:,j),Zind(:,j)); timeErp=interp2(obj.zgrid,obj.rgrid,timeEr,Zp(:,j),Rp(:,j)); timeEzp=interp2(obj.zgrid,obj.rgrid,timeEz,Zp(:,j),Rp(:,j)); Vdrift(:,j)=(timeEzp.*Brp(:,j)-timeErp.*Bzp(:,j))./Bp(:,j).^2; end end quantity=sqrt((obj.VTHET(p,t,track)-Vdrift).^2+(obj.VR(p,t,track).*costhet-obj.VZ(p,t,track).*sinthet).^2); end function sref = subsref(obj,s) % obj(i) is equivalent to obj.Data(i) switch s(1).type case '.' if(strcmp(s(1).subs,'H')) sref=H(obj,s(2).subs); elseif(strcmp(s(1).subs,'P')) sref=P(obj,s(2).subs); else sref=builtin('subsref',obj,s); end case '()' sref=builtin('subsref',obj,s); case '{}' error('MYDataClass:subsref',... 'Not a supported subscripted reference') end end end -end +end \ No newline at end of file diff --git a/matlab/meas_oscill_tscales.m b/matlab/meas_oscill_tscales.m new file mode 100644 index 0000000..6b91b37 --- /dev/null +++ b/matlab/meas_oscill_tscales.m @@ -0,0 +1,77 @@ + +% t0=M.t0d; +% [t0,it]=unique(t0); +% npart=M.npart(it); +it=1:40:length(M.t2d); +t0=M.t2d(it); +N=M.N(:,:,it); +geomw=M.geomweight(:,:,1); +geomw(geomw<0)=0; +geomw(geomw>0)=1; + +N=N.*geomw; +npart=squeeze(max(max(N,[],1),[],2)); +[t0,it]=unique(t0); +npart=npart(it); + + +f=figure; +semilogy(t0,npart,'linewidth',1.5,'displayname','raw') +grid +hold on + +npart=lowpass(npart,1/3e-7,1/(t0(2)-t0(1))); + +[peaksmax,locsmax]=findpeaks(npart,t0,'minpeakdistance',1.2e-7); +[peaksmin,locsmin]=findpeaks(-npart,t0,'minpeakdistance',1.2e-7); + +semilogy(t0,npart,'linewidth',1.5,'displayname','filtered') +grid +hold on +plot(locsmin,-peaksmin,'v','linewidth',1.5,'markersize',11) +plot(locsmax,peaksmax,'^','linewidth',1.5,'markersize',11) + +peaksmin=-peaksmin; +peaksmax=peaksmax(2:end); +locsmax=locsmax(2:end); +if(locsmax(end)>locsmin(end)) + locsmax=locsmax(1:end-1); + peaksmax=peaksmax(1:end-1); +end +if (peaksmin(1)length(locsmax) + nui=log(peaksmax./peaksmin(1:end-1))./(locsmax-locsmin(1:end-1)); + nul=log(peaksmax./peaksmin(2:end))./(locsmax-locsmin(2:end)); +elseif length(locsmin)==length(locsmax) + nui=log(peaksmax./peaksmin)./(locsmax-locsmin); + nul=log(peaksmax(1:end-1)./peaksmin(2:end))./(locsmax(1:end-1)-locsmin(2:end)); +else + nui=log(peaksmax(1:end-1)./peaksmin)./(locsmax(1:end-1)-locsmin); + nul=log(peaksmax(1:end-2)./peaksmin(2:end))./(locsmax(1:end-2)-locsmin(2:end)); +end + + +nuimean=mean(nui) +nulmean=mean(nul) + +%nuimean=1.8e8; +%nulmean=-2.6e8; + +for i=1:length(peaksmax) + t=[locsmax(i), locsmax(i)+2e-7]; + plot(t,peaksmax(i)*exp((t-t(1)).*nulmean),'--','linewidth',1.5) +end +for i=1:length(peaksmin) + t=[locsmin(i), locsmin(i)+2e-7]; + plot(t,peaksmin(i)*exp((t-t(1)).*nuimean),'--','linewidth',1.5) +end + +xlabel('time [ns]') +ylabel('N_e') +title(sprintf('\\Delta\\phi=%2.1fkV',(M.potout-M.potinn)*M.phinorm/1e3)) +M.savegraph(f,sprintf('%s/%s_nuoscillsn',M.folder,M.name)) \ No newline at end of file diff --git a/matlab/test_rad_stab_cyl.m b/matlab/test_rad_stab_cyl.m new file mode 100644 index 0000000..12c5481 --- /dev/null +++ b/matlab/test_rad_stab_cyl.m @@ -0,0 +1,41 @@ +a=1e-3; +b=0.03; +phia=-5e3; +phib=0; +rm=2.8e-3; +rp=0.02;%rm+3e-3; + +nB=200; +nne=500; + +B=linspace(0.01,3,nB); +ne=logspace(14,20,nne); + +vlight=299792458; +qe=1.60217662E-19; +me=9.109383E-31; +eps_0=8.85418781762E-12; +kb=1.38064852E-23; + +q=-qe; +C=-q*ne/(4*eps_0)*(rp^2-rm^2)/log(rp/rm)... + +(phib-phia)/log(b/a)... + +(q*ne/(2*eps_0)*rm^2*log(b*rm/(a*rp))... + +q*ne/(2*eps_0)*(rp^2-rm^2)*(log(b/rp)+0.5*(1+log(a/b)/log(rp/rm))))/log(b/a); +C=1/2*q*ne*rm^2/eps_0; +omegape2=qe^2*ne/eps_0/me; +omegace2=qe^2*B.^2/me^2; + +r=linspace(rm,rp,100); +for i=1:nB + for j=1:nne + [stab1(i,j),id]=min(1-2*omegape2(j)/omegace2(i)+4*q*C(j)/me/omegace2(i)./r.^2); + rmin(i,j)=r(id); + end +end + +figure +contourf(B,ne,stab1'>0,'edgecolor','none') +set(gca,'YScale','log') +title(sprintf('r_m=%2.1fmm r_p=%2.1fmm, \\phi_a=%2.1fkV, \\phi_b=%2.1fkV',rm*1e3,rp*1e3,phia/1e3,phib/1e3)) + diff --git a/src/Makefile b/src/Makefile index 3c118cc..fd46276 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,130 +1,130 @@ .DEFAULT_GOAL := all ifeq ($(PLATFORM),) $(error Please specify the env variable PLATFORM (mac, intel)) else $(info *** Using $(PLATFORM).mk ***) include $(PLATFORM).mk endif include .depend PROG = espic2d SRCS = main.f90 basic_mod.f90 newrun.f90 restart.f90 \ auxval.f90 inital.f90 resume.f90 start.f90 diagnose.f90 \ stepon.f90 tesend.f90 endrun.f90 chkrst.f90 mv2bk.f90 \ constants.f90 fields_mod.f90 beam_mod.f90 \ mpihelper_mod.f90 sort_mod.f90 distrib_mod.f90 \ maxwsrce_mod.f90 celldiag_mod.f90 geometry_mod.f90 \ random_mod.f90 neutcol_mod.f90 particletypes_mod.f90 \ - splinebound_mod.f90 weighttypes_mod.f90 + splinebound_mod.f90 weighttypes_mod.f90 psupply_mod.f90 SRCS_C = extra.c SRCS_F = random.f randother.f MKDIR_P = mkdir -p OUT_DIR = release F90FLAGS += -I$(BSPLINES)/include -I$(FUTILS)/include \ -I$(MUMPS)/include -I../ CCFLAGS += -qopenmp -O3 LDFLAGS += -L$(BSPLINES)/lib -L$(FUTILS)/lib -L${HDF5}/lib -L${HDF5}/lib \ -L$(MUMPS)/lib -L$(PARMETIS)/lib LIBS += -lbsplines -lpppack -lfutils -lhdf5_fortran -lhdf5 -lz $(MUMPSLIBS) -lpputils2 ifeq ($(USE_X),) F90FLAGS+=-DUSE_X=0 else $(info *** Using Xgrafix ***) LIBS+=-lXGF -lXGC -lX11 -lSWIG LDFLAGS+=-L/usr/local/xgrafix_1.2/src-double F90FLAGS+=-DUSE_X=1 SRCS+=xg_mod.f90 endif OBJS =${SRCS:.f90=.o} ${SRCS_F90:.F90=.o} ${SRCS_C:.c=.o} ${SRCS_F:.f=.o} FPP =${SRCS:.f90=.i90} OBJS_ =$(addprefix ./$(OUT_DIR)/,$(OBJS)) debug: F90FLAGS += $(DEBUGFLAGS) debug: OUT_DIR=debug debug: $(OUT_DIR) all profile: F90FLAGS+=$(PROFILEFLAGS) profile: LDFLAGS+= $(PROFILEFLAGS) profile: OUT_DIR=profile profile: $(OUT_DIR) all $(info *** Using $(OBJS) ***) .PHONY: directories clean debug profile all: directories $(PROG) $(PROG): $(OBJS) $(F90) $(LDFLAGS) $(F90FLAGS) -o $@ $(OBJS_) $(LIBS) tags: etags *.f90 clean: rm -f $(OBJS_) *.mod $(FPP) distclean: clean rm -f $(PROG) *~ a.out *.o TAGS extra.o: extra.c ifeq ($(USE_X),) ./$(OUT_DIR)/diagnose.o : diagnose.f90 fields_mod.o beam_mod.o basic_mod.o else ./$(OUT_DIR)/diagnose.o : diagnose.f90 fields_mod.o xg_mod.o beam_mod.o basic_mod.o endif directories: ${OUT_DIR} ${OUT_DIR}: ${MKDIR_P} ${OUT_DIR} #tinyspline.o: tinyspline.h parson.o # $(CC) $(CCFLAGS) -c -o ./$(OUT_DIR)/$@ $< # #tinyspline_wrap.o: tinyspline.h tinyspline_wrap.c ./$(OUT_DIR)/tinyspline_wrap.o # $(CC) $(CCFLAGS) -c -o $@ $< # #$(OUT_DIR)/tinyspline_wrap.o: tinyspline.h tinyspline_wrap.c # $(CC) $(CCFLAGS) -c -o $@ $< # #$(OUT_DIR)/tinysplinef.o: tinyspline_wrap.o # $(CC) $(CCFLAGS) -c -o $@ $< .SUFFIXES: $(SUFFIXES) .f90 .c .f ./$(OUT_DIR)/%.o: %.f90 $(F90) $(F90FLAGS) -MD -c -o $@ $< ./$(OUT_DIR)/%.o: %.f $(F90) $(F90FLAGS) -MD -c -o $@ $< ./$(OUT_DIR)/%.o: %.c $(CC) $(CCFLAGS) -c -o $@ $< %.o: %.c $(CC) $(CCFLAGS) -c -o ./$(OUT_DIR)/$@ $< %.o: %.f90 $(F90) $(F90FLAGS) -c -o ./$(OUT_DIR)/$@ $< %.o: %.f $(F90) $(F90FLAGS) -c -o ./$(OUT_DIR)/$@ $< depend .depend .depend_rel .depend_deb : makedepf90 *.[fF]90 > .depend diff --git a/src/geometry_mod.f90 b/src/geometry_mod.f90 index 2881db9..0188f2b 100644 --- a/src/geometry_mod.f90 +++ b/src/geometry_mod.f90 @@ -1,1192 +1,1197 @@ !------------------------------------------------------------------------------ ! EPFL/Swiss Plasma Center !------------------------------------------------------------------------------ ! ! MODULE: geometry ! !> @author !> Guillaume Le Bars EPFL/SPC ! ! DESCRIPTION: !> Module responsible for handling geometries with non constant radius using b-splines interpolation !> This module defines ways to comupte the weight function needed for weighted b-splines and !> can load the definition of the geometry from input files !------------------------------------------------------------------------------ MODULE geometry USE constants USE bsplines USE mumps_bsplines USE splinebound use weighttypes IMPLICIT NONE type innerspline Integer, Allocatable:: k(:) ! Index in reduced set real(kind=db), Allocatable:: weight(:) ! geomtric weight at relevant cell end type innerspline type test_params real(kind=db):: z0 real(kind=db):: r0 real(kind=db):: Lz real(kind=db):: Lr end type Integer, save:: testkr=1, testkz=1 Logical, save:: nlweb=.false. Integer, save :: walltype = 0 Integer, save, Allocatable:: bsplinetype(:) ! Array containing the inner/outer type for each bspline Integer, save, Allocatable:: gridcelltype(:,:) ! Array containing the inner/outer type for each gridcell Integer, save, Allocatable:: linkedspline(:,:) ! Array containing the lowerleft linked spline in case of boundary spline Real(kind=db), save, allocatable:: gridwgeom(:,:) ! Stores the geometric weight at the grid points Real(kind=db), save, allocatable:: gridwdom(:,:) ! Stores the domain weight at the grid points Real(kind=db), save, allocatable:: gtilde(:,:) ! Stores the extension to the domain of the boundary conditions type(mumps_mat):: etilde ! Matrix of extendend web splines type(mumps_mat):: etildet ! Transpose of Matrix of extendend web splines integer,save :: nbreducedspline ! Number of splines in the reduced set type(test_params), save:: test_pars PROCEDURE(geom_eval), POINTER:: dirichlet_weight => NULL() PROCEDURE(geomtot_eval), POINTER:: domain_weight => NULL() PROCEDURE(gtilde_eval), POINTER:: total_gtilde => NULL() PUBLIC:: geom_weight, dom_weight ABSTRACT INTERFACE SUBROUTINE gtilde_eval(z,r,g,w) USE constants Real(kind=db), INTENT(IN):: r(:),z(:) Real(kind=db), INTENT(OUT):: g(:,0:) Real(kind=db), INTENT(IN),OPTIONAL::w(:,0:) END SUBROUTINE SUBROUTINE geom_eval(z,r,w,wupper) USE constants Real(kind=db), INTENT(IN) :: r(:),z(:) Real(kind=db), INTENT(OUT):: w(:,0:) Real(kind=db), OPTIONAL :: wupper(:,0:) END SUBROUTINE SUBROUTINE geomtot_eval(z,r,w,idwall) USE constants Real(kind=db), INTENT(IN):: r(:),z(:) Real(kind=db), INTENT(OUT):: w(:,0:) INTEGER, optional, INTENT(OUT):: idwall(:) END SUBROUTINE END INTERFACE INTERFACE geom_weight MODULE PROCEDURE geom_weight0, geom_weight1, geom_weight2 END INTERFACE geom_weight INTERFACE dom_weight MODULE PROCEDURE dom_weight0, dom_weight1, dom_weight2, dom_weight3 END INTERFACE dom_weight NAMELIST /geomparams/ z_0, r_0, z_r, r_r, r_a, r_b, z_a, z_b ,walltype, L_r, L_z, nlweb, Interior, above1, above2, alpha, r_bLeft, r_bRight, testkr, testkz contains SUBROUTINE read_geom(Fileid, rnorm, splrz, Potinn, Potout) use mpi Use bsplines use basic, ONLY: phinorm use weighttypes type(spline2d):: splrz Real(kind=db):: rnorm, Potinn, Potout Integer:: Fileid, mpirank, ierr, istat character(len=1000) :: line !type(spline_boundary):: border0 !Real(kind=db):: cpoints(2,3),t(1), distance, pos !Real(kind=db), ALLOCATABLE::result(:,:,:) CALL MPI_COMM_RANK(MPI_COMM_WORLD, mpirank, ierr) Rewind(Fileid) READ(Fileid, geomparams, iostat=istat) if (istat.gt.0) then if(mpirank .eq. 0) then backspace(Fileid) read(Fileid,fmt='(A)') line write(*,'(A)') & 'Invalid line in geomparams: '//trim(line) end if call MPI_Abort(MPI_COMM_WORLD, -1, ierr) stop end if if(mpirank .eq. 0) WRITE(*, geomparams) !! Normalizations and initialization of geometric variables r_a=r_a/rnorm r_b=r_b/rnorm z_a=z_a/rnorm z_b=z_b/rnorm r_bLeft=r_bLeft/rnorm r_bRight=r_bRight/rnorm if(r_a .eq. 0 .and. r_b .eq.0) then !! in case no geom_params have been defined r_a=splrz%sp2%knots(0) r_b=splrz%sp2%knots(splrz%sp2%nints) end if z_0=z_0/rnorm r_0=r_0/rnorm z_r=z_r/rnorm r_r=r_r/rnorm invr_r=1/r_r invr_z=1/z_r Phidown=Potinn Phiup=Potout L_r=L_r/rnorm L_z=L_z/rnorm SELECT CASE (abs(walltype)) CASE (2) ! coaxial cylinder and top ellipse with cylinder extensions total_gtilde=>gUpDown Dirichlet_weight=>geom_w2 domain_weight=>geom_rvaschtot CASE (3) ! Two ellipses with "parallel" tangents with cylinders total_gtilde=>gUpDown Dirichlet_weight=>geom_w3 domain_weight=>geom_rvaschtot CASE (4) ! Two ellipses with same radii with cylinders total_gtilde=>gUpDown Dirichlet_weight=>geom_w4 domain_weight=>geom_rvaschtot CASE (5) ! Two ellipses with same radii with cylinders and total_gtilde=>gUpDown Dirichlet_weight=>geom_w5 domain_weight=>geom_rvaschtot CASE (6) ! circular coaxial tilted ellipse right Dirichlet total_gtilde=>gUpDown Dirichlet_weight=>geom_w6 domain_weight=>geom_rvaschtot CASE (7) ! circular coaxial tilted ellipse right and left Dirichlet total_gtilde=>gUpDown Dirichlet_weight=>geom_w7 domain_weight=>geom_rvaschtot CASE (8) ! circular coaxial tilted ellipse right and left Dirichlet total_gtilde=>gUpDown Dirichlet_weight=>geom_w8 domain_weight=>geom_rvaschtot CASE (9) ! Geometry defined as a spline curve total_gtilde=>gspline Dirichlet_weight=>geom_spline domain_weight=>geom_splinetot call read_splinebound(Fileid,the_domain, splrz, rnorm, phinorm) CASE (10) ! square section disc total_gtilde=>gUpDown domain_weight=>geom_rvaschtot Dirichlet_weight=>geom_w10 CASE DEFAULT ! Ellipse as in gt170 standard weight and straight coaxial configs total_gtilde=>gstd Dirichlet_weight=>geom_weightstd domain_weight=>geom_rvaschtot END SELECT ! If we are lauching a test case, we load the test_pars variable if(walltype.lt.0) then test_pars%Lr=(splrz%sp2%knots(splrz%sp2%nints)-splrz%sp2%knots(0))/testkr test_pars%Lz=(splrz%sp1%knots(splrz%sp1%nints)-splrz%sp1%knots(0))/testkz test_pars%r0=0.5*(splrz%sp2%knots(splrz%sp2%nints)+splrz%sp2%knots(0)) test_pars%z0=0.5*(splrz%sp1%knots(splrz%sp1%nints)+splrz%sp1%knots(0)) total_gtilde=>gtest end if end subroutine read_geom SUBROUTINE geom_init(spl2, vec1, vec2) type(spline2d):: spl2 real(kind=db):: vec1(:),vec2(:) Real(kind=db), Allocatable:: zgrid(:),rgrid(:) Integer:: nrank(2), nrz(2) Call get_dim(spl2, nrank, nrz) ! Obtain grid data drom the spline structure Allocate(zgrid(1:nrz(1)+1)) Allocate(rgrid(1:nrz(2)+1)) zgrid=spl2%sp1%knots(0:nrz(1)) rgrid=spl2%sp2%knots(0:nrz(2)) ! create a table of the calssification for each cell Allocate(gridcelltype(nrz(1),nrz(2))) Call classifycell(zgrid, rgrid, gridcelltype) if (nlweb) then Allocate(bsplinetype(nrank(1)*nrank(2))) Call classifyspline(spl2, gridcelltype, bsplinetype) Call buildetilde(spl2,bsplinetype,gridcelltype) end if ALLOCATE(gridwgeom((nrz(1)+1)*(nrz(2)+1),0:2)) gridwgeom=0 ALLOCATE(gridwdom((nrz(1)+1)*(nrz(2)+1),0:2)) gridwdom=0 ALLOCATE(gtilde((nrz(1)+1)*(nrz(2)+1),0:2)) gtilde=0 Call geom_weight (vec1, vec2, gridwgeom) CALL total_gtilde(vec1, vec2, gtilde, gridwgeom) Call dom_weight (vec1, vec2, gridwdom) end Subroutine geom_init Subroutine geom_diag(File_handle, str, rnorm) use mpi Use futils use weighttypes Integer:: File_handle Real(kind=db):: rnorm Character(len=*):: str CHARACTER(len=128):: grpname Integer:: ierr, mpirank CALL MPI_COMM_RANK(MPI_COMM_WORLD, mpirank, ierr) IF(mpirank .eq. 0) THEN Write(grpname,'(a,a)') trim(str),"/geometry" If(.not. isgroup(File_handle, trim(grpname))) THEN CALL creatg(File_handle, trim(grpname)) END IF Call attach(File_handle, trim(grpname), "r_a", r_a*RNORM) Call attach(File_handle, trim(grpname), "r_b", r_b*RNORM) Call attach(File_handle, trim(grpname), "z_a", z_a*RNORM) Call attach(File_handle, trim(grpname), "z_b", z_b*RNORM) Call attach(File_handle, trim(grpname), "z_0", z_0*RNORM) Call attach(File_handle, trim(grpname), "r_0", r_0*RNORM) Call attach(File_handle, trim(grpname), "r_r", r_r*RNORM) Call attach(File_handle, trim(grpname), "z_r", z_r*RNORM) Call attach(File_handle, trim(grpname), "L_r", test_pars%Lr*RNORM) Call attach(File_handle, trim(grpname), "L_z", test_pars%Lz*RNORM) Call attach(File_handle, trim(grpname), "interior", interior) Call attach(File_handle, trim(grpname), "above1", above1) Call attach(File_handle, trim(grpname), "above2", above2) Call attach(File_handle, trim(grpname), "walltype", walltype) Call putarr(File_handle, trim(grpname)//'/geomweight',gridwdom) Call putarr(File_handle, trim(grpname)//'/dirichletweight',gridwgeom) Call putarr(File_handle, trim(grpname)//'/gtilde',gtilde) Call putarr(File_handle, trim(grpname)//'/ctype',gridcelltype) Call putarr(File_handle, trim(grpname)//'/linked_s',linkedspline) Call putarr(File_handle, trim(grpname)//'/bsplinetype',bsplinetype) END IF End subroutine geom_diag Subroutine buildetilde(spl2, bsplinetype, celltype) USE mumps_bsplines Use basic, ONLY: rnorm, mpirank type(spline2d):: spl2 Integer:: bsplinetype(:) Integer:: celltype(1:,1:) Logical, Allocatable:: Ibsplinetype(:) Integer:: i,j,k, icellz, icellr, jcellz, jcellr, nrank(2), nrz(2), norder(2) real(kind=db), allocatable:: zgrid(:), rgrid(:) real(kind=db):: wgeomi, indexdistance, eij integer:: l,m, n, linkedi type(innerspline):: innersplinelist real(kind=db), allocatable:: rgridmesh(:),zgridmesh(:), d(:), hz(:), cz(:), hr(:), cr(:), hmesh(:) integer, allocatable:: igridmesh(:), jgridmesh(:) !if(allocated(etilde)) deallocate(etilde) nbreducedspline=count(bsplinetype .eq. 1) Call get_dim(spl2,nrank,nrz,norder) ! Obtain grid data drom the spline structure Allocate(zgrid(1:nrz(1)+1)) Allocate(rgrid(1:nrz(2)+1)) zgrid=spl2%sp1%knots(0:nrz(1)) rgrid=spl2%sp2%knots(0:nrz(2)) allocate(linkedspline(nrank(1),nrank(2))) allocate(innersplinelist%k(nrank(1)*nrank(2)),innersplinelist%weight(nrank(1)*nrank(2))) allocate(Ibsplinetype(nrank(1)*nrank(2))) allocate(rgridmesh(nrank(1)*nrank(2)), zgridmesh(nrank(1)*nrank(2))) allocate(igridmesh(nrank(1)*nrank(2)), jgridmesh(nrank(1)*nrank(2))) allocate(hmesh(nrank(1)*nrank(2))) allocate(d(size(bsplinetype))) Ibsplinetype=.False. call calcsplinecenters(spl2%sp1,cz,hz) call calcsplinecenters(spl2%sp2,cr,hr) Do i=0,nrank(2)-1 zgridmesh(i*nrank(1)+1:(i+1)*nrank(1))=cz rgridmesh(i*nrank(1)+1:(i+1)*nrank(1))=cr(i+1) hmesh(i*nrank(1)+1:(i+1)*nrank(1))=hr(i+1)*hz igridmesh(i*nrank(1)+1:(i+1)*nrank(1))=(/ (j,j=0,nrank(1)-1)/) jgridmesh(i*nrank(1)+1:(i+1)*nrank(1))=i End do ! allocate etilde and its transpose call init(nrank(1)*nrank(2),nbreducedspline,etilde) call init(nrank(1)*nrank(2),nbreducedspline,etildet) k=1 Do i=1,nrank(1)*nrank(2) if(bsplinetype(i) .ne. 1) cycle ! span of this spline is completely outside D ! one cell of bspline i is completely in D icellz=mod(i-1,nrank(1))+1 icellr=(i-1)/(nrank(1))+1 outer: do l=max(1,icellz-norder(1)),min(nrz(1),icellz) do m=max(1,icellr-norder(2)),min(nrz(2),icellr) if (celltype(l,m).eq.1) then call geom_weight((zgrid(l)+zgrid(l+1))/2,(rgrid(m)+rgrid(m+1))/2,wgeomi) EXIT outer end if end do end do outer call putele(etilde,k,i,1/wgeomi) call putele(etildet,i,k,1/wgeomi) innersplinelist%k(i)=k innersplinelist%weight(i)=1/wgeomi k=k+1 linkedspline(icellz,icellr)=i Ibsplinetype(i)=icellz+norder(1) .le. nrank(1) .and. icellr+norder(2) .le. nrank(2) if(.not. Ibsplinetype(i)) cycle do m=0,norder(2) do l=0,norder(1) ! Check if all positive splines in this spline domain are inner splines Ibsplinetype(i)=Ibsplinetype(i) .and. (bsplinetype(i+l+m*nrank(1)) .eq. 1) end do end do end do !!$OMP PARALLEL DO DEFAULT(SHARED), PRIVATE(d,k,icellz,icellr,jcellr,jcellz,indexdistance,n,i,m,l,eij,linkedi) Do j=1,nrank(1)*nrank(2) ! find the closest b-spline fully in D for the web method if(bsplinetype(j) .ne. 0) cycle d=0 where(Ibsplinetype)! calculate distance between center of Interior splines and spline j d=(zgridmesh(j)-zgridmesh)**2+(rgridmesh(j)-rgridmesh)**2 end where k=minloc(d,1,MASK=Ibsplinetype) icellz=mod(k-1,nrank(1)) icellr=(k-1)/(nrank(1)) jcellz=mod(j-1,nrank(1)) jcellr=(j-1)/(nrank(1)) indexdistance=real((jcellz-icellz)**2 + (jcellr-icellr)**2,kind=db) if(d(k) .gt. ((norder(1)+2)**2+(norder(2)+2)**2)*2 .and. mpirank .eq. 0)then Write(*,'(a)') 'Warning on system conditioning, the number of radial or axial points could be too low!' Write(*,'(a,1f6.2,a,2(1pe12.4))') 'Distance found: ', sqrt(indexdistance), ' at (z,r): ',zgridmesh(j)*rnorm, rgridmesh(j)*rnorm !stop end if linkedspline(jcellz+1,jcellr+1)=k do n=0,norder(2) do i=0,norder(1) eij=1 !eij=1 do m=0,norder(2) if(n.eq.m) cycle eij=eij*(rgridmesh(j)-rgridmesh(k+m*nrank(1)))/(rgridmesh(k+n*nrank(1))-rgridmesh(k+m*nrank(1))) !eij=eij*(jcellr-icellr-m)/(n-m) end do do l=0,norder(1) if( i .eq. l ) cycle eij=eij*(zgridmesh(j)-zgridmesh(k+l))/(zgridmesh(k+i)-zgridmesh(k+l)) !eij=eij*(jcellz-icellz-l)/(i-l) end do linkedi=innersplinelist%k(k+i+n*nrank(1)) ! equivalent to findloc, necessary for ifort 17 eij=eij*innersplinelist%weight(k+i+n*nrank(1)) call putele(etilde,linkedi,j,eij) call putele(etildet,j,linkedi,eij) end do end do end do !!$OMP End parallel do call to_mat(etilde) call to_mat(etildet) end subroutine Subroutine calcsplinecenters(spl,ctrs,heights) use bsplines type(spline1d):: spl real(kind=db), allocatable:: ctrs(:), heights(:) integer:: nrank, nx, order, i, left1, j, left2, left3 real(kind=db):: x1, x2, x3 real(kind=db), allocatable:: fun1(:,:), fun2(:,:), fun3(:,:) real(kind=db),allocatable:: init_heights(:) call get_dim(spl, nrank, nx, order) if (allocated(ctrs)) deallocate(ctrs) if (allocated(heights)) deallocate(heights) allocate(heights(nrank)) allocate(ctrs(nrank)) allocate(fun1(1:order+1,0:1), fun2(1:order+1,0:1), fun3(1:order+1,0:1)) allocate(init_heights(nrank)) init_heights=1.0 ctrs(:)=spl%knots(0:nrank-1) call gridval(spl, ctrs, heights, 0, init_heights) if (order .gt.1) then do i=2,nrank-1 x1=spl%knots(i-order)+1e5*Epsilon(x1) x2=spl%knots(i-1)-1e5*Epsilon(x2) left1=max(0,i-order) left2=min(nx-2,i-2) call basfun(x1,spl,fun1, left1+1) !Write(*,*) 'i,xpt,xptm,w,wold,',i,xpt,xptm,w,wold call basfun(x2,spl,fun2, left2+1) fun3=1 j=0 Do while( j .le. 300) !Write(*,*) 'i,xpt,xptm,w,wold,',i,xpt,xptm,w,wold x3=(x1+x2)/2 call locintv(spl, x3, left3) call basfun(x3,spl,fun3, left3+1) if( (x2-x1).lt.1e-13) exit if(abs(fun3(i-left3,1)).lt.1e-15) exit if(fun3(i-left3,1)*fun1(i-left1,1).le.0) then fun2=fun3 x2=x3 left2=left3 else fun1=fun3 x1=x3 left1=left3 end if j=j+1 End do ctrs(i)=x3 heights(i)=fun3(i-left3,0) end do end if end subroutine !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Subroutine classifycell(zgrid,rgrid,gridctype) Real(kind=db):: zgrid(:),rgrid(:) Integer:: gridctype(:,:) Integer::i,j gridctype=-1 !$OMP parallel do private(i) Do j=1,size(rgrid,1)-1 Do i=1,size(zgrid,1)-1 ! Determines the type inner/boundary/outer for each cell Call classification((/zgrid(i),zgrid(i+1)/),(/rgrid(j),rgrid(j+1)/),& & gridctype(i,j)) End Do End do !$OMP end parallel do End subroutine !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine classifyspline(spl2,gridctype,bsptype) type(spline2d):: spl2 Integer:: gridctype(:,:) Integer:: bsptype(:) Integer:: nrank(2), nrz(2), ndegree(2) Integer:: i, j, mu, imin, imax, jmin, jmax Integer, Allocatable:: splinespan(:,:) call get_dim(spl2, nrank, nrz, ndegree) ! by default, all splines have part of their support outside the domain D bsptype=0 Allocate(splinespan(ndegree(1)+1,ndegree(2)+1)) Do mu=1,nrank(1)*nrank(2) ! scan the spline space ! obtain the axial spline index i=mod(mu-1,nrank(1))+1 ! obtain the radial spline index j=(mu-1)/nrank(1)+1 ! by default all cells are outside for correct behavior in boundaries splinespan=-1 ! find the axial span of this spline in cell indices imin=max(1,i-ndegree(1)) imax=min(nrz(1),i) ! find the radial span of this spline in cell indices jmin=max(1,j-ndegree(2)) jmax=min(nrz(2),j) ! obtain the cell type on which the spline is defined splinespan(1:(imax-imin+1),1:(jmax-jmin+1))=gridctype(imin:imax,jmin:jmax) if ( ANY( splinespan==1 ) ) then ! if at least one cell is fully in the domain the spline is an inside spline bsptype(mu)=1 else if (.not. ANY( splinespan==0 )) then ! if all the cells are outside, this is an outside spline bsptype(mu)=-1 end if end do End subroutine !--------------------------------------------------------------------------- !> @author !> Guillaume Le Bars EPFL/SPC ! ! DESCRIPTION: !> !> @brief !> general placeholder function used in fields_mod to compute the weight for weighted_bsplines !> This functions combine an ellipse function and an horizontal wall ! !--------------------------------------------------------------------------- SUBROUTINE geom_weight0(z,r,w) Real(kind=db), INTENT(IN):: r,z Real(kind=db), INTENT(OUT):: w Real(kind=db):: rtmp(1:1), ztmp(1:1), wtmp(1:1,1:1) ztmp=z rtmp=r call Dirichlet_weight(ztmp,rtmp,wtmp) w=wtmp(1,1) End SUBROUTINE geom_weight0 SUBROUTINE geom_weight1(z,r,w) Real(kind=db), INTENT(IN):: r,z Real(kind=db), INTENT(OUT):: w(0:) Real(kind=db):: rtmp(1:1), ztmp(1:1) Real(kind=db):: wtmp(1:1,0:size(w,1)-1) ztmp=z rtmp=r call Dirichlet_weight(ztmp,rtmp,wtmp) w=wtmp(1,:) End SUBROUTINE geom_weight1 SUBROUTINE geom_weight2(z,r,w) Real(kind=db), INTENT(IN):: r(:),z(:) Real(kind=db), INTENT(OUT):: w(:,0:) call Dirichlet_weight(z,r,w) ! End SUBROUTINE geom_weight2 !--------------------------------------------------------------------------- !> @author !> Guillaume Le Bars EPFL/SPC ! ! DESCRIPTION: !> !> @brief !> general placeholder function used in fields_mod to compute the domain weight for weighted_bsplines !--------------------------------------------------------------------------- SUBROUTINE dom_weight0(z,r,w,idwall) Real(kind=db), INTENT(IN):: r,z Real(kind=db), INTENT(OUT):: w Real(kind=db):: rtmp(1:1), ztmp(1:1), wtmp(1:1,1:1) INTEGER:: idwalltmp(1:1) INTEGER, optional, INTENT(OUT):: idwall ztmp=z rtmp=r call domain_weight(ztmp,rtmp,wtmp,idwall=idwalltmp) w=wtmp(1,1) if (present(idwall)) idwall=idwalltmp(1) End SUBROUTINE dom_weight0 SUBROUTINE dom_weight1(z,r,w,idwall) Real(kind=db), INTENT(IN):: r,z Real(kind=db), INTENT(OUT):: w(0:) Real(kind=db):: rtmp(1:1), ztmp(1:1) Real(kind=db):: wtmp(1:1,0:size(w,1)-1) INTEGER:: idwalltmp(1:1) INTEGER, optional, INTENT(OUT):: idwall ztmp=z rtmp=r call domain_weight(ztmp,rtmp,wtmp,idwall=idwalltmp) w=wtmp(1,:) if (present(idwall)) idwall=idwalltmp(1) End SUBROUTINE dom_weight1 SUBROUTINE dom_weight2(z,r,w,idwall) Real(kind=db), INTENT(IN):: r(:),z(:) Real(kind=db), INTENT(OUT):: w(:,0:) INTEGER, optional, INTENT(OUT):: idwall(:) call domain_weight(z,r,w,idwall=idwall) ! End SUBROUTINE dom_weight2 SUBROUTINE dom_weight3(z,r,w,idwall) Real(kind=db), INTENT(IN):: r(:),z(:) Real(kind=db), INTENT(OUT):: w(:) Real(kind=db):: wtmp(size(w,1),1:1) INTEGER, optional, INTENT(OUT):: idwall(:) call domain_weight(z,r,wtmp,idwall=idwall) w=wtmp(:,1) ! End SUBROUTINE dom_weight3 SUBROUTINE geom_weightstd(z,r,w,wupper) ! return the geometric weight for a coaxial configuration ! or central conductor + ellipse Real(kind=db), INTENT(IN):: r(:),z(:) Real(kind=db), INTENT(OUT):: w(:,0:) Real(kind=db), OPTIONAL:: wupper(:,0:) Real(kind=db):: walltmp(size(w,1),0:size(w,2)-1), elliptmp(size(w,1),0:size(w,2)-1) Real(kind=db):: squareroot(size(w,1)), denom(size(w,1)) call cyllweight(z,r,walltmp, r_a, above1) SELECT CASE (walltype) CASE (0) call cyllweight(z,r,elliptmp, r_b, above2) CASE DEFAULT call ellipseweight(z,r,elliptmp,r_0, z_0, invr_z, invr_r, Interior) END SELECT - + + if (present(wupper))then + w=walltmp + wupper=elliptmp + return + end if if(interior.eq.0 .and. above2.eq.0) then w=walltmp(:,:) else if (above1 .eq. 0) then w=elliptmp(:,:) else denom=walltmp(:,0)**2+elliptmp(:,0)**2 squareroot=sqrt(denom) w(:,0)=walltmp(:,0)+elliptmp(:,0)-squareroot ! weight at position r,z If(size(w,2) .gt. 1) then ! first derivative w(:,1)=walltmp(:,1)+elliptmp(:,1)-(elliptmp(:,1)*elliptmp(:,0)+walltmp(:,1)*walltmp(:,0))/& & squareroot ! z derivative of w w(:,2)=walltmp(:,2)+elliptmp(:,2)-(elliptmp(:,2)*elliptmp(:,0)+walltmp(:,2)*walltmp(:,0))/& & squareroot ! r derivative of w End If End if End SUBROUTINE geom_weightstd SUBROUTINE classification(z, r, ctype) ! classify if cell is fully inside, outside or on the boundary of the domain real(kind=db), INTENT(IN):: r(2), z(2) INTEGER, INTENT(OUT):: ctype Real(kind=db)::weights(5,1:1) Real(kind=db):: zeval(5),reval(5) zeval=(/ z(1),z(2),z(1),z(2), (z(2)+z(1))/2 /) reval=(/ r(1),r(1),r(2),r(2), (r(2)+r(1))/2 /) CAll dom_weight(zeval,reval,weights) ctype=int(sign(1.0_db,weights(5,1))) If(weights(1,1)*weights(2,1) .le. 0 ) then ctype=0 return End If If(weights(1,1)*weights(3,1) .le. 0 ) then ctype=0 return End If If(weights(2,1)*weights(4,1) .le. 0 ) then ctype=0 return End If If(weights(3,1)*weights(4,1) .le. 0 ) then ctype=0 return End If end subroutine ! ################################################################## Subroutine calc_gauss(spl2, ngauss, i, j, xgauss, wgauss, gausssize, celltype) ! calculates the gauss integration points for the FEM method for any cell type ! takes care of boundary cells as well type(spline2d), INTENT(IN):: spl2 Integer, Intent(out):: gausssize INTEGER, Intent(out), Optional :: celltype Real(kind=db), Allocatable::rgrid(:),zgrid(:) Real(kind=db), ALLOCATABLE::xgauss(:,:), wgauss(:) Integer:: i,j, ngauss(2) Real(kind=db),Allocatable:: pts(:,:), zpoints(:) Real(kind=db):: zg(ngauss(1)),rg(ngauss(2)), wzg(ngauss(1)), wrg(ngauss(2)) Integer:: k, l, directiondown, directionup, nbzpoints, direction, ctype Logical:: hasmaxpoint Real(kind=db):: xptup, xptdown, w,wlu,wld, rmin, rmax type(spline1d):: splz, splr splz=spl2%sp1 splr=spl2%sp2 Allocate(zgrid(1:splz%nints+1)) Allocate(rgrid(1:splr%nints+1)) zgrid=splz%knots(0:splz%nints) rgrid=splr%knots(0:splr%nints) hasmaxpoint=.false. If(allocated(xgauss)) deallocate(xgauss) if(allocated(wgauss)) deallocate(wgauss) !Call classification((/zgrid(i),zgrid(i+1)/),(/rgrid(j),rgrid(j+1)/),ctype) ctype=gridcelltype(i,j) If (ctype .ge. 1) then ! we have a normal internal cell Allocate(xgauss(ngauss(1)*ngauss(2),2)) Allocate(wgauss(ngauss(1)*ngauss(2))) gausssize=ngauss(1)*ngauss(2) !Computation of gauss weight and position in r and z direction for gaussian integration CALL get_gauss(spl2%sp1, ngauss(1), i, zg, wzg) CALL get_gauss(spl2%sp2, ngauss(2), j, rg, wrg) ! Construction of matrix xgauss and wgauss storing the weight and position for 2d gaussian integration DO k=1,ngauss(2) xgauss((k-1)*ngauss(1)+1:k*ngauss(1),1)=zg xgauss((k-1)*ngauss(1)+1:k*ngauss(1),2)=rg(k) wgauss((k-1)*ngauss(1)+1:k*ngauss(1))=wrg(k)*wzg END DO Else If(ctype.eq.0) then ! we have a boundary cell !Call Boundary_Limits(pts) !Do k=1,size(pts,1) ! hasmaxpoint=hasmaxpoint .or. (pts(k,1) .ge. zgrid(i) .and. pts(k,1) .le. zgrid(i+1) & ! & .and. pts(k,2) .ge. rgrid(j) .and. pts(k,2) .le. rgrid(j+1)) !End do If(.not. hasmaxpoint) Then directiondown=1 directionup=1 ! We check if the boundary goes through the cell upper and lower limit Call Find_crosspointdico((/zgrid(i),zgrid(i+1)/),rgrid(j),xptdown,directiondown) Call Find_crosspointdico((/zgrid(i),zgrid(i+1)/),rgrid(j+1),xptup,directionup) call dom_weight(zgrid(i),rgrid(j),wld) call dom_weight(zgrid(i),rgrid(j+1),wlu) select case ( directionup+directiondown) Case (0) ! The intersections are only on the left and right cell boundaries ! or the upper and lower limits are full boundaries nbzpoints=2 Allocate(zpoints(nbzpoints)) zpoints=(/zgrid(i),zgrid(i+1)/) Case(1) if(directiondown.eq.1)then if( wlu .gt. 0) then ! the lower left corner is inside nbzpoints=3 Allocate(zpoints(nbzpoints)) zpoints=(/zgrid(i), xptdown,zgrid(i+1)/) else nbzpoints=2 Allocate(zpoints(nbzpoints)) if(wld.gt.0)then ! the upper left corner is inside zpoints=(/zgrid(i),xptdown/) else zpoints=(/xptdown,zgrid(i+1)/) end if end if else if(wld .gt. 0) then ! the lower left corner is inside nbzpoints=3 Allocate(zpoints(nbzpoints)) zpoints=(/zgrid(i), xptup,zgrid(i+1)/) else nbzpoints=2 Allocate(zpoints(nbzpoints)) if(wlu.gt.0)then ! the upper left corner is inside zpoints=(/zgrid(i),xptup/) else zpoints=(/xptup,zgrid(i+1)/) end if end if end if Case(2) nbzpoints=4 Allocate(zpoints(nbzpoints)) zpoints=(/zgrid(i),min(xptdown,xptup),max(xptdown,xptup), zgrid(i+1) /) !If(wld.lt.0) zpoints=(/min(xptdown,xptup),max(xptdown,xptup), zgrid(i+1) /) !else ! nbzpoints=2 ! Allocate(zpoints(nbzpoints)) ! If(wld.ge.0) zpoints=(/zgrid(i),min(xptdown,xptup) /) ! If(wld.lt.0) zpoints=(/max(xptdown,xptup), zgrid(i+1) /) !end if End select Allocate(xgauss(ngauss(1)*ngauss(2)*(nbzpoints-1),2)) Allocate(wgauss(ngauss(1)*ngauss(2)*(nbzpoints-1))) gausssize=ngauss(1)*ngauss(2)*(nbzpoints-1) ! Compute gauss points Do l=1,nbzpoints-1 !CALL get_gauss(spl2%sp1, ngauss(1), i, zg, wzg) Call gauleg(zpoints(l),zpoints(l+1),zg,wzg,ngauss(1)) ! We test if the lower or upper side is in the domain call dom_weight(zg(1),rgrid(j),wld) rmin=rgrid(j) if (wld .le. 0) rmin = rgrid(j+1) Do k=1,ngauss(1) direction=2 Call Find_crosspointdico((/rgrid(j),rgrid(j+1)/),zg(k),rmax,direction) ! We compute the radial limits at each z position Call gauleg(min(rmin,rmax),max(rmin,rmax),rg,wrg,ngauss(2)) ! We obtain the gauss w and pos for these boundaries xgauss(k+(l-1)*ngauss(1)*ngauss(2) : l*ngauss(2)*ngauss(1) : ngauss(1),1) = zg(k) xgauss(k+(l-1)*ngauss(1)*ngauss(2) : l*ngauss(2)*ngauss(1) : ngauss(1),2) = rg wgauss(k+(l-1)*ngauss(1)*ngauss(2) : l*ngauss(2)*ngauss(1) : ngauss(1)) = wrg*wzg(k) End do End Do End If Else gausssize=1 Allocate(xgauss(1:1,2)) Allocate(wgauss(1:1)) !Computation of gauss weight and position in r and z direction for gaussian integration CALL get_gauss(spl2%sp1, ngauss(1), i, zg, wzg) CALL get_gauss(spl2%sp2, ngauss(2), j, rg, wrg) ! Construction of matrix xgauss and wgauss storing the weight and position for 2d gaussian integration xgauss(1,1)=(zg(1)+zg(ngauss(1)))*0.5 xgauss(1,2)=(rg(1)+rg(ngauss(2)))*0.5 wgauss(1)=0 End If If(PRESENT(celltype)) celltype=ctype End Subroutine calc_gauss Subroutine Find_crosspoint(x,y,xpt, direction) ! calculates the boundary limit between x(1) and x(2) using Newton's method Real(kind=db):: x(2), y Real(kind=db):: xptm, xpt, temp Real(kind=db):: w, wold Real(kind=db):: w1, w2, w3 Real(kind=db):: x1, x2, x3 Integer, Intent(INOUT):: direction Integer:: i ! calculates the position of the boundary ( where the weight changes sign ) ! between x(1) and x(2) at 2nd coordinate y xptm=x(1) xpt=x(2) i=0 ! direction=1 finds cross-point along z if(direction .eq.1) Call dom_weight(xptm,y,wold) ! direction=2 finds cross-point along r if(direction .eq.2) Call dom_weight(y,xptm,wold) if(direction .eq.1) Call dom_weight(xpt,y,w) if(direction .eq.2) Call dom_weight(y,xpt,w) ! if the weight doesn't change sign there is no cross point if(w*wold.gt.0) then direction=0 return End If ! Find the cross-point Do while( i .le.100 .and. abs(w).gt.1e-9) !Write(*,*) 'i,xpt,xptm,w,wold,',i,xpt,xptm,w,wold xptm=xpt-w*(xpt-xptm)/(w-wold) wold=w temp=xptm xptm=xpt xpt=temp i=i+1 if(direction .eq.1) Call dom_weight(xpt,y,w) if(direction .eq.2) Call dom_weight(y,xpt,w) End do if(xpt .ge. x(2) .or. xpt .le. x(1) ) direction=0 End Subroutine Subroutine Find_crosspointdico(x,y,xpt, direction) ! calculates the boundary limit between x(1) and x(2) using dichotomy method Real(kind=db):: x(2), y Real(kind=db):: xpt Real(kind=db):: w1, w2, w3 Real(kind=db):: x1, x2, x3 Integer, Intent(INOUT):: direction Integer:: i ! calculates the position of the boundary ( where the weight changes sign ) ! between x(1) and x(2) at 2nd coordinate y x1=x(1) x2=x(2) i=0 select case(direction) case(1) ! direction=1 finds cross-point along z Call dom_weight(x1,y,w1) Call dom_weight(x2,y,w2) case(2) ! direction=2 finds cross-point along r Call dom_weight(y,x1,w1) Call dom_weight(y,x2,w2) end select ! if the weight doesn't change sign there is no cross point if(w1*w2.gt.0) then direction=0 xpt=x2 return End If ! Find the cross-point Do while( i .le. 500 .and. abs(x2-x1).gt.1e-13) x3=0.5*(x1+x2) i=i+1 select case(direction) case(1) ! direction=1 finds cross-point along z Call dom_weight(x3,y,w3) case(2) ! direction=2 finds cross-point along r Call dom_weight(y,x3,w3) end select if(w1*w3.gt.0)then! we are in a region were there is no change of sign x1=x3 w1=w3 else x2=x3 w2=w3 end if !if(abs(w3).lt.1e-14.and. w3 .ge.0)Exit End do xpt=x3 if(xpt .ge. x(2) .or. xpt .le. x(1) ) direction=0 End Subroutine SUBROUTINE geom_rvaschtot(z,r,w,idwall) ! returns the total weight which is the same as the Dirichlet weight for a boundary ! defined with Rvaschev functions Use splinebound, ONLY: spline_w Real(kind=db), INTENT(IN):: r(:),z(:) Real(kind=db), INTENT(OUT):: w(:,0:) Real(kind=db), allocatable:: w2(:,:) Real(kind=db), allocatable:: w3(:,:) INTEGER, optional, INTENT(OUT):: idwall(:) INTEGER:: sw2 sw2=size(w,2) if(present(idwall)) then idwall=0 allocate(w2(size(w,1),1:size(w,2))) allocate(w3(size(w,1),1:size(w,2))) call Dirichlet_weight(z,r,w2,w3) ! gives total weight where(w2(:,1).le.0) idwall=1 where(w3(:,1).le.0) idwall=2 call Combine(w2, w3, w, -1) else call Dirichlet_weight(z,r,w) end if End SUBROUTINE geom_rvaschtot Subroutine gstd(z,r,gtilde,w) ! g tilde function added to rhs of poisson solver for the standard coaxial configuration Real(kind=db), INTENT(IN):: r(:),z(:) Real(kind=db), INTENT(OUT):: gtilde(:,0:) Real(kind=db), INTENT(IN),OPTIONAL::w(:,0:) Real(kind=db):: belowtmp(size(r,1),0:size(gtilde,2)-1), abovetmp(size(r,1),0:size(gtilde,2)-1) Real(kind=db):: denom(size(r,1)) if (above1.eq.0) then gtilde=0 gtilde(:,0)=Phiup RETURN end if ! Weight functions necessary for calculation of g ! coaxial insert call cyllweight(z,r,belowtmp, r_a, above1) SELECT CASE (walltype) CASE (0) ! top cylinder call cyllweight(z,r,abovetmp, r_b, above2) CASE DEFAULT ! Ellipse as in gt170 call ellipseweight(z,r,abovetmp,r_0,z_0,invr_z,invr_r,Interior) END SELECT ! Extension to the whole domain of the boundary conditions ! constructed by weight multiplied with boundary value gtilde(:,0)=(Phidown*abovetmp(:,0) + Phiup*belowtmp(:,0) ) / & & (abovetmp(:,0)+belowtmp(:,0)) If(size(gtilde,2) .gt. 2) then ! first derivative denom=(abovetmp(:,0)+belowtmp(:,0))**2 gtilde(:,1)=(Phiup-Phidown)*(belowtmp(:,1)*abovetmp(:,0)-belowtmp(:,0)*abovetmp(:,1)) / & & denom ! Axial derivative gtilde(:,2)=(Phiup-Phidown)*(belowtmp(:,2)*abovetmp(:,0)-belowtmp(:,0)*abovetmp(:,2)) / & & denom ! Radial derivative End If End subroutine SUBROUTINE gUpDown(z,r,gtilde,w) ! g tilde function added to rhs of poisson solver by combining two boundaries set at different potentials Real(kind=db), INTENT(IN):: r(:),z(:) Real(kind=db), INTENT(OUT):: gtilde(:,0:) Real(kind=db), INTENT(IN),OPTIONAL::w(:,0:) Real(kind=db):: belowtmp(size(r,1),0:size(gtilde,2)-1), abovetmp(size(r,1),0:size(gtilde,2)-1) Real(kind=db):: denom(size(r,1)) ! Weight functions necessary for calculation of g call Dirichlet_weight(z,r,belowtmp,abovetmp) ! Extension to the whole domain of the boundary conditions ! constructed by weight multiplied with boundary value gtilde(:,0)=(Phidown*abovetmp(:,0) + Phiup*belowtmp(:,0) ) / & & (abovetmp(:,0)+belowtmp(:,0)) If(size(gtilde,2) .gt. 2) then ! first derivative denom=(abovetmp(:,0)+belowtmp(:,0))**2 gtilde(:,1)=(Phiup-Phidown)*(belowtmp(:,1)*abovetmp(:,0)-belowtmp(:,0)*abovetmp(:,1)) / & & denom ! Axial derivative gtilde(:,2)=(Phiup-Phidown)*(belowtmp(:,2)*abovetmp(:,0)-belowtmp(:,0)*abovetmp(:,2)) / & & denom ! Radial derivative End If END SUBROUTINE gUpDown Subroutine gtest(z,r,gtilde,w) ! calculates the Poisson gtilde term for testing the solver on a new geometry Real(kind=db), INTENT(IN):: r(:),z(:) Real(kind=db), INTENT(OUT):: gtilde(:,0:) Real(kind=db), INTENT(IN),OPTIONAL::w(:,0:) Real(kind=db):: wtmp(size(gtilde,1),0:size(gtilde,2)-1) ! if(present(w)) then wtmp=w else call Dirichlet_weight(z,r,wtmp) end if gtilde(:,0)=(sin(pi*(z-test_pars%z0)/(test_pars%Lz))*sin(pi*(r-test_pars%r0)/(test_pars%Lr))+2) If(size(gtilde,2) .gt. 1) then ! first derivative gtilde(:,1)=pi/(test_pars%Lz)*cos(pi*(z-test_pars%z0)/(test_pars%Lz))*sin(pi*(r-test_pars%r0)/(test_pars%Lr))*(1-wtmp(:,0))-wtmp(:,1)*gtilde(:,0) gtilde(:,2)=pi/(test_pars%Lr)*sin(pi*(z-test_pars%z0)/(test_pars%Lz))*cos(pi*(r-test_pars%r0)/(test_pars%Lr))*(1-wtmp(:,0))-wtmp(:,2)*gtilde(:,0) End If gtilde(:,0)=gtilde(:,0)*(1-wtmp(:,0)) End subroutine Subroutine ftest(z,r,f) ! calculates the Poisson source term for testing the solver on a new geometry Real(kind=db), INTENT(IN):: r(:),z(:) Real(kind=db), INTENT(OUT)::f(:,0:) ! f(:,0)=(pi/test_pars%Lz)**2*sin(pi*(z-test_pars%z0)/(test_pars%Lz))*sin(pi*(r-test_pars%r0)/(test_pars%Lr))& & + (pi/test_pars%Lr)*sin(pi*(z-test_pars%z0)/(test_pars%Lz))& & *( -1/r*(cos(pi*(r-test_pars%r0)/(test_pars%Lr))) + (pi/test_pars%Lr)*sin(pi*(r-test_pars%r0)/(test_pars%Lr))) End Subroutine ftest subroutine Reducematrix(full,reduced) ! Reduce the Finite element matrix from full spline space to reduced web-spline space use mumps_bsplines type(mumps_mat):: full, reduced, tempmat1, tempmat2 Integer:: fullrank, reducedrank Integer:: i,j, k call to_mat(full) fullrank=full%rank reducedrank=nbreducedspline call init(reducedrank,2,reduced) call init(fullrank,2,tempmat1) call init(reducedrank,2,tempmat2) tempmat1=mmx_mumps_mat_loc(full,etildet,(/fullrank,fullrank/),(/fullrank,reducedrank/),.false.) tempmat2=mmx_mumps_mat_loc(etildet,tempmat1,(/fullrank,reducedrank/),(/fullrank,reducedrank/),.true.) do i=1,reducedrank do k=tempmat2%irow(i),tempmat2%irow(i+1)-1 j=tempmat2%cols(k) call putele(reduced, i, j, tempmat2%val(k)) end do end do end subroutine !++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ FUNCTION mmx_mumps_mat_loc(mata, matb, ranka, rankb, transpose) RESULT(matc) ! ! Return product matc=mata*matb ! All matrices are represented in csr sparse representation ! Use mumps_bsplines TYPE(mumps_mat) :: mata,matb,matc INTEGER:: ranka(2), rankb(2) ! nb of (rows,columns) for each matrix INTEGER :: n, info, m, request, sort LOGICAL:: transpose Character(1):: T ! m=ranka(1) n=ranka(2) T='N' if (transpose)then T='T' m=ranka(2) n=ranka(1) end if !#ifdef MKL ! if(associated(matc%val)) deallocate(matc%val) if(associated(matc%cols)) deallocate(matc%cols) if(associated(matc%irow)) deallocate(matc%irow) allocate(matc%irow(m+1)) allocate(matc%cols(1)) allocate(matc%val(1)) request=1 sort=7 CALL mkl_dcsrmultcsr(T, request, sort, ranka(1), ranka(2), rankb(2), & & mata%val, mata%cols, mata%irow(1), & & matb%val, matb%cols, matb%irow(1), & & matc%val, matc%cols, matc%irow(1), & & 1, info) if(info .gt. 0) WRITE(*,'(a,i4)') " Error in mmx_mumps_mat_loc: ", info if(associated(matc%val)) deallocate(matc%val) if(associated(matc%cols)) deallocate(matc%cols) allocate(matc%val(matc%irow(m+1)-1)) allocate(matc%cols(matc%irow(m+1)-1)) request=2 CALL mkl_dcsrmultcsr(T, request, sort, ranka(1), ranka(2), rankb(2), & & mata%val, mata%cols, mata%irow(1), & & matb%val, matb%cols, matb%irow(1), & & matc%val, matc%cols, matc%irow(1), & & 1, info) if(info .ne. 0) WRITE(*,'(a,i4)') " Error in mmx_mumps_mat_loc: ", info if (transpose)then matc%rank=ranka(2) else matc%rank=ranka(1) end if ! END FUNCTION mmx_mumps_mat_loc END MODULE geometry diff --git a/src/intel_ppb110.mk b/src/intel_ppb110.mk new file mode 100644 index 0000000..bd48aff --- /dev/null +++ b/src/intel_ppb110.mk @@ -0,0 +1,23 @@ +CC = icc +CFLAGS = +FC = mpiifort +# +#PARMETIS=$(PARMETIS_ROOT) +#MUMPSLIBS= -ldmumps -lzmumps -lmumps_common -lpord +#XGRAFIX=$(HOME)/lib/intel/xgrafix +#MUMPS=$(MUMPS_ROOT) +#HDF5=$(HDF5_ROOT) +# +RELEASEFLAGS = -fpp -mkl=cluster -qopenmp -qopenmp-simd -O3 -xHost -warn all +FFLAGS = -fpp -g -traceback -check bounds -mkl=cluster -O3 +DEBUGFLAGS = -fpp -g -O0 -xHost -qopenmp -qopenmp-simd -traceback -mkl=cluster\ + -check all -check bounds -check noarg_temp_created \ + -warn all -ftrapuv -fpe0 -debug extended \ + -check uninit -debug all -diag-enable=all +PROFILEFLAGS= -g + +F90 = $(FC) +F90FLAGS= $(RELEASEFLAGS) -I/home/lebars/lib/intel/SISL/include \ + -I/home/lebars/lib/intel/forSISL/include +LDFLAGS = +LIBS = /home/lebars/lib/intel/forSISL/lib/forsisl.a /home/lebars/lib/intel/SISL/lib/libsisl.a diff --git a/wk/gt170_refurb_deep_well/electron_tracers.in b/wk/gt170_refurb_deep_well/electron_tracers.in new file mode 100644 index 0000000..b8ee847 --- /dev/null +++ b/wk/gt170_refurb_deep_well/electron_tracers.in @@ -0,0 +1,21 @@ +&partsload +mass=9.10938300000000e-31, +charge=-1.60217662000000e-19, +!weight=1.07241110779661e+04, +weight=2e+06, +H0=3.20000000000000e-14, +P0=8.66000000000000e-25, +nblock=1, +npartsalloc=200, +velocitytype=1, +radialtype=2, +temperature=2.20000000000000e+04, +is_test=t, +is_field=f, +calc_moments=f, +qmratioscale=0.001 +/ + +//slices +0.02 0.065 0.079 200 +0.1 diff --git a/wk/gt170_refurb_deep_well/electrons_gauss.in b/wk/gt170_refurb_deep_well/electrons_gauss.in new file mode 100644 index 0000000..073a5a6 --- /dev/null +++ b/wk/gt170_refurb_deep_well/electrons_gauss.in @@ -0,0 +1,21 @@ +&partsload +mass=9.10938300000000e-31, +charge=-1.60217662000000e-19, +!weight=1.07241110779661e+04, +weight=1.000e+08, +H0=3.20000000000000e-14, +P0=8.66000000000000e-25, +nblock=1, +npartsalloc=10, +velocitytype=1, +radialtype=2, +temperature=2.20000000000000e+04, +is_test=f, +is_field=t, +calc_moments=t, +qmratioscale=1.0 +/ + +//slices +0.02 0.062 0.079 000 +0.1 diff --git a/wk/gt170_refurb_deep_well/ion_tracers.in b/wk/gt170_refurb_deep_well/ion_tracers.in new file mode 100644 index 0000000..2310f43 --- /dev/null +++ b/wk/gt170_refurb_deep_well/ion_tracers.in @@ -0,0 +1,20 @@ +&partsload +mass=3.347e-29, +charge=1.60217662000000e-19, +!weight=1.07241110779661e+04, +weight=2e6, +H0=3.20000000000000e-14, +P0=8.66000000000000e-25, +nblock=1, +npartsalloc=100, +velocitytype=1, +radialtype=2, +temperature=300, +is_test=t, +is_field=f, +calc_moments=f +/ + +//slices +0.02 0.065 0.079 000 +0.03 diff --git a/wk/gt170_refurb_deep_well/job.in b/wk/gt170_refurb_deep_well/job.in new file mode 100644 index 0000000..4f4fc61 --- /dev/null +++ b/wk/gt170_refurb_deep_well/job.in @@ -0,0 +1,120 @@ +A Skeleton for MPI Time-Dependent program +========================================= +T.M. Tran SPC/EPFL +- +&BASIC + job_time=43000.0, extra_time=200.0, + nrun=400000, !# of steps + nlres=f, + newres=f, + femorder=3,3, + ngauss=6,6, + nlppform=.TRUE. + partperiodic=f + nlxg=f, ! Display graphical interface + nlclassical=t, ! Solve classical equations of motion + it0d=5, + it2d=200, + ittext=100, + itparts=5000, + ittracer=1000, + itgraph=100, + nbcelldiag=0, + itcelldiag=20, + resfile='/misc/tes_NIPS.h5' + rstfile='/misc/res_NIPS.h5' + nbspecies=3, + partfile='electrons_gauss.in','electron_tracers.in','ion_tracers.in', + + radii=0.045,0.092! + nnr=334!43!344!55,90,45 !# of intervals between radii(1) and radii(2), between radii(2) and radii(3) and between radii + !nnr=202,120,48,140,32!188,!# of intervals between radii(1) and radii(2) + !radii=0.0085,0.059,0.065,0.077,0.084,0.092 + + !radii=0.05, 0.076, 0.081,0.091 !radius of inner metallic wall, plasma boundaries and outer metallic wall + plasmadim=-0.009, 0.0155, 0.074, 0.078, !zmin zmax rmin rmax of initial plasma loading + distribtype=7 ! 1: uniform RZ gaussian in V, 2: stable eq 4.85 from Davidson + !lz=-0.29,0.290, !Cylinder length + !nz=2336!1200!195!1560, !# of intervals in z + + lz=-0.1,0.192, !Cylinder length + nz=240!1200!195!1560, !# of intervals in z + + nplasma=2116800, !132300, ! 100000# of superparticles + nlmaxwellsource=t, + nblock=2000, + nlPhis=f, ! if false deactivate calculation of self electric fieldq +! nplasma=100 + potinn=-30000, !potential at inner wall [V] + potout=0, !30000, !potential at outer wall [V] + B0=0.23, !Davidson chapter 4 formula 4.89 [T] + Rcurv=1.5,!1.001, !Davidson chapter 4 formula 4.89 + width=0.48, + n0=-3e17, dt=2E-12 !Initial plasma density in plasmadim +! n0=-4E16, dt=8E-12 +! n0=-5.e15, dt=8E-12, +! n0=-3.e19, dt=8e-13, +! n0=-5.e8 + temp=22000, !Initial temperature of plasma [K] (thermal velocity) + H0=3.2e-14, + P0=8.66e-25, + magnetfile='../../matlab/Magnetic_Field_GLS_2020/Cryogenic/phiBprofile_refurbasg_48_red.h5' + bscaling=0, +/ + +&maxwellsourceparams +frequency=5E10, +temperature=22000, +rlimits=0.010,0.081, +zlimits=-0.010,0.15 +time_start=-1.0, +radialtype=2 +time_end=0 +/ + +&geomparams +testkr=5 +testkz=5 +r_a=0.0051 +r_b=0.0909 +z_a=-0.05 +z_b=0.05 +! Z_0 = 0.095, +! R_0 = 0.091 , +! Z_R = 0.160000000000000 , +! R_R = 1.000000000000000E-002, +! !WALLTYPE = -2, +! L_R = 0.120000000000000 , +! L_Z = 0.960000000000000 , +walltype=9 ! ellipse plus flat bottom and flat top +nlweb=t +/ + +&spldomain +dist_extent=3.5e-3, +epsge=1e-5 +epsce=1e-10 +h5fname='refurb_geom_open.h5', +Dvals=-0,0,0 +/ + +&neutcolparams +neutdens=2.5e20, +!Neon parameters +Eion=15.4, +scatter_fac=8.3, +nlcol=t, +!species=1,3 +io_cross_sec_file='/home/lebars/espic2d/wk/H2_io_cross_sec.in', +ela_cross_sec_file='/home/lebars/espic2d/wk/H2_ela_cross_sec.in', +/ + +&psupplyparams +expneutdens=2.5e17, +PsResistor=1e6, +geomcapacitor=8e-11 +targetbias=90000 +nbhdt=10 +active=t, +bdpos=-1,1,1 +/ \ No newline at end of file diff --git a/wk/gt170_refurb_deep_well/proto_geom.h5 b/wk/gt170_refurb_deep_well/proto_geom.h5 new file mode 100644 index 0000000..84c334c Binary files /dev/null and b/wk/gt170_refurb_deep_well/proto_geom.h5 differ diff --git a/wk/gt170_refurb_deep_well/refurb_geom.h5 b/wk/gt170_refurb_deep_well/refurb_geom.h5 new file mode 100644 index 0000000..54269e4 Binary files /dev/null and b/wk/gt170_refurb_deep_well/refurb_geom.h5 differ diff --git a/wk/gt170_refurb_deep_well/refurb_geom_4.h5 b/wk/gt170_refurb_deep_well/refurb_geom_4.h5 new file mode 100644 index 0000000..229576a Binary files /dev/null and b/wk/gt170_refurb_deep_well/refurb_geom_4.h5 differ diff --git a/wk/gt170_refurb_deep_well/refurb_geom_open.h5 b/wk/gt170_refurb_deep_well/refurb_geom_open.h5 new file mode 100644 index 0000000..54269e4 Binary files /dev/null and b/wk/gt170_refurb_deep_well/refurb_geom_open.h5 differ diff --git a/wk/gt170_refurb_deep_well/stable.sh b/wk/gt170_refurb_deep_well/stable.sh new file mode 100755 index 0000000..aceaf2b --- /dev/null +++ b/wk/gt170_refurb_deep_well/stable.sh @@ -0,0 +1,126 @@ +#!/bin/bash -l +#SBATCH --job-name=espic2d +#SBATCH --time=12:00:00 +#SBATCH -n 6 +#SBATCH -c 6 +#SBATCH --mem=144G +#srun amplxe-cl -c hotspots -r results_$nbprocs -- ../src/espic2d < stable.in +module purge +module restore espic2d-intel +export I_MPI_PLATFORM=auto +export espicsrc='/home/lebars/espic2d/src' +export espicwk='/home/lebars/espic2d/wk' +res_folder='/scratch/lebars/gt170_refurbished/Deep_well/' +mkdir -p $res_folder +cat > job.in << EOM +A Skeleton for MPI Time-Dependent program +========================================= +T.M. Tran SPC/EPFL +- +&BASIC + job_time=43000.0, extra_time=200.0, + nrun=100, !# of steps + nlres=f, + newres=f, + femorder=2,2, + ngauss=6,6, + nlppform=.TRUE. + partperiodic=f + nlxg=f, ! Display graphical interface + nlclassical=t, ! Solve classical equations of motion + nz=600, !# of intervals in z + nnr=65,80,25 !# of intervals between radii(1) and radii(2), between radii(2) and radii(3) and between radii(3) and radii(4) + it0d=10, + it2d=100, + ittext=100, + itparts=5000, + ittracer=10, + itgraph=100, + nbcelldiag=1, + itcelldiag=20, + resfile='${res_folder}tes30kv_w.h5' + rstfile='${res_folder}res30kv_w.h5' + nbspecies=3, + partfile='electrons_gauss.in','electron_tracers.in','ion_tracers.in', + + radii=0.055, 0.076, 0.080,0.091 !radius of inner metallic wall, plasma boundaries and outer metallic wall + plasmadim=-0.009, 0.0155, 0.074, 0.078, !zmin zmax rmin rmax of initial plasma loading + distribtype=7 ! 1: uniform RZ gaussian in V, 2: stable eq 4.85 from Davidson + lz=-0.1,0.185, !Cylinder length + + nplasma=2116800, !132300, ! 100000# of superparticles + nlmaxwellsource=t, + nblock=2000, + nlPhis=t, ! if false deactivate calculation of self electric fieldq +! nplasma=100 + potinn=-30000, !potential at inner wall [V] + potout=0, !30000, !potential at outer wall [V] + B0=0.23, !Davidson chapter 4 formula 4.89 [T] + Rcurv=1.5,!1.001, !Davidson chapter 4 formula 4.89 + width=0.48, + n0=-3e17, dt=2E-12 !Initial plasma density in plasmadim +! n0=-4E16, dt=8E-12 +! n0=-5.e15, dt=8E-12, +! n0=-3.e19, dt=8e-13, +! n0=-5.e8 + temp=22000, !Initial temperature of plasma [K] (thermal velocity) + H0=3.2e-14, + P0=8.66e-25, + magnetfile='phiBprofile_refurbasg_well' + bscaling=0, +/ + +&maxwellsourceparams +frequency=5E8, +temperature=22000, +rlimits=0.064,0.081, +zlimits=-0.010,0.034 +time_start=-1.0, +radialtype=2 +time_end=-1.0 +/ + +&celldiagparams +specieid=1, +rindex=112, +zindex=117, +/ + +&geomparams +!x=0.028/2*cos(t)+0.012;y=0.002*sin(t)+0.081 +r_a=0.06375 +z_0=0.012 +r_0=0.081 +z_r=0.014 +r_r=0.002 +r_b=0.081 +above2=-1 +walltype=9 ! ellipse plus flat bottom and flat top +nlweb=t +/ + +&spldomain +nbsplines=2, +dist_extent=5e-3, +dr=-0.002, +Lz=0.014, +ra=0.06375, +rb=0.081 +epsge=1e-5 +epsce=1e-10 +h5fname='refurb_geom.h5', +/ + +&neutcolparams +neutdens=2.5e21, +!Neon parameters +Eion=21.56, +scatter_fac=24.2, +nlcol=t, +io_cross_sec_file='${espicwk}/Ne_io_cross_sec.in', +ela_cross_sec_file='${espicwk}/Ne_ela_cross_sec.in', +/ +EOM +export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK +#srun -n $nbprocs ../src/espic2d "$VAR" +srun $espicsrc/espic2d job.in diff --git a/wk/stable.sh b/wk/stable.sh new file mode 100755 index 0000000..9ae87dc --- /dev/null +++ b/wk/stable.sh @@ -0,0 +1,73 @@ +#!/bin/bash -l +#SBATCH --job-name=espic2d +#SBATCH --time=12:00:00 +#SBATCH --hint=nomultithread +#SBATCH -c 4 +#SBATCH -n 2 +#srun amplxe-cl -c hotspots -r results_8 -- ../src/espic2d < stable8.in +#export I_MPI_HYDRA_BOOTSTRAP=ssh +export I_MPI_DEBUG=1000 +cat >job.in << EOM +A Skeleton for MPI Time-Dependent program +========================================= +T.M. Tran SPC/EPFL +- +&BASIC + job_time=144000.0, extra_time=360.0, + nrun=100000, !# of steps + nlres=f, + femorder=3,3, + ngauss=4,4, + nlppform=.TRUE. + nlxg=f, ! Display graphical interface + nlclassical=t, ! Solve classical equations of motion + dt=8E-12, !timestep [s] + nz=128, !# of intervals in z + nnr=10,40,30 !# of intervals between radii(1) and radii(2), between radii(2) and radii(3) and between radii(3) and radii(4) + it0d=10, + it2d=100, + ittext=100, + itparts=5000, + itgraph=100, + resfile='stable_13_fine.h5' + + radii=0.001,6e-3,9e-3,0.16 !radius of inner metallic wall, plasma boundaries and outer metallic wall + plasmadim=-0.10, 0.10, 0.0070, 0.0074, !zmin zmax rmin rmax of initial plasma loading + distribtype=1 ! 1: uniform RZ gaussian in V, 2: stable eq 4.85 from Davidson + lz=-0.32,0.32, !Cylinder length + + nplasma=529200 !132300, ! 100000# of superparticles + npartsalloc=600000 + nblock=1000, + nlPhis=t, ! Deactivate calculation of self electric field +! nplasma=100 + potinn=-20000, !potential at inner wall [V] + potout=0, !30000, !potential at outer wall [V] + B0=0.21, !Davidson chapter 4 formula 4.89 [T] + Rcurv=3,!1.001, !Davidson chapter 4 formula 4.89 + width=0.64, + n0=-5e13, dt=8E-13 !Initial plasma density in plasmadim +! n0=-4E16, dt=8E-12 +! n0=-5.e15, dt=8E-12, +! n0=-3.e19, dt=8e-13, +! n0=-5.e8 + temp=10000, !Initial temperature of plasma [K] (thermal velocity) + !H0=3.2e-14, + !P0=8.66e-25, +/ + +&geomparams +r_a=0.001, +r_b=0.16 +nlweb=t, +walltype=0, +above1=1, +above2=-1, +/ + + +EOM +export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK +mpirun -np 2 ../../src/espic2d job.in + +