def test_revolve(self): # square torus square = CurveFactory.n_gon(4) square.rotate(pi / 2, (1, 0, 0)) square.translate((2, 0, 0)) # in xz-plane with corners at (3,0),(2,1),(1,0),(2,-1) surf = SurfaceFactory.revolve(square) surf.reparam() # set parametric space to (0,1)^2 v = np.linspace(0, 1, 13) x = surf.evaluate(0, v) # outer ring evaluation u=0 for pt in np.array(x[0, :, :]): self.assertAlmostEqual(np.linalg.norm(pt, 2), 3.0) # check radius=3 x = surf.evaluate(.25, v) # top ring evaluation u=.25 for pt in np.array(x[0, :, :]): self.assertAlmostEqual(pt[0] * pt[0] + pt[1] * pt[1], 2 * 2) # check radius=2 self.assertAlmostEqual(pt[2], 1) # check height=1 x = surf.evaluate(.375, v) # mid inner ring evaluation u=.375 for pt in np.array(x[0, :, :]): self.assertAlmostEqual(pt[0] * pt[0] + pt[1] * pt[1], 1.5 * 1.5) # check radius=1.5 self.assertAlmostEqual(pt[2], .5) # check height=0.5 # incomplete revolve c = CurveFactory.line([1,0], [0,1], relative=True) surf = SurfaceFactory.revolve(c, theta=4.2222, axis=[0,1,0]) surf.reparam() u = np.linspace(0,1,7) v = np.linspace(0,1,7) x = surf(u,v) for uPt in x: for pt in uPt: self.assertAlmostEqual(pt[0]**2 + pt[2]**2, 1.0) # radius 1 from y-axis
def test_revolve(self): # square torus square = cf.n_gon(4) square.rotate(pi / 2, (1, 0, 0)) square.translate( (2, 0, 0)) # in xz-plane with corners at (3,0),(2,1),(1,0),(2,-1) surf = sf.revolve(square) surf.reparam() # set parametric space to (0,1)^2 v = np.linspace(0, 1, 13) x = surf.evaluate(0, v) # outer ring evaluation u=0 for pt in np.array(x[0, :, :]): self.assertAlmostEqual(np.linalg.norm(pt, 2), 3.0) # check radius=3 x = surf.evaluate(.25, v) # top ring evaluation u=.25 for pt in np.array(x[0, :, :]): self.assertAlmostEqual(pt[0] * pt[0] + pt[1] * pt[1], 2 * 2) # check radius=2 self.assertAlmostEqual(pt[2], 1) # check height=1 x = surf.evaluate(.375, v) # mid inner ring evaluation u=.375 for pt in np.array(x[0, :, :]): self.assertAlmostEqual(pt[0] * pt[0] + pt[1] * pt[1], 1.5 * 1.5) # check radius=1.5 self.assertAlmostEqual(pt[2], .5) # check height=0.5 # incomplete revolve c = cf.line([1, 0], [0, 1], relative=True) surf = sf.revolve(c, theta=4.2222, axis=[0, 1, 0]) surf.reparam() u = np.linspace(0, 1, 7) v = np.linspace(0, 1, 7) x = surf(u, v) for uPt in x: for pt in uPt: self.assertAlmostEqual(pt[0]**2 + pt[2]**2, 1.0) # radius 1 from y-axis
def test_line(self): # 2D line c = CurveFactory.line([1, 1], [2, 0]) self.assertEqual(c.order(0), 2) # linear discretization self.assertEqual(len(c), 2) # two control points self.assertEqual(c.dimension, 2) self.assertEqual(c[0][0], 1) self.assertEqual(c[0][1], 1) self.assertEqual(c[-1][0], 2) self.assertEqual(c[-1][1], 0) # 3D line c = CurveFactory.line([1, 2, 3], [8, 7, 6]) self.assertEqual(c.order(0), 2) # linear discretization self.assertEqual(len(c), 2) # two control points self.assertEqual(c.dimension, 3)
def test_line(self): # 2D line c = cf.line([1, 1], [2, 0]) self.assertEqual(c.order(0), 2) # linear discretization self.assertEqual(len(c), 2) # two control points self.assertEqual(c.dimension, 2) self.assertEqual(c[0][0], 1) self.assertEqual(c[0][1], 1) self.assertEqual(c[-1][0], 2) self.assertEqual(c[-1][1], 0) # 3D line c = cf.line([1, 2, 3], [8, 7, 6]) self.assertEqual(c.order(0), 2) # linear discretization self.assertEqual(len(c), 2) # two control points self.assertEqual(c.dimension, 3)
def test_2d_self_connection(self): c = curve_factory.line([1, 0], [2, 0]) surf = surface_factory.revolve(c) surf = surf.split(surf.knots('v')[0], direction='v') # break periodicity surf.set_dimension(2) model = SplineModel(2, 2) model.add(surf) writer = IFEMWriter(model) expected = [IFEMConnection(1, 1, 3, 4, 0)] for connection, want in zip(writer.connections(), expected): self.assertEqual(connection, want)
def line(self): dim = int( self.read_next_non_whitespace().strip()) start = np.array(next(self.fstream).split(), dtype=float) direction= np.array(next(self.fstream).split(), dtype=float) finite = next(self.fstream).strip() != '0' param = np.array(next(self.fstream).split(), dtype=float) reverse = next(self.fstream).strip() != '0' d = np.array(direction) s = np.array(start) # d /= np.linalg.norm(d) if not finite: param = [-state.unlimited, +state.unlimited] result = CurveFactory.line(s+d*param[0], s+d*param[1]) if reverse: result.reverse() return result
def read(self): if not hasattr(self, 'fstream'): self.onlywrite = False self.fstream = File3dm.Read(self.filename) if self.onlywrite: raise IOError('Could not read from file %s' % (self.filename)) result = [] for obj in self.fstream.Objects: geom = obj.Geometry print(geom) if type(geom) is Extrusion: geom = geom.ToBrep(splitKinkyFaces=True) if type(geom) is Brep: for idx in range(len(geom.Faces)): print(' ', geom.Faces[idx], "(", geom.Faces[idx].UnderlyingSurface(), ")") nsrf = geom.Faces[idx].UnderlyingSurface().ToNurbsSurface() result.append(self.read_surface(nsrf)) if type(geom) is Line: geom = result.append(curve_factory.line(geom.From, geom.To)) continue if type(geom) is PolylineCurve: geom = geom.ToPolyline() if type(geom) is Polyline or \ type(geom) is Circle or \ type(geom) is threedmCurve or \ type(geom) is BezierCurve or \ type(geom) is Arc: geom = geom.ToNurbsCurve() if type(geom) is NurbsCurve: result.append(self.read_curve(geom)) if type(geom) is Cylinder or \ type(geom) is Sphere or \ type(geom) is threedmSurface: geom = geom.ToNurbsSurface() if type(geom) is NurbsSurface: result.append(self.read_surface(geom)) return result
def test_constructor(self): trim_loop = [ CurveFactory.line([.25, .25], [.75, .25]), CurveFactory.line([.75, .25], [.75, .75]), CurveFactory.line([.75, .75], [.25, .75]), CurveFactory.line([.25, .75], [.25, .25]) ] # error with non-closed trimming loop with self.assertRaises(RuntimeError): s = TrimmedSurface(loops=[trim_loop[:3]]) # error with trimming curves in 3D space with self.assertRaises(RuntimeError): loop_3d = [ CurveFactory.line([.25, .25, 1], [.75, .25, 1]), CurveFactory.line([.75, .25, 1], [.75, .75, 1]), CurveFactory.line([.75, .75, 1], [.25, .75, 1]), CurveFactory.line([.25, .75, 1], [.25, .25, 1]) ] s = TrimmedSurface(loops=[loop_3d]) s = TrimmedSurface(loops=[trim_loop]) self.assertEqual(s.dimension, 2) self.assertFalse(s.rational)
def cut_square(width, height, radius, inner_radius, nel_ang, order, out): # Compute number of elements along each part rest1 = height - radius - inner_radius rest2 = width - radius - inner_radius nel_cyl = int(np.ceil(4/np.pi * (inner_radius - radius) / radius * nel_ang)) nel_rest1 = int(np.ceil(4/np.pi * rest1 / radius * nel_ang)) nel_rest2 = int(np.ceil(4/np.pi * rest2 / radius * nel_ang)) # Create quarter circles theta = np.linspace(0, np.pi/2, 2*nel_ang+1)[::-1] pts = np.array([radius * np.cos(theta), radius * np.sin(theta)]).T circle = cf.cubic_curve(pts, boundary=cf.Boundary.NATURAL).set_dimension(3) knots = circle.knots('u') inner1, inner2 = circle.split(knots[len(knots) // 2]) # Fill the cylinder patches factor = inner_radius / radius outer1, outer2 = inner1 * factor, inner2 * factor cyl1 = sf.edge_curves(inner1, outer1).set_order(4,4).refine(0, nel_cyl-1) cyl2 = sf.edge_curves(inner2, outer2).set_order(4,4).refine(0, nel_cyl-1) # Create the "curved rectangles" dist = np.sqrt(2) * radius edge1 = cf.line((0, height), (dist, height)).set_order(4).set_dimension(3).refine(nel_ang-1) rect1 = sf.edge_curves(outer1, edge1).set_order(4,4).refine(0, nel_rest1-1) edge2 = cf.line((width, dist), (width, 0)).set_order(4).set_dimension(3).refine(nel_ang-1) rect2 = sf.edge_curves(outer2, edge2).set_order(4,4).refine(0, nel_rest2-1) # Final square edge1 = rect2.section(u=0) edge2 = edge1 + (0, height - dist, 0) rect = sf.edge_curves(edge1, edge2).set_order(4,4).refine(0, nel_rest1-1) diff = 4 - order patches = [patch.lower_order(diff, diff) for patch in [cyl1, cyl2, rect1, rect2, rect]] with G2(out + '.g2') as f: f.write(patches) root = etree.Element('geometry') etree.SubElement(root, 'patchfile').text = out + '.g2' topology = etree.SubElement(root, 'topology') for mid, sid, midx, sidx, rev in [(1,2,2,1,False), (1,3,4,3,False), (2,4,4,3,False), (3,5,2,1,False), (4,5,1,3,False)]: etree.SubElement(topology, 'connection').attrib.update({ 'master': str(mid), 'slave': str(sid), 'midx': str(midx), 'sidx': str(sidx), 'reverse': 'true' if rev else 'false', }) topsets = etree.SubElement(root, 'topologysets') for name, entries in [('Circle', [(1, (3,)), (2, (3,))]), ('Left', [(1, (1,)), (3, (1,))]), ('Right', [(4, (4,)), (5, (2,))]), ('Top', [(3, (4,)), (5, (4,))]), ('Bottom', [(2, (2,)), (4, (2,))])]: topset = etree.SubElement(topsets, 'set') topset.attrib.update({'name': name, 'type': 'edge'}) for pid, indices in entries: item = etree.SubElement(topset, 'item') item.attrib['patch'] = str(pid) item.text = ' '.join(str(i) for i in indices) with open(out + '.xinp', 'wb') as f: f.write(etree.tostring( root, pretty_print=True, encoding='utf-8', xml_declaration=True, standalone=False ))
def cylinder(diam, width, front, back, side, height, re, grad, inner_elsize, nel_side, nel_bndl, nel_circ, nel_height, order, out, outer_graded, thickness): assert all(f >= width for f in [front, back, side]) rad_cyl = diam / 2 width *= rad_cyl back = back * rad_cyl - width front = front * rad_cyl - width side = side * rad_cyl - width elsize = width * 2 / nel_circ dim = 2 if height == 0.0 else 3 vx_add = 8 if dim == 3 else 0 patches = PatchDict(dim) if inner_elsize and nel_side: # Calculate grading factor based on first element size, # total length and number of elements dr = rad_cyl * inner_elsize grad = find_factor(dr, width - rad_cyl, nel_side) elif nel_bndl and grad: # Calculate first element size based on total length # and number of elements # We want nel_bndl elements inside the boundary layer # Calculate how small the inner element must be size_bndl = 1 / sqrt(re) * diam dr = (1 - grad) / (1 - grad**nel_bndl) * size_bndl # Potentially reduce element size so we get a whole number of elements # on either side of the cylinder #nel_side = int(ceil(log(1 - 1/dr * (1 - grad) * (width - rad_cyl)) / log(grad))) nel_side = int( round( log(1 - 1 / dr * (1 - grad) * (width - rad_cyl)) / log(grad))) dr = (1 - grad) / (1 - grad**nel_side) * (width - rad_cyl) else: print('Specify (inner-elsize and nel-side) or (nel-bndl and grad)', file=sys.stderr) sys.exit(1) # Graded radial space from cylinder to edge of domain radial_kts = graded_space(rad_cyl, dr, grad, nel_side) + [width] # Create a radial and divide it radial = cf.cubic_curve(np.matrix(radial_kts).T, boundary=cf.Boundary.NATURAL) radial.set_dimension(3) radial_kts = radial.knots('u') # middle = radial_kts[len(radial_kts) // 2] middle = next(k for k in radial_kts if k >= thickness * diam) radial_inner, radial_outer = radial.split(middle, 'u') radial_inner.rotate(pi / 4) dl = np.linalg.norm( radial_outer(radial_outer.knots('u')[-2]) - radial_outer.section(u=-1)) * grad # Revolve the inner radial and divide it radials = [ radial_inner.clone().rotate(v) for v in np.linspace(0, 2 * pi, 4 * nel_circ + 1) ] inner = sf.loft(radials) ikts = inner.knots('v') inner.insert_knot((ikts[0] + ikts[1]) / 2, 'v') inner.insert_knot((ikts[-1] + ikts[-2]) / 2, 'v') ikts = inner.knots('v') patches.add('iu', 'il', 'id', 'ir', inner.split([ikts[k * nel_circ] for k in range(5)][1:-1], 'v')) patches.connect( ('ir', 4, 'iu', 3), ('iu', 4, 'il', 3), ('il', 4, 'id', 3), ('id', 4, 'ir', 3), ) patches.boundary('cylinder', 'ir', 1) patches.boundary('cylinder', 'iu', 1) patches.boundary('cylinder', 'il', 1) patches.boundary('cylinder', 'id', 1) # Create an outer section rc = radial_outer.section(u=0) alpha = (sqrt(2) * width - rc[0]) / (width - rc[0]) right = ((radial_outer - rc) * alpha + rc).rotate(pi / 4) left = right.clone().rotate(pi / 2).reverse() outer = cf.line((-width, width, 0), (width, width, 0)) outer.set_order(4).refine(nel_circ - 1) inner = patches['iu'].section(u=-1) outer = sf.edge_curves(right, outer, left, inner).reverse('v') patches.add('ou', 'ol', 'od', 'or', [outer.clone().rotate(v) for v in [0, pi / 2, pi, 3 * pi / 2]]) patches.connect( ('or', 4, 'ou', 3), ('ou', 4, 'ol', 3), ('ol', 4, 'od', 3), ('od', 4, 'or', 3), ('or', 1, 'ir', 2), ('ou', 1, 'iu', 2), ('ol', 1, 'il', 2), ('od', 1, 'id', 2), ) if front > 0: la = patches['ol'].section(u=-1) lb = la.clone() - (front, 0, 0) front_srf = sf.edge_curves(lb, la).set_order(4, 4).swap().reverse('v') nel = int(ceil(log(1 - 1 / dl * (1 - grad) * front) / log(grad))) geometric_refine(front_srf, grad, nel - 1, reverse=True) patches['fr'] = front_srf patches.connect(('fr', 2, 'ol', 2, 'rev')) patches.boundary('inflow', 'fr', 1) else: patches.boundary('inflow', 'ol', 2) patches.boundary('inflow', 'ou', 4, dim=-2, add=vx_add) patches.boundary('inflow', 'od', 2, dim=-2, add=vx_add) if back > 0: la = patches['or'].section(u=-1) lb = la.clone() + (back, 0, 0) back_srf = sf.edge_curves(la, lb).set_order(4, 4).swap() if outer_graded: nel = int(ceil(log(1 - 1 / dl * (1 - grad) * back) / log(grad))) geometric_refine(back_srf, grad, nel - 1) else: #nel = int(ceil(back / dl)) nel = int(round(back / (2 * width) * nel_circ)) back_srf.refine(nel - 1, direction='u') patches['ba'] = back_srf patches.connect(('ba', 1, 'or', 2)) patches.boundary('outflow', 'ba', 2) else: patches.boundary('outflow', 'or', 2) if side > 0: la = patches['ou'].section(u=-1).reverse() lb = la + (0, side, 0) patches['up'] = sf.edge_curves(la, lb).set_order(4, 4) patches.connect(('up', 3, 'ou', 2, 'rev'), ('dn', 4, 'od', 2)) patches.boundary('top', 'up', 4) patches.boundary('bottom', 'dn', 3) if 'fr' in patches: btm = front_srf.section(v=-1) right = patches['up'].section(u=0) top = (btm + (0, side, 0)).reverse() left = (right - (front, 0, 0)).reverse() patches['upfr'] = sf.edge_curves(btm, right, top, left) patches.connect( ('upfr', 3, 'fr', 4), ('upfr', 2, 'up', 1), ('dnfr', 4, 'fr', 3), ('dnfr', 2, 'dn', 1), ) patches.boundary('wall', 'upfr', 4) patches.boundary('inflow', 'upfr', 1) patches.boundary('wall', 'dnfr', 3) patches.boundary('inflow', 'dnfr', 1) else: patches.boundary('inflow', 'up', 1) patches.boundary('inflow', 'dn', 1) if 'ba' in patches: btm = back_srf.section(v=-1) left = patches['up'].section(u=-1).reverse() top = (btm + (0, side, 0)).reverse() right = (left + (back, 0, 0)).reverse() patches['upba'] = sf.edge_curves(btm, right, top, left) patches.connect( ('upba', 3, 'ba', 4), ('upba', 1, 'up', 2), ('dnba', 4, 'ba', 3), ('dnba', 1, 'dn', 2), ) patches.boundary('wall', 'upba', 4) patches.boundary('outflow', 'upfr', 2) patches.boundary('wall', 'dnba', 3) patches.boundary('outflow', 'dnba', 2) else: patches.boundary('outflow', 'up', 2) patches.boundary('outflow', 'dn', 2) nel = int(ceil(log(1 - 1 / dl * (1 - grad) * side) / log(grad))) for uk in {'up', 'upfr', 'upba'} & patches.keys(): dk = 'dn' + uk[2:] patches[dk] = patches[uk] - (0, side + 2 * width, 0) geometric_refine(patches[uk], grad, nel - 1, direction='v') geometric_refine(patches[dk], grad, nel - 1, direction='v', reverse=True) else: patches.boundary('wall', 'ou', 2) patches.boundary('wall', 'od', 2) patches.boundary('wall', 'or', 4, dim=-2, add=vx_add) patches.boundary('wall', 'or', 2, dim=-2, add=vx_add) if 'fr' in patches: patches.boundary('wall', 'fr', 4) patches.boundary('wall', 'fr', 3) patches.boundary('wall', 'ol', 2, dim=-2, add=vx_add) patches.boundary('wall', 'ol', 4, dim=-2, add=vx_add) if 'ba' in patches: patches.boundary('wall', 'ba', 4) patches.boundary('wall', 'ba', 3) if height > 0.0: names = [ 'iu', 'il', 'id', 'ir', 'ou', 'ol', 'od', 'or', 'fr', 'ba', 'up', 'upba', 'upfr', 'dn', 'dnba', 'dnfr' ] for pname in names: if pname not in patches: continue patch = patches[pname] patch = extrude(patch, (0, 0, height)) patch.raise_order(0, 0, 2) patch.refine(nel_height - 1, direction='w') patches[pname] = patch patches.boundary('zup', pname, 6) patches.boundary('zdown', pname, 5) patches.connect((pname, 5, pname, 6, 'per')) patches.write(out, order=order)
def flag(diam, flag_width, flag_length, width, back, flag_grad, grad, nel_rad, nel_circ, nel_flag, order, out): assert (back > width) rad_cyl = diam / 2 width *= rad_cyl back = back * rad_cyl - width # Create a circle angle = 2 * np.arcsin(flag_width / rad_cyl / 2) pts = rad_cyl * np.array( [(np.cos(a), np.sin(a)) for a in np.linspace(angle, 2 * np.pi - angle, nel_circ + 1)]) circle = cf.cubic_curve(pts, boundary=cf.Boundary.NATURAL) circle.set_dimension(3) # Subdivide it nels_side = int(round(nel_circ // 2 * 3 * np.pi / 4 / (np.pi - angle))) nels_front = (nel_circ // 2 - nels_side) * 2 S = (-nel_flag * width + nels_side * (width + back)) / (nel_flag + nels_side) kts = circle.knots('u') kts = kts[nels_side], kts[nels_side + nels_front] circ_up, circ_front, circ_down = circle.split(kts) # Extend to boundary front = cf.line((-width, width), (-width, -width)).set_order(4).refine(nels_front - 1) front = sf.edge_curves(front, circ_front).raise_order(0, 2) geometric_refine(front, grad, nel_rad - 1, direction='v', reverse=True) up = cf.line((S, width), (-width, width)).set_order(4).refine(nels_side - 1) up = sf.edge_curves(up, circ_up).raise_order(0, 2) geometric_refine(up, grad, nel_rad - 1, direction='v', reverse=True) down = cf.line((-width, -width), (S, -width)).set_order(4).refine(nels_side - 1) down = sf.edge_curves(down, circ_down).raise_order(0, 2) geometric_refine(down, grad, nel_rad - 1, direction='v', reverse=True) # Create the flag upt = circle(circle.start('u')) fl_up = cf.line((flag_length + rad_cyl, upt[1], 0), upt).raise_order(2) geometric_refine(fl_up, flag_grad, nel_flag - 1, direction='u', reverse=True) ln_up = cf.cubic_curve(np.array([((1 - i) * (width + back) + i * S, width) for i in np.linspace(0, 1, nel_flag + 1) ]), boundary=cf.Boundary.NATURAL, t=fl_up.knots('u')) fl_up = sf.edge_curves(ln_up, fl_up).raise_order(0, 2) geometric_refine(fl_up, grad, nel_rad - 1, direction='v', reverse=True) dpt = circle(circle.end('u')) fl_down = cf.line(dpt, (flag_length + rad_cyl, dpt[1], 0)) geometric_refine(fl_down, flag_grad, nel_flag - 1, direction='u') ln_down = cf.cubic_curve(np.array([ ((1 - i) * S + i * (width + back), -width) for i in np.linspace(0, 1, nel_flag + 1) ]), boundary=cf.Boundary.NATURAL, t=fl_down.knots('u')) fl_down = sf.edge_curves(ln_down, fl_down).raise_order(0, 2) geometric_refine(fl_down, grad, nel_rad - 1, direction='v', reverse=True) fl_back = cf.line((flag_length + rad_cyl, dpt[1], 0), (flag_length + rad_cyl, upt[1], 0)) ln_back = cf.line((width + back, -width, 0), (width + back, width, 0)) fl_back = sf.edge_curves(ln_back, fl_back).raise_order(2, 2).refine(40, direction='u') geometric_refine(fl_back, grad, nel_rad - 1, direction='v', reverse=True) with G2(out + '.g2') as f: f.write([up, front, down, fl_up, fl_down, fl_back]) root = etree.Element('geometry') etree.SubElement(root, 'patchfile').text = out + '.g2' topology = etree.SubElement(root, 'topology') for mid, sid, midx, sidx, rev in [(1, 2, 2, 1, False), (1, 4, 1, 2, False), (2, 3, 2, 1, False), (3, 5, 2, 1, False), (4, 6, 1, 2, False), (5, 6, 2, 1, False)]: etree.SubElement(topology, 'connection').attrib.update({ 'master': str(mid), 'slave': str(sid), 'midx': str(midx), 'sidx': str(sidx), 'reverse': 'true' if rev else 'false', }) topsets = etree.SubElement(root, 'topologysets') for name, index, entries in [('inflow', 3, [2]), ('outflow', 3, [6]), ('top', 3, [1, 4]), ('bottom', 3, [3, 5]), ('cylinder', 4, [1, 2, 3]), ('flag', 4, [4, 5, 6])]: topset = etree.SubElement(topsets, 'set') topset.attrib.update({'name': name, 'type': 'edge'}) for pid in entries: item = etree.SubElement(topset, 'item') item.attrib['patch'] = str(pid) item.text = str(index) topset = etree.SubElement(topsets, 'set') topset.attrib.update({'name': 'inflow', 'type': 'vertex'}) item = etree.SubElement(topset, 'item') item.attrib['patch'] = '2' item.text = '1 2' with open(out + '.xinp', 'wb') as f: f.write( etree.tostring(root, pretty_print=True, encoding='utf-8', xml_declaration=True, standalone=False))