#!/usr/bin/env python3 """ This script creates an assembly for liquid immersion and allows for various exports. Usage: python3 sys-assembly --display --stl output.stl """ import argparse from bd_cruft import ( atx_motherboard, immersion_mb_plate, tslot_extrusion, atx_psu, immersion_pci_gpu, immersion_tank, immersion_chassis, immersion_lid, export_3d, ) from build123d import * from ocp_vscode import * import logging import copy TANK_THICK = 9 # XXX from immersion tank, don't set statically TSLOT_HI_LEN = 380 + TANK_THICK # Length of 4x corners from immersion_chassis TSLOT_WIDE_LEN = 450 # Length of 5x left/right horizontal from immersion_chassis TSLOT_DEEP_LEN = 260 # Length of 4x front/back horizontal TSLOT_SIZE = 20 # Size of extrusion (e.g. 20mm x 20mm) BOT_OFFSET = 24 # How far first horizontal extrusion is from bottom WEIR_OFFSET = 60 # XXX from immersion_tank, don't set statically MB_PLATE_THICKNESS = 5.6 # XXX FIX don't set TANK_OFFSET_X = TSLOT_SIZE # The zero points on the motherboard are the first hole, not the edge of the board. MB_RISER = 6.5 # Size of motherboard risers/standoffs GPU_OFFSET = 12 + 2 # Distance from motherboard to GPU ATX_PSU_LENGTH = 200 # XXX from atx_psu ATX_PSU_WIDTH = 85 # Width of PSU XXX from atx_psu ATX_PSU_HEIGHT = 150 # XXX from atx_psu export_formats = { "mf": export_3d.export_mf, "stl": export_3d.export_stl, "step": export_3d.sys_export_step, "brep": export_3d.sys_export_brep, } def compound_assembly(): # Immersion Chassis chassis_config = immersion_chassis.ImmersionChassisConfig() chassis = immersion_chassis.compound_chassis(**chassis_config.model_dump()) compound_chassis = Compound.make_compound(chassis).locate( Location( Vector( 0, 0, 0, ), (0, 0, 0), ) ) compound_chassis.label = "Immersion Chassis" compound_chassis.color = Color(0.5, 0.5, 0.5, 1.0) # Acrylic immersion tank tank_config = immersion_tank.TankConfig() tank = immersion_tank.create_tank(**tank_config.model_dump()) compound_tank = Compound.make_compound(tank).locate( Location( Vector( TANK_OFFSET_X, TSLOT_SIZE, 0, ), (0, 0, 0), ) ) compound_tank.label = "Immersion Tank" compound_tank.color = Color(0.25, 0.64, 0.76, 0.35) # Acrylic # Acrylic immersion motherboard mount plate plate_config = immersion_mb_plate.ImmersionMBPlateConfig() plate = immersion_mb_plate.create_plate(**plate_config.model_dump()) plate.label = "Immersion Motherboard Plate" compound_plate = Compound.make_compound([(plate.part)]).locate( Location( Vector( TANK_OFFSET_X + TANK_THICK, TSLOT_SIZE + tank_config.tank_length - TANK_THICK - WEIR_OFFSET, TANK_THICK, ), (90, 0, 0), ) ) compound_plate.label = "MB Mount Plate" compound_plate.color = Color(0.25, 0.64, 0.76, 0.25) # Acrylic # Acrylic Immersion Lid lid_config = immersion_lid.ImmersionLidConfig() lid = immersion_lid.create_plate(**lid_config.model_dump()) lid.label = "Immersion Lid" compound_lid = Compound.make_compound([(lid.part)]).locate( Location( Vector( 0, 0, TSLOT_HI_LEN, ), (0, 0, 0), ) ) compound_lid.label = "Immersion Lid" compound_lid.color = Color(0.25, 0.64, 0.76, 0.25) # Acrylic # ATX Motherboard mb = import_step(file_name="examples/motherboard.stp") mb.label = "Motherboard" compound_mb = Compound.make_compound([(mb)]).locate( Location( Vector( TSLOT_SIZE + 16 + TANK_OFFSET_X + TANK_THICK, TSLOT_SIZE + tank_config.tank_length - TANK_THICK - WEIR_OFFSET - MB_PLATE_THICKNESS - MB_RISER, 243.84 + 99, ), (0, 180, 180), ) ) compound_mb.label = "Motherboard" compound_mb.color = Color("ForestGreen", 1.0) # # Koolance ERM-3K3U # koolance = import_step(file_name="examples/koolance.step") # koolance.label = "Koolance" # compound_koolance = Compound.make_compound([(koolance)]).locate( # Location( # Vector( # 900, # 388, # 240, # ), # (90, 90, 0), # ) # ) # compound_koolance.label = "Koolance ERM-3K3U" # compound_koolance.color = Color("Black", 1.0) # Power Supplies def create_psu(label, location): psu_config = atx_psu.AtxpsuConfig() psu = atx_psu.create_atx_psu(**psu_config.model_dump()) psu.label = label compound = Compound.make_compound([(psu.part)]).locate(location) return psu, compound # ATX PSU1 psu1_config = atx_psu.AtxpsuConfig() psu1, compound_psu1 = create_psu( "PSU1", Location( Vector( # PSU on back of chassis # (psu1_config.atx_psu_width * 2) - TSLOT_SIZE, # TSLOT_DEEP_LEN + (TSLOT_SIZE * 2), # TSLOT_HI_LEN - psu1_config.atx_psu_height - (TSLOT_SIZE * 2) - (TSLOT_SIZE / 2), # ), # (0, 0, 90), # PSU on top of chassis (psu1_config.atx_psu_width * 2) - TSLOT_SIZE, TSLOT_DEEP_LEN + (TSLOT_SIZE * 2), TSLOT_HI_LEN, ), (90, 0, 90), ), ) compound_psu1.label = "PSU 1" compound_psu1.color = Color("Black", 1.0) # ATX PSU2 psu2_config = atx_psu.AtxpsuConfig() psu2, compound_psu2 = create_psu( "PSU2", Location( Vector( # PSU on back of chassis # TSLOT_WIDE_LEN - (TSLOT_SIZE / 2), # wut # TSLOT_DEEP_LEN + (TSLOT_SIZE * 2), # TSLOT_HI_LEN - psu1_config.atx_psu_height - (TSLOT_SIZE * 2) - (TSLOT_SIZE / 2), # XXX # ), # (0, 0, 90), # PSU on top of chassis TSLOT_WIDE_LEN - (TSLOT_SIZE / 2), # XXX TSLOT_DEEP_LEN + (TSLOT_SIZE * 2), TSLOT_HI_LEN, ), (90, 0, 90), ), ) compound_psu2.label = "PSU 2" compound_psu2.color = Color("SlateGray", 1.0) # PCIe GPUs for Immersion def create_gpu(label, location): gpu_config = immersion_pci_gpu.ImmersionpcigpuConfig() gpu = immersion_pci_gpu.create_immersion_pci_gpu(**gpu_config.model_dump()) gpu.label = label compound = Compound.make_compound([(gpu.part)]).locate(location) compound.label = label compound.color = Color("GreenYellow", 1.0) return gpu, compound # List of GPUs to create gpus_to_create = [ {"label": "GPU 1", "offset": 20}, {"label": "GPU 2", "offset": 40}, {"label": "GPU 3", "offset": 60}, {"label": "GPU 4", "offset": 80}, {"label": "GPU 5", "offset": 100}, {"label": "GPU 6", "offset": 120}, {"label": "GPU 7", "offset": 140}, ] all_gpus = [] gpu_compounds = [] for gpu_info in gpus_to_create: gpu, compound_gpu = create_gpu( gpu_info["label"], Location( Vector( TSLOT_SIZE + TANK_OFFSET_X + (gpu_info["offset"]), TSLOT_SIZE + tank_config.tank_length - TANK_THICK - WEIR_OFFSET - MB_PLATE_THICKNESS - MB_RISER - GPU_OFFSET, 84, ), (90, 0, 0), ), ) all_gpus.append(gpu) gpu_compounds.append(compound_gpu) all_assembly = Compound( label="Immersion AI Node", children=[ compound_chassis, compound_plate, compound_lid, compound_psu1, compound_psu2, gpu_compounds[0], gpu_compounds[1], gpu_compounds[2], gpu_compounds[3], gpu_compounds[4], gpu_compounds[5], gpu_compounds[6], compound_tank, compound_mb, # compound_koolance, ], ) # print(all_assembly.show_topology()) return all_assembly def display_object(obj: BuildPart): """ Display the given object in the IDE with specified color and transparency. :param obj: The object to be displayed. :type obj: Any :param color: The color of the object. :type color: Tuple[int, int, int] :param alpha: The transparency of the object. :type alpha: float """ show_object( obj, black_edges=False, ) def parse_args(**kwargs): """ Parse the command line arguments. :param kwargs: Additional arguments to pass to ArgumentParser.parse_args() :return: The parsed command line arguments. :rtype: Any """ parser = argparse.ArgumentParser( description="Create and manipulate a atx motherboard." ) parser.add_argument( "--display", action="store_false", help="Display the generated plate in IDE" ) parser.add_argument( "--mf", dest="mf_filename", type=str, metavar="FILENAME", help="Export the plate as an 3MF file", ) parser.add_argument( "--stl", dest="stl_filename", type=str, metavar="FILENAME", help="Export the plate as an STL file", ) parser.add_argument( "--step", dest="step_filename", type=str, metavar="FILENAME", help="Export the plate as an STEP file", ) parser.add_argument( "--brep", dest="brep_filename", type=str, metavar="FILENAME", help="Export the plate as an BREP file", ) args = parser.parse_args(**kwargs) return args def main(): args = parse_args() sys_assembly = compound_assembly() if any(filename in args for filename in export_formats): args.display = False if args.display: display_object(sys_assembly) for file_extension, export_function in export_formats.items(): filename = getattr(args, f"{file_extension}_filename") if filename is not None: export_function(sys_assembly, filename) if __name__ == "__main__": main()