"""
S4OpticalSurface — abstract base class for optical surface shapes used in wofryimpl mirror elements.
"""
# abstract class defining the interfaces of the optical surfaces to be implemented in the children classes
# it also defines common utilities
import numpy
import os
import h5py
import time
[docs]
class S4OpticalSurface(object):
[docs]
def info(self):
raise NotImplementedError
[docs]
def duplicate(self):
raise NotImplementedError
[docs]
def surface_height(self, x, y, **kwargs):
raise NotImplementedError
[docs]
def get_normal(self, x, **kwargs):
raise NotImplementedError
[docs]
def calculate_intercept(self, XIN, VIN, **kwargs):
raise NotImplementedError
[docs]
def apply_specular_reflection_on_beam(self, beam, **kwargs):
raise NotImplementedError
[docs]
def apply_refraction_on_beam(self, beam, **kwargs):
raise NotImplementedError
[docs]
def apply_crystal_diffraction_bragg_symmetric_on_beam(self, beam, **kwargs):
raise NotImplementedError
#
# common utilities
#
[docs]
def write_mesh_file(self, x, y, filename="surface.dat"):
X = numpy.outer(x, numpy.ones_like(y))
Y = numpy.outer(numpy.ones_like(x), y)
Z = self.surface_height(X, Y)
write_shadow_surface(Z.T, x, y, outFile=filename)
[docs]
def write_mesh_h5file(self, x, y, filename="surface.h5", subgroup_name="surface_file", overwrite=True):
X = numpy.outer(x, numpy.ones_like(y))
Y = numpy.outer(numpy.ones_like(x), y)
Z = self.surface_height(X, Y)
if (os.path.isfile(filename)) and (overwrite == True): os.remove(filename)
if not os.path.isfile(filename): # if file doesn't exist, create it.
file = h5py.File(filename, 'w')
# points to the default data to be plotted
file.attrs['default'] = subgroup_name + '/Z'
# give the HDF5 root some more attributes
file.attrs['file_name'] = filename
file.attrs['file_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
file.attrs['creator'] = 'write_surface_file'
file.attrs['code'] = 'Oasys'
file.attrs['HDF5_Version'] = h5py.version.hdf5_version
file.attrs['h5py_version'] = h5py.version.version
file.close()
file = h5py.File(filename, 'a')
try:
f1 = file.create_group(subgroup_name)
except:
f1 = file[subgroup_name]
f1z = f1.create_dataset("Z", data=Z.T)
f1x = f1.create_dataset("X", data=x)
f1y = f1.create_dataset("Y", data=y)
# NEXUS attributes for automatic plot
f1.attrs['NX_class'] = 'NXdata'
f1.attrs['signal'] = "Z"
f1.attrs['axes'] = [b"Y", b"X"]
f1z.attrs['interpretation'] = 'image'
f1x.attrs['long_name'] = "X [m]"
f1y.attrs['long_name'] = "Y [m]"
file.close()
print("File %s written to disk." % filename)
# copied from shadow3 ShadowTools
[docs]
def write_shadow_surface(s, xx, yy, outFile='presurface.dat'):
"""
Write a 2-D height mesh to disk in the SHADOW *presurface* format.
Parameters
----------
s : numpy.ndarray, shape (Nx, Ny)
2-D array of surface heights [m].
xx : numpy.ndarray, shape (Nx,)
Spatial coordinates along the mirror width (sagittal axis) [m].
yy : numpy.ndarray, shape (Ny,)
Spatial coordinates along the mirror length (tangential axis) [m].
outFile : str, optional
Path to the output file. Default ``'presurface.dat'``.
Returns
-------
int
1 on success, 0 on failure.
"""
out = 1
try:
fs = open(outFile, 'w')
except IOError:
out = 0
print("Error: can\'t open file: " + outFile)
return
else:
# dimensions
fs.write(repr(xx.size) + " " + repr(yy.size) + " \n")
# y array
for i in range(yy.size):
fs.write(' ' + repr(yy[i]))
fs.write("\n")
# for each x element, the x value and the corresponding z(y)
# profile
for i in range(xx.size):
tmps = ""
for j in range(yy.size):
tmps = tmps + " " + repr(s[j, i])
fs.write(' ' + repr(xx[i]) + " " + tmps)
fs.write("\n")
fs.close()
print("write_shadow_surface: File for SHADOW " + outFile + " written to disk.")
if __name__ == "__main__":
a = S4OpticalSurface()
a.info()