Skip to content
Snippets Groups Projects
Commit de5e78db authored by Francois POLACK's avatar Francois POLACK
Browse files

Feature: nexus_Save : save the height map under NeXus format

	 fix issues with scales
parent 773080b7
No related branches found
No related tags found
No related merge requests found
......@@ -41,6 +41,8 @@ import ZygoDatx
from processing import *
from activefigure import *
import pickle
from pathlib import Path
from nexusformat.nexus.tree import *
class HeightMap(object):
'''! @brief The HeightMap object-
......@@ -87,8 +89,8 @@ class HeightMap(object):
self.dzdx = None
## slope dze/dy
self.dzdy = None
## the fit parameter (rx, pitch, ry, roll, z0) [unused]
self.fitpars = None
## the fit parameter (rot,rx, pitch, ry, roll, Z0) [unused]
self.fitparams = None
## slope rms CPSD
self.srms = None
......@@ -102,9 +104,10 @@ class HeightMap(object):
self.angle=None
self.Cx=None
self.Cy=None
## fiducial list and sample drawing defined 25/09/2023
self.fiducial_list=None
self.reference_point=None
self.sample_drawing=None
def read_Zygofile(self, filename='', origin='zero' ):
"""! Reads a Zygo datafile in .datx, .dat or xyz format, and loads it into the HeightMap object.
......@@ -204,8 +207,8 @@ class HeightMap(object):
"""
size=(self.pixel[0]*self.z.shape[1],self.pixel[1]*self.z.shape[0])
org=((self.pixel[0]+offset[0])*self.origin[0], (self.pixel[1]+offset[1]*self.origin[1]))
# org corrigé le 25/09/23 - FP
org=(self.pixel[0]*(offset[0]+self.origin[0]), self.pixel[1]*(offset[1]+self.origin[1]))
self.x=np.linspace(org[0],org[0]+size[0],num=self.z.shape[1], endpoint=False)
self.y=np.linspace(org[1],org[1]+size[1],num=self.z.shape[0], endpoint=False)
......@@ -274,8 +277,8 @@ class HeightMap(object):
and assign the residuals of the fit to the height error array (HeightMap.ze)
"""
print("\nRemove best toroid with axis orientation {:.3f}mrad=".format(1e3*rot))
(fitparams, self.ze) = fit_toroid(self.x,self.y,self.z, rot)
(Z0, pitch, roll, x2, y2)=fitparams
(fitcoeffs, self.ze) = fit_toroid(self.x,self.y,self.z, rot)
(Z0, pitch, roll, x2, y2)=fitcoeffs
self.angle=rot
# these are the removed curvatures = 1/R
self.Cx=2*x2
......@@ -289,7 +292,8 @@ class HeightMap(object):
rx = 0.5/ x2
except ZeroDivisionError:
rx=math.inf
print("debug: fit params:" , fitparams)
self.fitparams=(rot,rx, pitch, ry, roll, Z0)
print("debug: fit params:" , fitcoeffs)
print("rx = {:.3e}m, pitch = {:.4e}rad, ry = {:.3e}m, roll = {:.4e}rad, Z0 = {:.3e}m".
format(rx, pitch, ry, roll, Z0))
self.detrend='tore'
......@@ -637,9 +641,97 @@ class HeightMap(object):
plt.ylabel('y (mm)')
plt.title("testplot")
def nexus_save(self,filepath):
fname=Path(filepath).with_name(Path(filepath).stem+'.nxs')
print("creating file ", fname)
# print("flipped axes", self.flipROI) WARNING if ROI is flipped the reference frame of rawZ and z are different
#define the absolute coordinates
xpix=self.pixel[0]
ypix=-self.pixel[1]
# set the coordinate origin in pixel units
if self.fiducial_list !=None and self.reference_point != None :
refpoint=self.fiducial_list[self.reference_point['name']]
# this is true if ref point is in meter and fiducials in pixels
origin_x=refpoint['coordinates'][0]-self.reference_point['coordinates'][0]/xpix
origin_y=refpoint['coordinates'][1]-self.reference_point['coordinates'][1]/ypix
print ('origin =(', origin_x, ', ', origin_y, ')')
print ('ROI origin =(', self.ROIorigin[0], ', ', self.ROIorigin[1], ')')
else:
origin_x=0
origin_y=rawZ.shape[0]-1
# Create raw_data
xraw=np.linspace(-origin_x*xpix,(self.rawZ.shape[1]-origin_x)*xpix,num=self.rawZ.shape[1], endpoint=False)
yraw=np.linspace(-origin_y*ypix,(self.rawZ.shape[0]-origin_y)*ypix,num=self.rawZ.shape[0], endpoint=False)
x=NXfield(xraw, name='x', unit='meter')
y=NXfield(yraw, name='y', unit='meter')
rawdata=NXdata(NXfield(self.z, name='height', unit='meter'),[x,y],name='raw_data')
#create detrended data group wit height and slope fields
height=NXfield(self.ze, name='height', unit='meter')
xview=np.linspace((self.ROIorigin[0]-origin_x)*xpix,(self.ROIorigin[0]+self.ROIsize[0]-origin_x)*xpix,num=self.z.shape[1], endpoint=False)
yview=np.linspace((self.ROIorigin[1]-origin_y)*ypix,(self.ROIorigin[1]+self.ROIsize[1]-origin_y)*ypix,num=self.z.shape[0], endpoint=False)
x=NXfield(xview, name='x', unit='meter')
y=NXfield(yview, name='y', unit='meter')
slope_x=NXfield(self.dzdx, unit='radian')
slope_y=NXfield(self.dzdy, unit='radian')
detrended=NXdata(height,[x,y], slope_x=slope_x, slope_y=slope_y, name='detrended_data')
#create the process group with detrending parameters and ROI definition
region=NXgroup( name='ROI', nxclass='NXregion', start=self.ROIorigin, count=self.ROIsize)
region.region_type=NXattr('rectangular')
process=NXprocess(region)
process.program=NXattr('detrend')
process.fit=NXattr('toroid')
process.radius_x=NXfield(self.fitparams[1],unit='meter')
process.radius_y=NXfield(self.fitparams[3],unit='meter')
process.rotation=NXfield(self.fitparams[0],unit='meter')
# the process.data group defining the process group will be a link. It cannot be set before the whole tree is created
#attach the process group to the detrended data group
detrended.process=process
#create the sample and instrument group
sample=NXsample()
detector=NXdetector(pixel_size_x=NXfield(self.pixel[0], unit='meter'), pixel_size_y=NXfield(self.pixel[1], unit='meter'))
instrument= NXinstrument(detector)
#Create the measurement NXentry as complying to NXmetrology definition
entry=NXentry(detrended,rawdata,sample,instrument, name='measurement1')
entry.definition=NXattr('NXmetrology')
# add the data group as link to detrended group and set it as default
entry.data=NXlink(detrended)
entry.data.set_default()
# add a the source data to the process group as alink
process.data=NXlink(rawdata)
#add a drawing in the sample group if defined
if self.sample_drawing!=None:
add_drawing(sample,self.sample_drawing)
#add a fiducial group to the sample group
if self.fiducial_list != None:
sample.fiducials=NXgroup(nxclass='NXfiducials')
for name in self.fiducial_list:
fiducial=self.fiducial_list[name]
coord=((fiducial['coordinates'][0]-origin_x)*xpix, (fiducial['coordinates'][1]-origin_y)*ypix)
sample.fiducials.insert(NXfield(coord, name=name))
#print(name, ': ', fiducial['mark'], fiducial['coordinates'][0]*self.pixel[0]*1.e3, fiducial['coordinates'][1]*self.pixel[1]*1.e3,'mm')
# erase the old file if any and write the NeXus tree to the file
if Path(fname).exists():
Path(fname).unlink()
entry.save(fname)
def add_drawing(parent,filename):
ext=Path(filename).suffix
if ext=='.svg' or ext=='.dxf':
with open(filename, 'r') as file:
text=file.read()
parent.drawing=NXfield(text)
elif ext=='.pdf':
with open(filename,'rb') as file:
filedata=file.read()
parent.drawing=NXfield(bytearray(filedata), dtype='uint8')
else:
print("Invalid drawing file extension: ", ext)
parent.drawing.format=NXattr(ext)
# this function return a HeightMap object from a previously saved .hmap file
def load(self, filepath=''):
# this module function returns a HeightMap object from a previously saved .hmap file
def load(filepath=''):
if not Path(filepath).is_file():
tkinter.Tk().withdraw()
filepath=filedialog.askopenfilename(title="open a hmap file", filetypes=(("superflat hmap","*.hmap"), ("all","*.*") ) )
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment