fusion-energy / paramak

Create parametric 3D fusion reactor CAD and neutronics models
https://paramak.readthedocs.io/en/main/
MIT License
58 stars 17 forks source link

Refactor reactor to assembly #304

Open shimwell opened 1 year ago

shimwell commented 1 year ago

I have been thinking about a refactor that makes use of the cadquery assembly.

This PR is a working progress but I think it shows some potential as we have a nice large reduction to the number of lines

shimwell commented 1 year ago

Alternatively I could inherit assembly like this

class ChildAssembly(Assembly):
    def __init__(self, obj: AssemblyObjects = None, loc: Optional[Location] = None, name: Optional[str] = None, color: Optional[Color] = None, metadata: Optional[Dict[str, Any]] = None):
        super().__init__(obj, loc, name, color, metadata)
shimwell commented 1 year ago

I think I might try a different approach, using patching

import cadquery as cq

@classmethod
def build_reactor(cls, height: float=1.):
    plane='XY'
    wp1 = cq.Workplane(plane).box(2.0, 2.0, height)
    wp2 = cq.Workplane("XY").circle(2.0).rect(0.5, 0.75).extrude(0.5)
    wp3 = cq.Workplane().build_component(height=height)

    my_assembly=cq.Assembly()

    my_assembly.add(wp1, name='wp1')
    my_assembly.add(wp2, name='wp2')
    my_assembly.add(wp3, name='wp3')

    return my_assembly

cq.assembly.Assembly.build_reactor = build_reactor

@classmethod
def build_component(cls,
    height: float = 10,
    plane: str='XY'
):
    wp = cq.Workplane(plane).box(2.0, 2.0, height)

    return wp

cq.Workplane.build_component = build_component

my_component = cq.Workplane().build_component()

my_reactor = cq.Assembly().build_reactor(height=10)
my_reactor.save(path='reactor.step')
my_reactor.add(my_component, name='my_component')
my_reactor.save(path='reactor2.step')
shimwell commented 1 year ago

Perhaps the first stage is to make functions for the components, remove the shape.py and make a few util functions. example for BlanketConstantThicknessArcH might look like this

from typing import Tuple

from cadquery import Workplane

def instructions_from_points(points):
    # obtains the first two values of the points list
    XZ_points = [(p[0], p[1]) for p in points]

    # obtains the last values of the points list
    connections = [p[2] for p in points[:-1]]

    current_linetype = connections[0]
    current_points_list = []
    instructions = []
    # groups together common connection types
    for i, connection in enumerate(connections):
        if connection == current_linetype:
            current_points_list.append(XZ_points[i])
        else:
            current_points_list.append(XZ_points[i])
            instructions.append({current_linetype: current_points_list})
            current_linetype = connection
            current_points_list = [XZ_points[i]]
    instructions.append({current_linetype: current_points_list})

    if list(instructions[-1].values())[0][-1] != XZ_points[0]:
        keyname = list(instructions[-1].keys())[0]
        instructions[-1][keyname].append(XZ_points[0])
    return instructions

def create_wire_workplane_from_instructions(instructions,workplane='XY'):

    solid = Workplane(workplane) #offset=extrusion_offset

    for entry in instructions:
        if list(entry.keys())[0] == "spline":
            solid = solid.spline(listOfXYTuple=list(entry.values())[0])
        if list(entry.keys())[0] == "straight":
            solid = solid.polyline(list(entry.values())[0])
        if list(entry.keys())[0] == "circle":
            p0 = list(entry.values())[0][0]
            p1 = list(entry.values())[0][1]
            p2 = list(entry.values())[0][2]
            solid = solid.moveTo(p0[0], p0[1]).threePointArc(p1, p2)

    return solid.close()

def BlanketConstantThicknessArcH(
    inner_mid_point: Tuple[float, float],
    inner_upper_point: Tuple[float, float],
    inner_lower_point: Tuple[float, float],
    thickness: float,
    rotation_angle=90,
    # workplane 
):

    points = [
        (inner_upper_point[0], inner_upper_point[1], "circle"),
        (inner_mid_point[0], inner_mid_point[1], "circle"),
        (inner_lower_point[0], inner_lower_point[1], "straight"),
        (
            inner_lower_point[0] + abs(thickness),
            inner_lower_point[1],
            "circle",
        ),
        (
            inner_mid_point[0] + abs(thickness),
            inner_mid_point[1],
            "circle",
        ),
        (
            inner_upper_point[0] + abs(thickness),
            inner_upper_point[1],
            "straight",
        ),
    ]

    points.append(points[0])

    instructions = instructions_from_points(points)
    print(instructions)
    wire = create_wire_workplane_from_instructions(instructions=instructions)
    print(wire)

    solid = wire.revolve(rotation_angle)
    return solid

a=BlanketConstantThicknessArcH(
    (10,0),
    (2,10),
    (2,-10),
    10
)