diff --git a/bin/test_romhom.py b/bin/test_romhom.py new file mode 100644 index 0000000000000000000000000000000000000000..2482c81ff50e091d59fd5ca260cc5fefb3638a33 --- /dev/null +++ b/bin/test_romhom.py @@ -0,0 +1,35 @@ +from pykat.utilities.maps import read_map +from pykat.utilities.knm import * +from pykat.utilities.optics.gaussian_beams import beam_param + +couplings = np.array([[[0,0,0,0], [0,0,1,0], [0,0,0,1]], + [[1,0,0,0], [1,0,1,0], [1,0,0,1]], + [[0,1,0,0], [0,1,1,0], [0,1,0,1]]]) + +q1 = beam_param(w0=2e-2, z=0) +q2 = beam_param(w0=2e-2, z=0) + +m = read_map('etm08_virtual.txt') + +m.data = np.zeros((200, 200)) +m.x = np.linspace(-0.151, 0.149, m.size[0]) +m.y = np.linspace(-0.151, 0.149, m.size[1]) +m.center = np.array(m.size)/2 +m.step_size = (m.x[1]-m.x[0], m.y[1]-m.y[0]) + +print "generating weights..." +w = m.generateROMWeights() + +print "computing Riemann knm..." +K1 = knmHG(couplings, q1, q2, surface_map=m) +print np.abs(K1) + +print "computing ROMHOM knm..." +K2 = knmHG(couplings, q1, q2, surface_map=m, method="romhom") +print np.abs(K2) + +#w.writeToFile("testWeights.rom") + + + + diff --git a/pykat/utilities/knm.py b/pykat/utilities/knm.py index 53ca9988938eae101f4d8e3f1f3638d1c4ee7805..f878050f59e0aa136ad455faa4af44956cb942a3 100644 --- a/pykat/utilities/knm.py +++ b/pykat/utilities/knm.py @@ -8,10 +8,7 @@ import numpy as np import pykat import collections import math - -def makeCouplingMatrix(max_order): - pass - +from romhom import u_star_u def riemann_HG_knm(x, y, mode_in, mode_out, q1, q2, q1y=None, q2y=None, Axy=None): @@ -39,11 +36,124 @@ def riemann_HG_knm(x, y, mode_in, mode_out, q1, q2, q1y=None, q2y=None, Axy=None return dx * dy * np.einsum('ij,ij', Axy, U1*U2) -def ROM_HG_knm(m, mode_in, mode_out, q1, q2, q1y=None, q2y=None): - pass +def __gen_ROM_HG_knm_cache(weights, couplings, q1, q2, q1y=None, q2y=None): + + if q1y == None: + q1y = q1 + + if q2y == None: + q2y = q2 + + it = np.nditer(couplings, flags=['refs_ok','f_index']) + + cache = {} + + cache["w_ij_Q1Q3"] = weights.w_ij_Q1 + weights.w_ij_Q3 + cache["w_ij_Q2Q4"] = weights.w_ij_Q2 + weights.w_ij_Q4 + cache["w_ij_Q1Q2"] = weights.w_ij_Q1 + weights.w_ij_Q2 + cache["w_ij_Q1Q4"] = weights.w_ij_Q1 + weights.w_ij_Q4 + cache["w_ij_Q2Q3"] = weights.w_ij_Q2 + weights.w_ij_Q3 + cache["w_ij_Q3Q4"] = weights.w_ij_Q3 + weights.w_ij_Q4 + cache["w_ij_Q1Q2Q3Q4"] = weights.w_ij_Q1 + weights.w_ij_Q3 + weights.w_ij_Q2 + weights.w_ij_Q4 + while not it.finished: + try: + mode_in = [int(it.next()), int(it.next())] + mode_out = [int(it.next()), int(it.next())] + + strx = "x[%i,%i]" % (mode_in[0], mode_out[0]) + stry = "y[%i,%i]" % (mode_in[1], mode_out[1]) + + if strx not in cache: + cache[strx] = u_star_u(q1.z, q2.z, q1.w0, q2.w0, mode_in[0], mode_out[0], weights.nodes) + + if q1 == q1y and q2 == q2y: + cache[stry] = cache[strx] + elif stry not in cache: + cache[stry] = u_star_u(q1y.z, q2y.z, q1y.w0, q2y.w0, mode_in[1], mode_out[1], weights.nodes) + + + + except StopIteration: + break + + return cache + +def ROM_HG_knm(weights, mode_in, mode_out, q1, q2, q1y=None, q2y=None, cache=None): + if q1y == None: + q1y = q1 -def knmHG(couplings, surface_map, q1, q2, q1y=None, q2y=None, method="riemann"): + if q2y == None: + q2y = q2 + + # x modes + n = mode_in[0] + m = mode_out[0] + + # y modes + npr = mode_in[1] + mpr = mode_out[1] + + if cache == None: + u_x_nodes = u_star_u(q1.z, q2.z, q1.w0, q2.w0, n, m, weights.nodes) + u_y_nodes = u_star_u(q1y.z, q2y.z, q1y.w0, q2y.w0, npr, mpr, weights.nodes) + + w_ij_Q1Q3 = weights.w_ij_Q1 + weights.w_ij_Q3 + w_ij_Q2Q4 = weights.w_ij_Q2 + weights.w_ij_Q4 + w_ij_Q1Q2 = weights.w_ij_Q1 + weights.w_ij_Q2 + w_ij_Q1Q4 = weights.w_ij_Q1 + weights.w_ij_Q4 + w_ij_Q2Q3 = weights.w_ij_Q2 + weights.w_ij_Q3 + w_ij_Q3Q4 = weights.w_ij_Q3 + weights.w_ij_Q4 + w_ij_Q1Q2Q3Q4 = weights.w_ij_Q1 + weights.w_ij_Q3 + weights.w_ij_Q2 + weights.w_ij_Q4 + else: + strx = "x[%i,%i]" % (mode_in[0], mode_out[0]) + stry = "y[%i,%i]" % (mode_in[1], mode_out[1]) + + u_x_nodes = cache[strx] + u_y_nodes = cache[stry] + + w_ij_Q1Q3 = cache["w_ij_Q1Q3"] + w_ij_Q2Q4 = cache["w_ij_Q2Q4"] + w_ij_Q1Q2 = cache["w_ij_Q1Q2"] + w_ij_Q1Q4 = cache["w_ij_Q1Q4"] + w_ij_Q2Q3 = cache["w_ij_Q2Q3"] + w_ij_Q3Q4 = cache["w_ij_Q3Q4"] + w_ij_Q1Q2Q3Q4 = cache["w_ij_Q1Q2Q3Q4"] + + u_xy_nodes = np.outer(u_x_nodes, u_y_nodes) + + n_mod_2 = n % 2 + m_mod_2 = m % 2 + npr_mod_2 = npr % 2 + mpr_mod_2 = mpr % 2 + + if n_mod_2 == m_mod_2 and npr_mod_2 == mpr_mod_2: + k_ROQ = np.einsum('ij,ij', u_xy_nodes, w_ij_Q1Q2Q3Q4) + + elif n_mod_2 != m_mod_2: + if npr_mod_2 == mpr_mod_2: + k_ROQ = np.einsum('ij,ij', u_xy_nodes, w_ij_Q1Q4) + np.einsum('ij,ij', -u_xy_nodes, w_ij_Q2Q3) + else: + k_ROQ = np.einsum('ij,ij', u_xy_nodes, w_ij_Q2Q4) + np.einsum('ij,ij', -u_xy_nodes, w_ij_Q1Q3) + + elif npr_mod_2 != mpr_mod_2: + if n_mod_2 == m_mod_2: + k_ROQ = np.einsum('ij,ij', u_xy_nodes, w_ij_Q3Q4) + np.einsum('ij,ij', -u_xy_nodes, w_ij_Q1Q2) + else: + k_ROQ = np.einsum('ij,ij', u_xy_nodes, w_ij_Q2Q4) + np.einsum('ij,ij', -u_xy_nodes, w_ij_Q1Q3) + + return k_ROQ + + + +def knmHG(couplings, q1, q2, surface_map=None, q1y=None, q2y=None, method="riemann"): + if q1y == None: + q1y = q1 + + if q2y == None: + q2y = q2 + + assert q1.wavelength == q2.wavelength and q1y.wavelength == q2y.wavelength and q1y.wavelength == q1.wavelength couplings = np.array(couplings) @@ -52,8 +162,7 @@ def knmHG(couplings, surface_map, q1, q2, q1y=None, q2y=None, method="riemann"): if int(a) - a != 0: raise BasePyKatException("Iterator should be product of 4, each element of coupling array should be [n,m,n',m']") - if "phase" in surface_map.type: - Axy = np.exp(2j * 2 * math.pi / q1.wavelength * surface_map.data * surface_map.scaling) + Axy = surface_map.z_xy(q1.wavelength) x = surface_map.x y = surface_map.y @@ -64,16 +173,32 @@ def knmHG(couplings, surface_map, q1, q2, q1y=None, q2y=None, method="riemann"): i = 0 + if method == "romhom": + if surface_map == None: + raise BasePyKatException("Using 'romhom' method requires a surface map to be specified") + + weights = surface_map.ROMWeights + + if weights == None: + raise BasePyKatException("The ROM weights need to be generated for this map before use.") + + romcache = None#__gen_ROM_HG_knm_cache(weights, couplings, q1=q1, q2=q2, q1y=q1y, q2y=q2y) + else: + romcache = None + weights = None + while not it.finished: try: mode_in = [int(it.next()), int(it.next())] mode_out = [int(it.next()), int(it.next())] - + if method == "riemann": K[i] = riemann_HG_knm(x, y, mode_in, mode_out, q1=q1, q2=q2, q1y=q1y, q2y=q2y, Axy=Axy) + elif method == "romhom": + K[i] = ROM_HG_knm(weights, mode_in, mode_out, q1=q1, q2=q2, q1y=q1y, q2y=q2y, cache=romcache) else: - raise BasePyKatException("method value not accepted") + raise BasePyKatException("method value '%s' not accepted" % method) i +=1 diff --git a/pykat/utilities/maps.py b/pykat/utilities/maps.py index e9f1ab23d19591cf67cfce8ee18f89af990fd370..e115f4c58e2c53eefb3c19be33faed8747f748f2 100644 --- a/pykat/utilities/maps.py +++ b/pykat/utilities/maps.py @@ -1,5 +1,6 @@ from pykat.utilities.romhom import makeReducedBasis, makeEmpiricalInterpolant, makeWeights import numpy +import math class surfacemap: def __init__(self, name, maptype, size, center, step_size, scaling, data=None): @@ -7,7 +8,6 @@ class surfacemap: self.name = name self.type = maptype self.center = center - self.size = size self.step_size = step_size self.scaling = scaling self.data = data @@ -19,7 +19,7 @@ class surfacemap: mapfile.write("% Surface map\n") mapfile.write("% Name: {0}\n".format(self.name)) mapfile.write("% Type: {0}\n".format(self.type)) - mapfile.write("% Size: {0} {1}\n".format(self.size[0], self.size[1])) + mapfile.write("% Size: {0} {1}\n".format(self.data.shape[0], self.data.shape[1])) mapfile.write("% Optical center (x,y): {0} {1}\n".format(self.center[0], self.center[1])) mapfile.write("% Step size (x,y): {0} {1}\n".format(self.step_size[0], self.step_size[1])) mapfile.write("% Scaling: {0}\n".format(float(self.scaling))) @@ -37,7 +37,11 @@ class surfacemap: @property def y(self): return self.step_size[1] * (numpy.array(range(1, self.data.shape[1]+1))- self.center[1]) - + + @property + def size(self): + return self.data.shape + @property def offset(self): return numpy.array(self.step_size)*(self.center - numpy.array(self.size)/2) @@ -45,13 +49,22 @@ class surfacemap: @property def ROMWeights(self): return self._rom_weights - + + def z_xy(self, wavelength=1064e-9): + + if "phase" in self.type: + k = math.pi * 2 / wavelength + return numpy.exp(2j * k * self.scaling * self.data) + else: + raise BasePyKatException("Map type needs handling") + + def generateROMWeights(self): b = makeReducedBasis(self.x[0:(len(self.x)/2)], offset=self.offset) EI = makeEmpiricalInterpolant(b) self._rom_weights = makeWeights(self, EI) - return self.ROMWeights + return self.ROMWeights, EI def plot(self, show=True, clabel=None): diff --git a/pykat/utilities/optics/gaussian_beams.py b/pykat/utilities/optics/gaussian_beams.py index 02ecfbfcfd28a7fbab6133b5f0230e39ba9d02eb..cd1f554349b352a682df73336048b734f9693f81 100644 --- a/pykat/utilities/optics/gaussian_beams.py +++ b/pykat/utilities/optics/gaussian_beams.py @@ -82,7 +82,7 @@ class gauss_param(object): def w(self): return abs(self.__q)*math.sqrt(self.__lambda / (self.__nr * math.pi * self.__q.imag)) - def w(self, z=None, wavelength=None, nr=None, w0=None): + def beamsize(self, z=None, wavelength=None, nr=None, w0=None): if z == None: z = self.z @@ -144,7 +144,7 @@ class gauss_param(object): else: return float("inf") - def Rc(self, z=None, wavelength=None, nr=None, w0=None): + def curvature(self, z=None, wavelength=None, nr=None, w0=None): if z == None: z = self.z else: diff --git a/pykat/utilities/romhom.py b/pykat/utilities/romhom.py index 840e7aee915dd4ff155b76f6f72939e76aa9a44c..a4677b2781a74d40d0322a7596cb62176f1a90fe 100644 --- a/pykat/utilities/romhom.py +++ b/pykat/utilities/romhom.py @@ -1,14 +1,16 @@ +import math import maps import os.path -import numpy as np import pykat import collections + from itertools import combinations_with_replacement as combinations from pykat.utilities.optics.gaussian_beams import beam_param, HG_beam from scipy.linalg import inv from math import factorial from hermite import * -import math + +import numpy as np EmpiricalInterpolant = collections.namedtuple('EmpiricalInterpolant', 'B nodes node_indices limits x') ReducedBasis = collections.namedtuple('ReducedBasis', 'RB limits x') @@ -16,11 +18,12 @@ ROMLimits = collections.namedtuple('ROMLimits', 'zmin zmax w0min w0max max_order class ROMWeights: - def __init__(self, w_ij_Q1, w_ij_Q2, w_ij_Q3, w_ij_Q4, limits): + def __init__(self, w_ij_Q1, w_ij_Q2, w_ij_Q3, w_ij_Q4, nodes, limits): self.w_ij_Q1 = w_ij_Q1 self.w_ij_Q2 = w_ij_Q2 self.w_ij_Q3 = w_ij_Q3 self.w_ij_Q4 = w_ij_Q4 + self.nodes = nodes self.limits = limits def writeToFile(self, filename): @@ -101,7 +104,7 @@ def u(re_q1, w0_1, n1, x): wz1 = w(w0_1, im_q1, re_q1) - return A_n1 * hermite(n1, np.sqrt(2.)*x / wz1) * np.exp(-1j*(2*math.pi/(1064e-9))* x**2 /(2.*q_z1)) + return A_n1 * hermite(n1, np.sqrt(2.)*x / wz1) * np.exp(np.array(-1j*(2*math.pi/(1064e-9))* x**2 /(2.*q_z1))) def u_star_u(re_q1, re_q2, w0_1, w0_2, n1, n2, x): @@ -240,14 +243,14 @@ def makeEmpiricalInterpolant(RB): invV = inv(V[0:len(node_indices), 0:len(node_indices)]) B = B_matrix(invV, e_x) - - return EmpiricalInterpolant(B=np.array(B), nodes=np.array(x_nodes), node_indices=np.array(node_indices), limits=RB.limits, x=RB.x) + + return EmpiricalInterpolant(B=np.array(B), nodes=np.array(x_nodes, dtype=np.float64), node_indices=np.array(node_indices, dtype=np.int32), limits=RB.limits, x=RB.x) def makeWeights(smap, EI): # get full A_xy - A_xy = smap.data + A_xy = smap.z_xy() hx = len(smap.x)/2 hy = len(smap.y)/2 @@ -289,83 +292,6 @@ def makeWeights(smap, EI): B_ij_Q4 = np.outer(B[i], B[j]) w_ij_Q4[i][j] = dx*dy*np.einsum('ij,ij', B_ij_Q4, A_xy_Q4) - - return ROMWeights(w_ij_Q1=w_ij_Q1, w_ij_Q2=w_ij_Q2, w_ij_Q3=w_ij_Q3, w_ij_Q4=w_ij_Q4, limits=EI.limits) - -def ROMKnm(W, max_order, q1, q2, q1y=None, q2y=None): - - if q1y == None: - q1y = q1 - - if q2y == None: - q2y = q2 - - # get symmetric and anti-symmetric w_ij's - w_ij_Q1Q3 = W.w_ij_Q1 + W.w_ij_Q3 - w_ij_Q2Q4 = W.w_ij_Q2 + W.w_ij_Q4 - w_ij_Q1Q2 = W.w_ij_Q1 + W.w_ij_Q2 - w_ij_Q1Q4 = W.w_ij_Q1 + W.w_ij_Q4 - w_ij_Q2Q3 = W.w_ij_Q2 + W.w_ij_Q3 - w_ij_Q3Q4 = W.w_ij_Q3 + W.w_ij_Q4 - - w_ij_Q1Q2Q3Q4 = W.w_ij_Q1 + W.w_ij_Q3 + W.w_ij_Q2 + W.w_ij_Q4 - - num_fields = int((max_order + 1) * (max_order + 2) / 2); - - K_ROQ = np.array((num_fields, num_fields)) - - for i in range(len(nm_pairs)): - for j in range(len(nm_pairs)): - - # full quadrature - n = nm_pairs[i][0] - m = nm_pairs[i][1] - npr = nm_pairs[j][0] - mpr = nm_pairs[j][1] - u_xy = np.outer(u_star_u(re_q1, re_q2, w0_1, w0_2, n, m, full_x), u_star_u(re_q1, re_q2, w0_1, w0_2, npr, mpr, full_x)) - k = dx*dy*np.einsum('ij,ij', u_xy, A_xy) - - # ROQ - if nm_pairs[i][0] % 2 == 0 and nm_pairs[i][1] % 2 == 0 and nm_pairs[j][0] % 2 == 0 and nm_pairs[j][1] % 2 == 0: - u_xy_nodes = np.outer(u_star_u(re_q1, re_q2, w0_1, w0_2, n, m, nodes_nv), u_star_u(re_q1, re_q2, w0_1, w0_2, npr, mpr, nodes_nv)) - k_ROQ = np.einsum('ij,ij', u_xy_nodes, w_ij_Q1Q2Q3Q4) - - elif nm_pairs[i][0] % 2 == 1 and nm_pairs[i][1] % 2 == 1 and nm_pairs[j][0] % 2 == 1 and nm_pairs[j][1] % 2 == 1: - u_xy_nodes = np.outer(u_star_u(re_q1, re_q2, w0_1, w0_2, n, m, nodes_nv), u_star_u(re_q1, re_q2, w0_1, w0_2, npr, mpr, nodes_nv)) - k_ROQ = np.einsum('ij,ij', u_xy_nodes, w_ij_Q1Q2Q3Q4) - - elif nm_pairs[i][0] % 2 == 0 and nm_pairs[i][1] % 2 == 0 and nm_pairs[j][0] % 2 == 1 and nm_pairs[j][1] % 2 == 1: - u_xy_nodes = np.outer(u_star_u(re_q1, re_q2, w0_1, w0_2, n, m, nodes_nv), u_star_u(re_q1, re_q2, w0_1, w0_2, npr, mpr, nodes_nv)) - k_ROQ = np.einsum('ij,ij', u_xy_nodes, w_ij_Q1Q2Q3Q4) - - elif nm_pairs[i][0] % 2 == 1 and nm_pairs[i][1] % 2 == 1 and nm_pairs[j][0] % 2 == 0 and nm_pairs[j][1] % 2 == 0: - u_xy_nodes = np.outer(u_star_u(re_q1, re_q2, w0_1, w0_2, n, m, nodes_nv), u_star_u(re_q1, re_q2, w0_1, w0_2, npr, mpr, nodes_nv)) - k_ROQ = np.einsum('ij,ij', u_xy_nodes, w_ij_Q1Q2Q3Q4) - - elif nm_pairs[i][0] % 2 == 0 and nm_pairs[i][1] % 2 == 1 or nm_pairs[i][0] % 2 == 1 and nm_pairs[i][1] % 2 == 0: - u_x_nodes = u_star_u(re_q1, re_q2, w0_1, w0_2, n,m, nodes_nv) - u_y_nodes = u_star_u(re_q1, re_q2, w0_1, w0_2, npr, mpr, nodes_nv) - - if nm_pairs[j][0] % 2 == 0 and nm_pairs[j][1] % 2 == 0 or nm_pairs[j][0] % 2 == 1 and nm_pairs[j][1] % 2 == 1: - u_xy_nodes_Q1Q4 = np.outer(u_x_nodes, u_y_nodes) - u_xy_nodes_Q2Q3 = - u_xy_nodes_Q1Q4 - k_ROQ = np.einsum('ij,ij', u_xy_nodes_Q1Q4, w_ij_Q1Q4) + np.einsum('ij,ij', u_xy_nodes_Q2Q3, w_ij_Q2Q3) - else: - u_xy_nodes_Q2Q4 = np.outer(u_x_nodes, u_y_nodes) - u_xy_nodes_Q1Q3 = - u_xy_nodes_Q2Q4 - k_ROQ = np.einsum('ij,ij', u_xy_nodes_Q2Q4, w_ij_Q2Q4) + np.einsum('ij,ij', u_xy_nodes_Q1Q3, w_ij_Q1Q3) - - elif nm_pairs[j][0] % 2 == 0 and nm_pairs[j][1] % 2 == 1 or nm_pairs[j][0] % 2 == 1 and nm_pairs[j][1] % 2 == 0: - u_x_nodes = u_star_u(re_q1, re_q2, w0_1, w0_2, n, m, nodes_nv) - u_y_nodes = u_star_u(re_q1, re_q2, w0_1, w0_2, npr, mpr, nodes_nv) - - if nm_pairs[i][0] % 2 == 0 and nm_pairs[i][1] % 2 == 0 or nm_pairs[i][0] % 2 == 1 and nm_pairs[i][1] % 2 == 1: - u_xy_nodes_Q3Q4 = np.outer(u_x_nodes, u_y_nodes) - u_xy_nodes_Q1Q2 = - u_xy_nodes_Q3Q4 - k_ROQ = np.einsum('ij,ij', u_xy_nodes_Q3Q4, w_ij_Q3Q4) + np.einsum('ij,ij', u_xy_nodes_Q1Q2, w_ij_Q1Q2) - else: - u_xy_nodes_Q2Q4 = np.outer(u_x_nodes, u_y_nodes) - u_xy_nodes_Q1Q3 = - u_xy_nodes_Q2Q4 - k_ROQ = np.einsum('ij,ij', u_xy_nodes_Q2Q4, w_ij_Q2Q4) + np.einsum('ij,ij', u_xy_nodes_Q1Q3, w_ij_Q1Q3) - + return ROMWeights(w_ij_Q1=w_ij_Q1, w_ij_Q2=w_ij_Q2, w_ij_Q3=w_ij_Q3, w_ij_Q4=w_ij_Q4, nodes=EI.nodes, limits=EI.limits) + \ No newline at end of file