def test_ngon(): """ Tests regular 5-gon prism function vs combination of isosceles triangular prisms up to L=5. """ trip5 = qlm.tri_iso_prism2(5, .2, 1, 5, 0, np.pi/5) trip6 = rot.rotate_qlm(trip5, 2*np.pi/5, 0, 0) trip7 = rot.rotate_qlm(trip6, 2*np.pi/5, 0, 0) trip8 = rot.rotate_qlm(trip7, 2*np.pi/5, 0, 0) trip9 = rot.rotate_qlm(trip8, 2*np.pi/5, 0, 0) pent = qlm.ngon_prism(5, 1, 1, 10*np.sin(np.pi/5), 0, 5) pent2 = trip5+trip6+trip7+trip8+trip9 assert (abs(pent-pent2) < 350*np.finfo(float).eps).all()
def test_pyramid(): """ Tests pyramid function four x,y symmetric right tetrahedrons. """ tetb = qlm.tetrahedron(5, 1, np.sqrt(2), np.sqrt(2), 3) tetb = rot.rotate_qlm(tetb, -np.pi/4, 0, 0) tet2 = rot.rotate_qlm(tetb, np.pi/2, 0, 0) tet3 = rot.rotate_qlm(tetb, np.pi, 0, 0) tet4 = rot.rotate_qlm(tet2, np.pi, 0, 0) tet5 = qlmA.tetrahedron(5, 1, np.sqrt(2), np.sqrt(2), 3) tet6 = qlmA.tetrahedron(5, 1, np.sqrt(2), np.sqrt(2), 3) tet5 = rot.rotate_qlm(tet5, -np.pi/4, 0, 0) tet6 = rot.rotate_qlm(tet6, np.pi/4, 0, 0) tet7 = rot.rotate_qlm(tet5, np.pi, 0, 0) tet8 = rot.rotate_qlm(tet6, np.pi, 0, 0) pyr3 = tet5 + tet6 + tet7 + tet8 pyr2 = tetb + tet2 + tet3 + tet4 pyr = qlmA.pyramid(5, 1, 3, 2, 2) pyr4 = qlm.pyramid(5, 4, 1, 1, 3) assert (abs(pyr2-pyr)[:4] < 10*np.finfo(float).eps).all() assert (abs(pyr3-pyr)[:4] < 10*np.finfo(float).eps).all() assert (abs(pyr4-pyr2) < 10*np.finfo(float).eps).all() # Test explicit formula for L<5 (we'll do L=3) pyr = qlmA.pyramid(3, 1, 3, 2, 2) assert (np.shape(pyr) == (4, 7))
def test_rotateA2(): d = 1 m = 1 m1 = np.array([[m, d, 0, 0], [m, -d, 0, 0]]) qm1 = pgm.qmoments(10, m1) alpha = -np.pi/4 qm1b = pgm.qmoments(10, glb.rotate_point_array(m1, alpha, [0, 0, 1])) qm1c = rot.rotate_qlm(qm1, alpha, 0, 0) assert (abs(qm1c-qm1b) < 20*np.finfo(float).eps).all()
def test_rotateB(): d = 1 m = 1 m1 = np.array([[m, d, 0, 0], [m, -d, 0, 0]]) qm1 = pgm.qmoments(10, m1) beta = np.pi/4 qm1b = pgm.qmoments(10, glb.rotate_point_array(m1, beta, [0, 1, 0])) qm1c = rot.rotate_qlm(qm1, 0, beta, 0) assert (abs(qm1c-qm1b) < 10*np.finfo(float).eps).all()
def test_platehole(): """ Tests platehole against numerical calculation """ ph = qlmN.platehole(5, 1, 1, .5, np.pi/3) ph = rot.rotate_qlm(ph, 0, np.pi/3, 0) pha = qlmA.platehole(5, 1, 1, .5, np.pi/3) assert (abs(ph-pha) < 2e3*np.finfo(float).eps).all() # Test explicit formula for L<5 (we'll do L=3) pha = qlmA.platehole(3, 1, 1, .5, np.pi/3) assert (np.shape(pha) == (4, 7))
def test_rect_prism(): """ Tests rectangular prism function vs explicit formula up to L=5. """ rect = qlm.rect_prism(5, 1, 1, 1, 15, 0) rect2 = qlmA.rect_prism(5, 1/15, 1, 15, 1) # Rectangle from triang ACH matches ACH values trip2 = qlmA.tri_prism(5, 1/15, 1, 7.5, .5, -.5) trip = qlmA.tri_prism(5, 1/15, 1, .5, 7.5, -7.5) trip2 = rot.rotate_qlm(trip2, np.pi/2, 0, 0) trip3 = rot.rotate_qlm(trip2, np.pi, 0, 0) trip4 = rot.rotate_qlm(trip, np.pi, 0, 0) rect3 = trip+trip2+trip3+trip4 # Rectangle from triang prisms matches ACH values trip5 = qlm.tri_iso_prism(5, .25, 1, 15, .5, 0) trip6 = qlm.tri_iso_prism(5, .25, 1, 1, 7.5, 0) trip6 = rot.rotate_qlm(trip6, np.pi/2, 0, 0) trip7 = rot.rotate_qlm(trip5, np.pi, 0, 0) trip8 = rot.rotate_qlm(trip6, np.pi, 0, 0) rect4 = trip5+trip6+trip7+trip8 assert (abs(rect-rect2) < 400*np.finfo(float).eps).all() assert (abs(rect-rect3) < 5e3*np.finfo(float).eps).all() assert (abs(rect-rect4) < 5e3*np.finfo(float).eps).all() # Test explicit formula for L<5 (we'll do L=3) rect2 = qlmA.rect_prism(3, 1/15, 1, 15, 1) assert (np.shape(rect2) == (4, 7))
def test_rotateAB(): d = 1 m = 1 m1 = np.array([[m, d, 0, 0]]) qm1 = pgm.qmoments(10, m1) alpha = -np.pi/4 beta = np.pi/4 # Rotate around z first by alpha m2 = glb.rotate_point_array(m1, alpha, [0, 0, 1]) # Rotate around y second by beta and get new moments qm1b = pgm.qmoments(10, glb.rotate_point_array(m2, beta, [0, 1, 0])) qm1c = rot.rotate_qlm(qm1, 0, beta, alpha) assert (abs(qm1c-qm1b) < 20*np.finfo(float).eps).all()
def test_cylhole(): """ Tests Steinmetz solid XXX : fails for q22 and q44 """ stein3 = qlmA.cylhole(5, 1, 2, 5) stein4 = qlmN.steinmetz(5, 1, 2, 5) stein4 = rot.rotate_qlm(stein4, np.pi/2, 0, 0) assert (abs(stein3-stein4)[:2] < 1e3*np.finfo(float).eps).all() # Test explicit formula for L<5 (we'll do L=3) stein2 = qlmA.cylhole(3, 1, 1, 2) assert (np.shape(stein2) == (4, 7))
def rotate(self, alpha, beta, gamma): self.qlm = rot.rotate_qlm(self.qlm, alpha, beta, gamma) self.pointmass = glb.rotate_point_array(self.pointmass, gamma, [0, 0, 1]) self.pointmass = glb.rotate_point_array(self.pointmass, beta, [0, 1, 0]) self.pointmass = glb.rotate_point_array(self.pointmass, alpha, [0, 0, 1]) # Rotate center of mass using point-gravity tools rotcom = np.concatenate([[self.mass], self.com]) rotcom = glb.rotate_point_array(rotcom, gamma, [0, 0, 1]) rotcom = glb.rotate_point_array(rotcom, beta, [0, 1, 0]) rotcom = glb.rotate_point_array(rotcom, alpha, [0, 0, 1]) self.com = rotcom[1:4]
def test_annulus2(): """ Tests annulus function vs explicit annulus formula up to L=5. Partial. """ qcyl = qlm.annulus(5, 1, 1, 2, 3, np.pi/3, np.pi/8) rho = 8/(np.pi*(3**2-2**2)) qcyl2 = qlmA.annulus(5, rho, 1, 2, 3, np.pi/3, np.pi/8) assert (abs(qcyl-qcyl2) < 90*np.finfo(float).eps).all() qcyl3 = qlmN.cyl_mom(5, rho, np.pi/8, 2, 3, -.5, .5) qcyl3 = rot.rotate_qlm(qcyl3, np.pi/3, 0, 0) assert (abs(qcyl-qcyl2) < 90*np.finfo(float).eps).all() # Test explicit formula for L<5 (we'll do L=3) qcyl2 = qlmA.annulus(3, rho, 1, 2, 3, np.pi/3, np.pi/8) assert (np.shape(qcyl2) == (4, 7))
def test_cone(): """ Tests cone function vs explicit formula up to L=5. """ con = qlm.cone(5, 1, 1, 1, 0, np.pi) con4 = qlmA.cone2(5, 3/np.pi, 1, 1, 0) assert (abs(con-con4) < 10*np.finfo(float).eps).all() con3 = rot.rotate_qlm(con, 0, np.pi, 0) con3 = trs.translate_qlm(con3, [0, 0, .5]) con2 = qlmA.cone(5, 3/np.pi, 1, 1, 0) assert (abs(con3-con2) < 10*np.finfo(float).eps).all() con3 = trs.translate_qlm(con, [0, 0, -.5]) con2 = qlmA.cone(5, 3/np.pi, 1, 0, 1) assert (abs(con3-con2) < 10*np.finfo(float).eps).all() # Test explicit formula for L<5 (we'll do L=3) con2 = qlmA.cone(3, 3/np.pi, 1, 0, 1) assert (np.shape(con2) == (4, 7))
mtm = 39.658 htm = .1998 rtm = .34021/2 dx = -.72419 dy = -.92365 densAl = 2700 # kg/m^3 mh = densAl*np.pi*hc*rc**2 LMax = 10 # Create some rotating test-masses cyl = qlm.cylinder(LMax, mc, hc, rc) cyl3i = trs.translate_qlm(cyl, [r3, 0, 0]) cyl2i = trs.translate_qlm(cyl, [r2, 0, 0]) cyltot = np.copy(cyl3i) cyltot += rot.rotate_qlm(cyl3i, 2*np.pi/3, 0, 0) cyltot += rot.rotate_qlm(cyl3i, 4*np.pi/3, 0, 0) cyltot += cyl2i cyltot += rot.rotate_qlm(cyl2i, np.pi, 0, 0) # Create some rotating holes with negative mass cylh = qlm.cylinder(LMax, -mh, hc, rc) cylh3i = trs.translate_qlm(cylh, [r3, 0, 0]) cylh2i = trs.translate_qlm(cylh, [r2, 0, 0]) cylhtot = np.copy(cylh3i) cylhtot += rot.rotate_qlm(cylh3i, np.pi/3, 0, 0) cylhtot += rot.rotate_qlm(cylh3i, 2*np.pi/3, 0, 0) cylhtot += rot.rotate_qlm(cylh3i, np.pi, 0, 0) cylhtot += rot.rotate_qlm(cylh3i, 4*np.pi/3, 0, 0) cylhtot += rot.rotate_qlm(cylh3i, 5*np.pi/3, 0, 0) cylhtot += cylh2i cylhtot += rot.rotate_qlm(cylh2i, np.pi/2, 0, 0)
# Find inner moments if translated by [.1, 0, 0] rvec = [0.1, 0, 0] qm1p = pgm.qmoments(lmax, glb.translate_point_array(m1, rvec)) # Find moments translated by [.1, 0, 0] using d'Urso, Adelberger tic1 = time.perf_counter() qm1p2 = trs.translate_qlm(qm1, rvec) toc1 = time.perf_counter() # Time the recursive method combined with recursive translation tic2 = time.perf_counter() r = np.sqrt(rvec[0]**2 + rvec[1]**2 + rvec[2]**2) if r == 0 or r == rvec[2]: phi, theta = 0, 0 else: phi = np.arctan2(rvec[1], rvec[0]) theta = np.arccos(rvec[2]/r) rrms = trr.transl_newt_z_RR(lmax, r) qm1r = rot.rotate_qlm(qm1, 0, -theta, -phi) qlmp = trr.apply_trans_mat(qm1r, rrms) qm1r2 = rot.rotate_qlm(qlmp, phi, theta, 0) toc2 = time.perf_counter() # Check that the translations match the predicted assert (np.abs(qm1p - qm1r2) < 300*np.finfo(float).eps).all() assert (np.abs(qm1p2 - qm1r2) < 300*np.finfo(float).eps).all() # Compare the time for calculation at l=20 print("recursive (l<=20)[s]\t|\texplicit (l=20)[s]") print(toc2-tic2, "\t|\t", toc1-tic1)
def read_mpc(LMax, filename, filepath='C:\\mpc\\'): """ Attempts to open .mpc files in the same manner as MULTIN by having a 'working register' and a 'total register'. That is, there are two sets of moments stored in memory. One is the sum of all the previous moments (total) and the other is the current shape (working) being manipulated. The working shape can be rotated, translated, and added to total sequentially many times. This function does not allow the use of 'recall', 'store', 'rescale', or 'save' statements currently. Takes an optional filepath which is assumed to be the standard filepath for MULTIN, 'C:\\mpc\\'. Inputs ------ LMax : int Highest degree inner multipole moments to compute filename : str Name of .mpc file (with or without extension) filepath : str, optional Directory containing .mpc file, assumed 'C:\\mpc\\' in MULTIN Returns ------- qlmTot : ndarray, complex Complex (LMax+1)x(2LMax + 1) array of inner multipole coefficients """ if not filename.endswith('.mpc'): filename += '.mpc' with open(filepath + filename) as f: lines = f.readlines() title = lines[0] print(title) # We don't actually use n integration in this nsteps = 25 # Assume units are centimeters unless told otherwise fac = 1e-2 nlines = len(lines[1:]) qlmTot = np.zeros([LMax + 1, 2 * LMax + 1], dtype='complex') qlmWrk = np.zeros([LMax + 1, 2 * LMax + 1], dtype='complex') k = 0 while k < nlines: line = lines[1 + k] # Get rid of stuff after a comment line = line.split('%')[0] if 'create' in line: print(line) shape = line.split('create')[1].split()[0] if shape == 'cylinder': line2 = [float(val) for val in lines[2 + k].split(',')] Ri, Ro, H, phi0, phi1 = line2 Ri, Ro, H = Ri * fac, Ro * fac, H * fac phic = (phi1 + phi0) * np.pi / 180 / 2 phih = (phi1 - phi0) * np.pi / 180 / 2 dens = float(lines[3 + k].split(',')[0]) * 1000 mass = dens * phih * H * (Ro**2 - Ri**2) print(dens, line2) qlmWrk = qlm.annulus(LMax, mass, H, Ri, Ro, phic, phih) pos = np.array(lines[4 + k].split(','), dtype=float) * fac k += 3 if (pos == 0).all() and ('add' in lines[2 + k]): k += 1 print('added ', shape) qlmTot += qlmWrk else: print('translated ', shape) qlmWrk = trs.translate_qlm(qlmWrk, pos) elif shape == 'sphere': line2 = [float(val) * fac for val in lines[2 + k].split(',')] r = line2[0] dens = float(lines[3 + k].split(',')[0]) * 1000 mass = dens * 4 / 3 * np.pi * r**3 qlmWrk = qlm.sphere(LMax, mass, r) pos = np.array(lines[4 + k].split(','), dtype=float) * fac k += 3 if (pos == 0).all() and ('add' in lines[2 + k]): k += 1 print('added ', shape) qlmTot += qlmWrk else: print('translated ', shape) qlmWrk = trs.translate_qlm(qlmWrk, pos) elif shape == 'cone': line2 = [float(val) * fac for val in lines[2 + k].split(',')] LR, UR, H = line2 dens = float(lines[3 + k].split(',')[0]) * 1000 mass = dens * np.pi * H * LR**2 / 3 print(LR, UR, H, dens, mass) qlmWrk = qlm.cone(LMax, mass, H, LR, 0, np.pi) pos = np.array(lines[4 + k].split(','), dtype=float) * fac k += 3 if (pos == 0).all() and ('add' in lines[2 + k]): k += 1 print('added ', shape) qlmTot += qlmWrk else: print('translated ', shape) qlmWrk = trs.translate_qlm(qlmWrk, pos) elif shape == 'triangle': line2 = [float(val) * fac for val in lines[2 + k].split(',')] d, y1, y2, t = line2 dens = float(lines[3 + k].split(',')[0]) * 1000 mass = dens * t * d * abs(y2 - y1) / 2 qlmWrk = qlm.tri_prism(LMax, mass, t, d, y1, y2) pos = np.array(lines[4 + k].split(','), dtype=float) * fac k += 3 if (pos == 0).all() and ('add' in lines[2 + k]): k += 1 print('added ', shape) qlmTot += qlmWrk else: print('translated ', shape) qlmWrk = trs.translate_qlm(qlmWrk, pos) elif shape == 'trapezoid': line2 = [float(val) * fac for val in lines[2 + k].split(',')] w1, w2, h, t = line2 if w2 < w1: w3, w4 = w2, w1 flip = True else: w3, w4 = w1, w2 flip = False dens = float(lines[3 + k].split(',')[0]) * 1000 y1, y2 = w3 / 2, w4 / 2 hs = w3 * h / (w4 - w3) hb = h + hs massTrib = dens * t * w4 * hb / 2 massTris = dens * t * w3 * hs / 2 print(hs, hb, w3, w4) qlmWrk = qlm.tri_iso_prism(LMax, massTrib, t, w4, hb, 0) qlmWrk -= qlm.tri_iso_prism(LMax, massTris, t, w3, hs, 0) qlmWrk = trs.translate_qlm(qlmWrk, [-hs, 0, 0]) if flip: qlmWrk = trs.translate_qlm(qlmWrk, [-(hb - hs), 0, 0]) qlmWrk = rot.rotate_qlm(qlmWrk, 0, 0, np.pi) pos = np.array(lines[4 + k].split(','), dtype=float) * fac k += 3 if (pos == 0).all() and ('add' in lines[2 + k]): k += 1 print('added ', shape) qlmTot += qlmWrk else: print('translated ', shape) qlmWrk = trs.translate_qlm(qlmWrk, pos) elif shape == 'partcylinder': line2 = [float(val) * fac for val in lines[2 + k].split(',')] r, d, h = line2 dens = float(lines[3 + k].split(',')[0]) * 1000 phih = np.arccos(d / r) massCyl = dens * h * phih * r**2 massTri = dens * h * d * r * np.sin(phih) qlmWrk = qlm.annulus(LMax, massCyl, h, 0, r, 0, phih) qlmWrk -= qlm.tri_iso_prism2(LMax, massTri, h, r, 0, phih) pos = np.array(lines[4 + k].split(','), dtype=float) * fac k += 3 if (pos == 0).all() and ('add' in lines[2 + k]): k += 1 print('added ', shape) qlmTot += qlmWrk else: print('translated ', shape) qlmWrk = trs.translate_qlm(qlmWrk, pos) elif shape == 'tetrahedron': line2 = [float(val) * fac for val in lines[2 + k].split(',')] x, y, z = line2 dens = float(lines[3 + k].split(',')[0]) * 1000 mass = dens * x * y * z / 6 qlmWrk = qlm.tetrahedron(LMax, mass, x, y, z) pos = np.array(lines[4 + k].split(','), dtype=float) * fac k += 3 if (pos == 0).all() and ('add' in lines[2 + k]): k += 1 print('added ', shape) qlmTot += qlmWrk else: print('translated ', shape) qlmWrk = trs.translate_qlm(qlmWrk, pos) elif shape == 'platehole': line2 = [float(val) for val in lines[2 + k].split(',')] r, t, theta = line2 t, r = t * fac, r * fac theta *= np.pi / 180 dens = float(lines[3 + k].split(',')[0]) * 1000 qlmWrk = qlmA.platehole(LMax, dens, t, r, theta) # qlmWrk = qlmN.platehole(LMax, dens, t, r, theta) # qlmWrk = rot.rotate_qlm(qlmWrk, 0, theta, 0) pos = np.array(lines[4 + k].split(','), dtype=float) * fac k += 3 if (pos == 0).all() and ('add' in lines[2 + k]): k += 1 print('added ', shape) qlmTot += qlmWrk else: print('translated ', shape) qlmWrk = trs.translate_qlm(qlmWrk, pos) elif shape == 'cylhole': line2 = [float(val) * fac for val in lines[2 + k].split(',')] r, R = line2 dens = float(lines[3 + k].split(',')[0]) * 1000 qlmWrk = qlmN.steinmetz(LMax, dens, r, R) qlmWrk = rot.rotate_qlm(qlmWrk, np.pi / 2, 0, 0) pos = np.array(lines[4 + k].split(','), dtype=float) * fac k += 3 if (pos == 0).all() and ('add' in lines[2 + k]): k += 1 print('added ', shape) qlmTot += qlmWrk else: print('translated ', shape) qlmWrk = trs.translate_qlm(qlmWrk, pos) elif shape == 'pyramid': line2 = [float(val) * fac for val in lines[2 + k].split(',')] x, y, z = line2 dens = float(lines[3 + k].split(',')[0]) * 1000 mass = dens * x * y * z / 3 qlmWrk = qlm.pyramid(LMax, mass, x / 2, y / 2, z) pos = np.array(lines[4 + k].split(','), dtype=float) * fac k += 3 if (pos == 0).all() and ('add' in lines[2 + k]): k += 1 print('added ', shape) qlmTot += qlmWrk else: print('translated ', shape) qlmWrk = trs.translate_qlm(qlmWrk, pos) elif shape == 'rectangle': line2 = [float(val) * fac for val in lines[2 + k].split(',')] x, y, z = line2 dens = float(lines[3 + k].split(',')[0]) * 1000 mass = dens * x * y * z qlmWrk = qlm.rect_prism(LMax, mass, z, x, y, 0) pos = np.array(lines[4 + k].split(','), dtype=float) * fac k += 3 if (pos == 0).all() and ('add' in lines[2 + k]): k += 1 print('added ', shape) qlmTot += qlmWrk else: print('translated ', shape) qlmWrk = trs.translate_qlm(qlmWrk, pos) else: print(shape, ' does not have a known set of moments') for n in range(nlines - k): line2 = lines[1 + k + 1] if ('create' not in line2) and ('end' not in line2): k += 1 else: break elif 'rotate' in line: dphi = np.array(line.split('rotate')[1].split(','), dtype=float) # Convert to radians dphi *= np.pi / 180 print('rotated ', shape) qlmWrk = rot.rotate_qlm(qlmWrk, dphi[0], dphi[1], dphi[2]) elif 'translate' in line: print('translated ', shape) dr = np.array(line.split('translate')[1].split(','), dtype=float) dr *= fac qlmWrk = trs.translate_qlm(qlmWrk, dr) elif 'add' in line: print('added ', shape) qlmTot += qlmWrk elif 'cmin' in line: print('parameters in centimeters') fac = 1e-2 elif 'inchin' in line: print('parameters in inches') fac = 25.4e-3 elif 'nsteps' in line: nsteps = line.split()[-1] elif 'load' in line: fname = line.split('load ')[1] fname = fname.strip() print(fname) qlmLoad = read_gsq(fname, filepath.replace('mpc', 'mom')) if np.shape(qlmLoad) != np.shape(qlmWrk): raise TypeError('Loaded part ' + fname + ' has wrong LMax') qlmWrk = qlmLoad shape = fname elif 'zeroqlm' in line: qlmTot *= 0 elif 'gettotal' in line: qlmWrk = np.copy(qlmTot) shape = 'Total' elif 'puttotal' in line: qlmTot = np.copy(qlmWrk) shape = 'Working' elif 'end' in line: print('end') break k += 1 return qlmTot
mc = 1.0558 r3 = .10478 r2 = .06033 mtm = 39.658 htm = .1998 rtm = .34021 / 2 dx = -.72419 dy = -.92365 LMax = 10 # Create some rotating test-masses cyl = qlm.cylinder(LMax, mc, hc, rc) cyl3i = trs.translate_qlm(cyl, [r3, 0, 0]) cyl2i = trs.translate_qlm(cyl, [r2, 0, 0]) cyltot = np.copy(cyl3i) cyltot += rot.rotate_qlm(cyl3i, 2 * np.pi / 3, 0, 0) cyltot += rot.rotate_qlm(cyl3i, 4 * np.pi / 3, 0, 0) cyltot += cyl2i cyltot += rot.rotate_qlm(cyl2i, np.pi, 0, 0) # create a test-mirror tm = qlm.cylinder(LMax, mtm, htm, rtm) tm = rot.rotate_qlm(tm, np.pi / 2, np.pi / 2, -np.pi / 2) tm = trs.translate_q2Q(tm, [dx, dy, 0]) # Figure out the force at different rotor angles nAng = 120 forces = np.zeros([nAng, 3], dtype='complex') nlm, nc, ns = mplb.torque_lm(LMax, cyltot, tm) dphi = 2 * np.pi / nAng # Now rotate the cylindrical test-masses through various angles and calculate
dens = 2800 # kg/m^3, 7075 T6 aluminum mc = dens * 2 * beta * (orc**2 - irc**2) * hc r3 = .10478 r2 = .06033 mtm = 39.658 htm = .20 # 20cm thickness rtm = .35 / 2 # 35cm diam d = 1.32 # m phi = 0.241 # radian dx = d * np.cos(phi) dy = d * np.sin(phi) LMax = 10 # Create some rotating test-masses arc = qlm.annulus(LMax, mc / 2, hc, irc, orc, 0, beta) arc2 = rot.rotate_qlm(arc, np.pi, 0, 0) arctot = arc + arc2 # create a test-mirror tm = qlm.cylinder(LMax, mtm, htm, rtm) tm = rot.rotate_qlm(tm, np.pi / 2, np.pi / 2, -np.pi / 2) tm = trs.translate_q2Q(tm, [dx, dy, 0]) # Figure out the force at different rotor angles nAng = 120 forces = np.zeros([nAng, 3], dtype='complex') nlm, nc, ns = mplb.torque_lm(LMax, arctot, tm) dphi = 2 * np.pi / nAng # Now rotate the cylindrical test-masses through various angles and calculate # the forces for k in range(nAng):