diff --git a/docs/usage.rst b/docs/usage.rst index 5575efcc..d1c72ea3 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -13,6 +13,14 @@ The reactors can be varied in terms of their radial build, vertical build, elong These examples show how to make various reactors with and without different components, each example is minimal and aims to show a single feature, you will have to combine examples to make a complete model. + +.. toctree:: + :maxdepth: 3 + + usage_tokamak + usage_spherical_tokamak + + Visualization options ===================== @@ -36,684 +44,3 @@ or the jupyter_cadquery package which allows for interactive 3D visualization in from jupyter_cadquery import show view = show(result) # where result is the returned reactor or component object view.export_html("3d.html") - - -Tokamak from plasma -------------------- - -- The tokamak_from_plasma function provides a parametric tokamak shaped reactor. -- This is characterized by a continuous blanket that goes around the inboard and outboard sides of the plasma. -- This reactor requires few arguments to create as it keeps the vertical build of the blanket layers the same thickness as the radial build. - -.. cadquery:: - :gridsize: 0 - :select: result - :color: #00cd00 - :width: 100% - :height: 600px - - import paramak - result = paramak.tokamak_from_plasma( - radial_builds=[ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 30), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 10), - ], - elongation=2, - triangularity=0.55, - rotation_angle=90, - ).toCompound() - - -.. code-block:: python - - import paramak - result = paramak.tokamak_from_plasma( - radial_builds=[ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 30), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 10), - ], - elongation=2, - triangularity=0.55, - rotation_angle=90, - ) - - -Spherical tokamak from plasma ------------------------------ - -- The spherical_tokamak_from_plasma function provides a parametric tokamak shaped reactor. -- This is characterized by a blanket that only goes around the outboard sides of the plasma. -- This reactor requires few arguments to create as it keeps the vertical build of the blanket layers the same thickness as the radial build. - - -.. cadquery:: - :gridsize: 0 - :select: result - :color: #00cd00 - :width: 100% - :height: 600px - - import paramak - result = paramak.spherical_tokamak_from_plasma( - radial_builds=[ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 10), - ], - elongation=2, - triangularity=0.55, - rotation_angle=90, - ).toCompound() - - -.. code-block:: python - - import paramak - result = paramak.spherical_tokamak_from_plasma( - radial_builds=[ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 10), - ], - elongation=2, - triangularity=0.55, - rotation_angle=90, - ) - result.save('reactor.step') - - - -Tokamak -------- - -- The spherical_tokamak function provides a parametric tokamak shaped reactor. -- This is characterized by a blanket that only goes around the outboard sides of the plasma. -- This reactor allows for a separate vertical and radial build which allows different thickness layers in the blanket. - -.. cadquery:: - :gridsize: 0 - :select: result - :color: #00cd00 - :width: 100% - :height: 600px - - import paramak - - result = paramak.tokamak( - radial_builds=[ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 30), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 10), - ], - vertical_build=[ - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 80), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 700), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 40), - (paramak.LayerType.SOLID, 15), - ], - triangularity=0.55, - rotation_angle=180, - ).toCompound() - -.. code-block:: python - - import paramak - - result = paramak.tokamak( - radial_builds=[ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 30), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 10), - ], - vertical_build=[ - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 80), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 700), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 40), - (paramak.LayerType.SOLID, 15), - ], - triangularity=0.55, - rotation_angle=180, - ) - - result.save(f"tokamak_minimal.step") - - - -Spherical tokamak ------------------ - -- The spherical_tokamak function provides a parametric tokamak shaped reactor. -- This is characterized by a blanket that only goes around the outboard sides of the plasma. -- This reactor allows for a separate vertical and radial build which allows different thickness layers in the blanket. - -.. cadquery:: - :gridsize: 0 - :select: result - :color: #00cd00 - :width: 100% - :height: 600px - - import paramak - - result = paramak.spherical_tokamak( - radial_builds=[ - [ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ] - ], - vertical_build=[ - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 700), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 30), - (paramak.LayerType.SOLID, 15), - ], - rotation_angle=180, - triangularity=0.55, - ).toCompound() - -.. code-block:: python - - import paramak - - result = paramak.spherical_tokamak( - radial_builds=[ - [ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ] - ], - vertical_build=[ - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 700), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 30), - (paramak.LayerType.SOLID, 15), - ], - rotation_angle=180, - triangularity=0.55, - ) - - result.save(f"spherical_tokamak_minimal.step") - -Reactor with divertor(s) ------------------------- - -- ll reactors support adding additional radial builds for the lower_divertor and or the upper_divertor. -- This example adds two divertors to a spherical_tokamak_from_plasma reactor but and other reactor would also work. - -.. cadquery:: - :gridsize: 0 - :select: result - :color: #00cd00 - :width: 100% - :height: 600px - - result = paramak.spherical_tokamak_from_plasma( - radial_builds=[ - [ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ], - [(paramak.LayerType.GAP, 75), ("lower_divertor", 100)], # this divertor connects to the center column - [(paramak.LayerType.GAP, 120), ("upper_divertor", 100)], # this divertor has some blanket between the center colum and itself - ], - elongation=2, - triangularity=0.55, - rotation_angle=180, - ).toCompound() - - -.. code-block:: python - - result = paramak.spherical_tokamak_from_plasma( - radial_builds=[ - [ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ], - [(paramak.LayerType.GAP, 75), ("lower_divertor", 100)], # this divertor connects to the center column - [(paramak.LayerType.GAP, 120), ("upper_divertor", 140)], # this divertor has some blanket between the center colum and itself - ], - elongation=2, - triangularity=0.55, - rotation_angle=180, - ) - result.save('reactor.step') - -Reactor with poloidal field coils ---------------------------------- - -- All reactors support adding a sequence of CadQuery shapes (e.g. workplanes) to the reactor using the add_extra_cut_shapes argument -- This example adds PF coils to a spherical_tokamak_from_plasma reactor but and other reactor would also work. - - -.. cadquery:: - :gridsize: 0 - :select: result - :color: #00cd00 - :width: 100% - :height: 600px - - import paramak - - add_extra_cut_shapes = [] - for case_thickness, height, width, center_point in zip( - [10, 15, 15, 10], [20, 50, 50, 20], [20, 50, 50, 20], - [(500, 300), (560, 100), (560, -100), (500, -300)] - ): - add_extra_cut_shapes.append( - paramak.poloidal_field_coil( - height=height, width=width, center_point=center_point, rotation_angle=270 - ) - ) - add_extra_cut_shapes.append( - paramak.poloidal_field_coil_case( - coil_height=height, - coil_width=width, - casing_thickness=case_thickness, - rotation_angle=270, - center_point=center_point, - ) - ) - - result = paramak.spherical_tokamak_from_plasma( - radial_builds=[ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ], - elongation=2, - triangularity=0.55, - rotation_angle=270, - add_extra_cut_shapes=add_extra_cut_shapes, - ).toCompound() - - -.. code-block:: python - - import paramak - - add_extra_cut_shapes = [] - for case_thickness, height, width, center_point in zip( - [10, 15, 15, 10], [20, 50, 50, 20], [20, 50, 50, 20], - [(500, 300), (560, 100), (560, -100), (500, -300)] - ): - add_extra_cut_shapes.append( - paramak.poloidal_field_coil( - height=height, width=width, center_point=center_point, rotation_angle=270 - ) - ) - add_extra_cut_shapes.append( - paramak.poloidal_field_coil_case( - coil_height=height, - coil_width=width, - casing_thickness=case_thickness, - rotation_angle=270, - center_point=center_point, - ) - ) - - result = paramak.spherical_tokamak_from_plasma( - radial_builds=[ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ], - elongation=2, - triangularity=0.55, - rotation_angle=270, - add_extra_cut_shapes=add_extra_cut_shapes, - ) - - result.save(f"spherical_tokamak_from_plasma_with_pf_magnets.step") - - -Reactor with toroidal field coils ---------------------------------- - -- In a similar way to adding poloidal field coils one can also add toroidal field coils by making use of the add_extra_cut_shapes argument. -- All reactors support adding a sequence of CadQuery shapes (e.g. workplanes) to the reactor using the add_extra_cut_shapes argument -- This example adds TF coils to a spherical_tokamak_from_plasma reactor but and other reactor would also work. -- Also these are rectangle shaped TF coils but other shapes are also available. - - -.. cadquery:: - :gridsize: 0 - :select: result - :color: #00cd00 - :width: 100% - :height: 600px - - import paramak - - tf = paramak.toroidal_field_coil_rectangle( - horizontal_start_point = (10, 520), - vertical_mid_point = (600, 0), - thickness = 50, - distance = 40, - with_inner_leg = True, - azimuthal_placement_angles = [0, 30, 60, 90, 120, 150, 180], - ) - - result = paramak.spherical_tokamak_from_plasma( - radial_builds=[ - (paramak.LayerType.GAP, 70), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ], - elongation=2.5, - rotation_angle=180, - triangularity=0.55, - add_extra_cut_shapes=[tf] - ).toCompound() - -.. code-block:: python - - import paramak - - tf = paramak.toroidal_field_coil_rectangle( - horizontal_start_point = (10, 520), - vertical_mid_point = (600, 0), - thickness = 50, - distance = 40, - with_inner_leg = True, - azimuthal_placement_angles = [0, 30, 60, 90, 120, 150, 180], - ) - - result = paramak.spherical_tokamak_from_plasma( - radial_builds=[ - (paramak.LayerType.GAP, 70), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ], - elongation=2.5, - rotation_angle=180, - triangularity=0.55, - add_extra_cut_shapes=[tf] - ) - - result.save(f"spherical_tokamak_minimal.step") - - -Tokamak with negative triangularity ------------------------------------ - -- The triangularity argument can be set to a negative value to make a plasma with a negative triangularity. -- This example makes a tokamak with a negative but this would work on any reactor. - -.. cadquery:: - :gridsize: 0 - :select: result - :color: #00cd00 - :width: 100% - :height: 600px - - import paramak - - result = paramak.tokamak( - radial_builds=[ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 30), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 10), - ], - vertical_build=[ - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 80), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 700), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 40), - (paramak.LayerType.SOLID, 15), - ], - triangularity=-0.55, - rotation_angle=180, - ).toCompound() - -.. code-block:: python - - import paramak - - result = paramak.tokamak( - radial_builds=[ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 30), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 20), - (paramak.LayerType.SOLID, 120), - (paramak.LayerType.SOLID, 10), - ], - vertical_build=[ - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 80), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 700), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 40), - (paramak.LayerType.SOLID, 15), - ], - triangularity=-0.55, - rotation_angle=180, - ) - - result.save(f"tokamak_minimal.step") - - - -Spherical tokamak with negative triangularity ---------------------------------------------- - -- The triangularity argument can be set to a negative value to make a plasma with a negative triangularity. -- This example makes a spherical tokamak with a negative but this would work on any reactor. - -.. cadquery:: - :gridsize: 0 - :select: result - :color: #00cd00 - :width: 100% - :height: 600px - - import paramak - - result = paramak.spherical_tokamak( - radial_builds=[ - [ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 40), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ] - ], - vertical_build=[ - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 80), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 700), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 40), - (paramak.LayerType.SOLID, 15), - ], - rotation_angle=180, - triangularity=-0.55, - ).toCompound() - -.. code-block:: python - - import paramak - - result = paramak.spherical_tokamak( - radial_builds=[ - [ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ] - ], - vertical_build=[ - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 80), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 700), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 10), - (paramak.LayerType.SOLID, 40), - (paramak.LayerType.SOLID, 15), - ], - rotation_angle=180, - triangularity=-0.55, - ) - result.save(f"spherical_tokamak_minimal.step") diff --git a/docs/usage_spherical_tokamak.rst b/docs/usage_spherical_tokamak.rst new file mode 100644 index 00000000..6c2c67d9 --- /dev/null +++ b/docs/usage_spherical_tokamak.rst @@ -0,0 +1,475 @@ +Usage +===== + +There are two main reactors to choose from, Tokamak and Spherical Tokamak. +These can be built with: +- A radial and vertical build +- A radial build and plasma elongation. + +The former gives the user more control of the size of components allowing reactor blankets to vary both radially and vertically. +The later allows reactors to be built with a minimal number of parameters. +In all cases it is possible to add additional components such as divertors, poloidal and toroidal magnets and any self made geometry as a CadQuery Workplane. +The reactors can be varied in terms of their radial build, vertical build, elongation and triangularity which gives a lot of variability. +These examples show how to make various reactors with and without different components, each example is minimal and aims to show a single feature, you will have to combine examples to make a complete model. + + + +.. toctree:: + :maxdepth: 3 + + usage-tokamak + usage-spherical-tokamak + + + +Spherical tokamak from plasma +----------------------------- + +- The spherical_tokamak_from_plasma function provides a parametric tokamak shaped reactor. +- This is characterized by a blanket that only goes around the outboard sides of the plasma. +- This reactor requires few arguments to create as it keeps the vertical build of the blanket layers the same thickness as the radial build. + + +.. cadquery:: + :gridsize: 0 + :select: result + :color: #00cd00 + :width: 100% + :height: 600px + + import paramak + result = paramak.spherical_tokamak_from_plasma( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 10), + ], + elongation=2, + triangularity=0.55, + rotation_angle=90, + ).toCompound() + + +.. code-block:: python + + import paramak + result = paramak.spherical_tokamak_from_plasma( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 10), + ], + elongation=2, + triangularity=0.55, + rotation_angle=90, + ) + result.save('reactor.step') + + + + +Spherical tokamak +----------------- + +- The spherical_tokamak function provides a parametric tokamak shaped reactor. +- This is characterized by a blanket that only goes around the outboard sides of the plasma. +- This reactor allows for a separate vertical and radial build which allows different thickness layers in the blanket. + +.. cadquery:: + :gridsize: 0 + :select: result + :color: #00cd00 + :width: 100% + :height: 600px + + import paramak + + result = paramak.spherical_tokamak( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + vertical_build=[ + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 700), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 30), + (paramak.LayerType.SOLID, 15), + ], + rotation_angle=180, + triangularity=0.55, + ).toCompound() + +.. code-block:: python + + import paramak + + result = paramak.spherical_tokamak( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + vertical_build=[ + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 700), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 30), + (paramak.LayerType.SOLID, 15), + ], + rotation_angle=180, + triangularity=0.55, + ) + + result.save(f"spherical_tokamak_minimal.step") + +Reactor with divertor(s) +------------------------ + +- ll reactors support adding additional radial builds for the lower_divertor and or the upper_divertor. +- This example adds two divertors to a spherical_tokamak_from_plasma reactor but and other reactor would also work. + +.. cadquery:: + :gridsize: 0 + :select: result + :color: #00cd00 + :width: 100% + :height: 600px + + from cadquery import Workplane + + # makes a rectangle that overlaps the lower blanket under the plasma + # the intersection of this and the layers will form the lower divertor + points = [(300, -700), (300, 0), (400, 0), (400, -700)] + divertor_lower = Workplane('XZ', origin=(0,0,0)).polyline(points).close().revolve(180) + result = paramak.spherical_tokamak_from_plasma( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + elongation=2, + triangularity=0.55, + rotation_angle=180, + extra_intersect_shapes=[divertor_lower] + ).toCompound() + + +.. code-block:: python + + from cadquery import Workplane + + # makes a rectangle that overlaps the lower blanket under the plasma + # the intersection of this and the layers will form the lower divertor + points = [(300, -700), (300, 0), (400, 0), (400, -700)] + divertor_lower = Workplane('XZ', origin=(0,0,0)).polyline(points).close().revolve(180) + result = paramak.spherical_tokamak_from_plasma( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + elongation=2, + triangularity=0.55, + rotation_angle=180, + extra_intersect_shapes=[divertor_lower] + ) + result.save('reactor.step') + +Reactor with poloidal field coils +--------------------------------- + +- All reactors support adding a sequence of CadQuery shapes (e.g. workplanes) to the reactor using the extra_cut_shapes argument +- This example adds PF coils to a spherical_tokamak_from_plasma reactor but and other reactor would also work. + + +.. cadquery:: + :gridsize: 0 + :select: result + :color: #00cd00 + :width: 100% + :height: 600px + + import paramak + + extra_cut_shapes = [] + for case_thickness, height, width, center_point in zip( + [10, 15, 15, 10], [20, 50, 50, 20], [20, 50, 50, 20], + [(500, 300), (560, 100), (560, -100), (500, -300)] + ): + extra_cut_shapes.append( + paramak.poloidal_field_coil( + height=height, width=width, center_point=center_point, rotation_angle=270 + ) + ) + extra_cut_shapes.append( + paramak.poloidal_field_coil_case( + coil_height=height, + coil_width=width, + casing_thickness=case_thickness, + rotation_angle=270, + center_point=center_point, + ) + ) + + result = paramak.spherical_tokamak_from_plasma( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + elongation=2, + triangularity=0.55, + rotation_angle=270, + extra_cut_shapes=extra_cut_shapes, + ).toCompound() + + +.. code-block:: python + + import paramak + + extra_cut_shapes = [] + for case_thickness, height, width, center_point in zip( + [10, 15, 15, 10], [20, 50, 50, 20], [20, 50, 50, 20], + [(500, 300), (560, 100), (560, -100), (500, -300)] + ): + extra_cut_shapes.append( + paramak.poloidal_field_coil( + height=height, width=width, center_point=center_point, rotation_angle=270 + ) + ) + extra_cut_shapes.append( + paramak.poloidal_field_coil_case( + coil_height=height, + coil_width=width, + casing_thickness=case_thickness, + rotation_angle=270, + center_point=center_point, + ) + ) + + result = paramak.spherical_tokamak_from_plasma( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + elongation=2, + triangularity=0.55, + rotation_angle=270, + extra_cut_shapes=extra_cut_shapes, + ) + + result.save(f"spherical_tokamak_from_plasma_with_pf_magnets.step") + + +Reactor with toroidal field coils +--------------------------------- + +- In a similar way to adding poloidal field coils one can also add toroidal field coils by making use of the extra_cut_shapes argument. +- All reactors support adding a sequence of CadQuery shapes (e.g. workplanes) to the reactor using the extra_cut_shapes argument +- This example adds TF coils to a spherical_tokamak_from_plasma reactor but and other reactor would also work. +- Also these are rectangle shaped TF coils but other shapes are also available. + + +.. cadquery:: + :gridsize: 0 + :select: result + :color: #00cd00 + :width: 100% + :height: 600px + + import paramak + + tf = paramak.toroidal_field_coil_rectangle( + horizontal_start_point = (10, 520), + vertical_mid_point = (600, 0), + thickness = 50, + distance = 40, + with_inner_leg = True, + azimuthal_placement_angles = [0, 30, 60, 90, 120, 150, 180], + ) + + result = paramak.spherical_tokamak_from_plasma( + radial_build=[ + (paramak.LayerType.GAP, 70), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + elongation=2.5, + rotation_angle=180, + triangularity=0.55, + extra_cut_shapes=[tf] + ).toCompound() + +.. code-block:: python + + import paramak + + tf = paramak.toroidal_field_coil_rectangle( + horizontal_start_point = (10, 520), + vertical_mid_point = (600, 0), + thickness = 50, + distance = 40, + with_inner_leg = True, + azimuthal_placement_angles = [0, 30, 60, 90, 120, 150, 180], + ) + + result = paramak.spherical_tokamak_from_plasma( + radial_build=[ + (paramak.LayerType.GAP, 70), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + elongation=2.5, + rotation_angle=180, + triangularity=0.55, + extra_cut_shapes=[tf] + ) + + result.save(f"spherical_tokamak_minimal.step") + + +Spherical tokamak with negative triangularity +--------------------------------------------- + +- The triangularity argument can be set to a negative value to make a plasma with a negative triangularity. +- This example makes a spherical tokamak with a negative but this would work on any reactor. + +.. cadquery:: + :gridsize: 0 + :select: result + :color: #00cd00 + :width: 100% + :height: 600px + + import paramak + + result = paramak.spherical_tokamak( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 40), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + vertical_build=[ + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 80), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 700), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 40), + (paramak.LayerType.SOLID, 15), + ], + rotation_angle=180, + triangularity=-0.55, + ).toCompound() + +.. code-block:: python + + import paramak + + result = paramak.spherical_tokamak( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + vertical_build=[ + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 80), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 700), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 40), + (paramak.LayerType.SOLID, 15), + ], + rotation_angle=180, + triangularity=-0.55, + ) + result.save(f"spherical_tokamak_minimal.step") diff --git a/docs/usage_tokamak.rst b/docs/usage_tokamak.rst new file mode 100644 index 00000000..391042cb --- /dev/null +++ b/docs/usage_tokamak.rst @@ -0,0 +1,417 @@ +Usage +===== + +There are two main reactors to choose from, Tokamak and Spherical Tokamak. +These can be built with: +- A radial and vertical build +- A radial build and plasma elongation. + +The former gives the user more control of the size of components allowing reactor blankets to vary both radially and vertically. +The later allows reactors to be built with a minimal number of parameters. +In all cases it is possible to add additional components such as divertors, poloidal and toroidal magnets and any self made geometry as a CadQuery Workplane. +The reactors can be varied in terms of their radial build, vertical build, elongation and triangularity which gives a lot of variability. +These examples show how to make various reactors with and without different components, each example is minimal and aims to show a single feature, you will have to combine examples to make a complete model. + + + +.. toctree:: + :maxdepth: 3 + + usage_tokamak + usage_spherical_tokamak + + + +Tokamak from plasma +------------------- + +- The tokamak_from_plasma function provides a parametric tokamak shaped reactor. +- This is characterized by a continuous blanket that goes around the inboard and outboard sides of the plasma. +- This reactor requires few arguments to create as it keeps the vertical build of the blanket layers the same thickness as the radial build. + +.. cadquery:: + :gridsize: 0 + :select: result + :color: #00cd00 + :width: 100% + :height: 600px + + import paramak + result = paramak.tokamak_from_plasma( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 30), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 10), + ], + elongation=2, + triangularity=0.55, + rotation_angle=90, + ).toCompound() + + +.. code-block:: python + + import paramak + result = paramak.tokamak_from_plasma( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 30), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 10), + ], + elongation=2, + triangularity=0.55, + rotation_angle=90, + ) + + +Tokamak +------- + +- The spherical_tokamak function provides a parametric tokamak shaped reactor. +- This is characterized by a blanket that only goes around the outboard sides of the plasma. +- This reactor allows for a separate vertical and radial build which allows different thickness layers in the blanket. + +.. cadquery:: + :gridsize: 0 + :select: result + :color: #00cd00 + :width: 100% + :height: 600px + + import paramak + + result = paramak.tokamak( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 30), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 10), + ], + vertical_build=[ + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 80), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 700), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 40), + (paramak.LayerType.SOLID, 15), + ], + triangularity=0.55, + rotation_angle=180, + ).toCompound() + +.. code-block:: python + + import paramak + + result = paramak.tokamak( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 30), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 10), + ], + vertical_build=[ + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 80), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 700), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 40), + (paramak.LayerType.SOLID, 15), + ], + triangularity=0.55, + rotation_angle=180, + ) + + result.save(f"tokamak_minimal.step") + + + +Tokamak with negative triangularity +----------------------------------- + +- The triangularity argument can be set to a negative value to make a plasma with a negative triangularity. +- This example makes a tokamak with a negative but this would work on any reactor. + +.. cadquery:: + :gridsize: 0 + :select: result + :color: #00cd00 + :width: 100% + :height: 600px + + import paramak + + result = paramak.tokamak( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 30), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 10), + ], + vertical_build=[ + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 80), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 700), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 40), + (paramak.LayerType.SOLID, 15), + ], + triangularity=-0.55, + rotation_angle=180, + ).toCompound() + +.. code-block:: python + + import paramak + + result = paramak.tokamak( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 30), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 120), + (paramak.LayerType.SOLID, 10), + ], + vertical_build=[ + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 80), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 700), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 40), + (paramak.LayerType.SOLID, 15), + ], + triangularity=-0.55, + rotation_angle=180, + ) + + result.save(f"tokamak_minimal.step") + + +Tokamak with several customizations +----------------------------------- + +- Combining many of the examples together to produce a Tokamak + with extra blanket layers, a lower divertor, PF and TF coils. + +.. cadquery:: + :gridsize: 0 + :select: result + :color: #00cd00 + :width: 100% + :height: 600px + + import paramak + from cadquery import vis, Workplane + + # makes a rectangle that overlaps the lower blanket under the plasma + # the intersection of this and the layers will form the lower divertor + points = [(300, -700), (300, 0), (400, 0), (400, -700)] + divertor_lower = Workplane('XZ', origin=(0,0,0)).polyline(points).close().revolve(180) + + # creates a toroidal + tf = paramak.toroidal_field_coil_rectangle( + horizontal_start_point = (10, 520), + vertical_mid_point = (860, 0), + thickness = 50, + distance = 40, + with_inner_leg = True, + azimuthal_placement_angles = [0, 30, 60, 90, 120, 150, 180], + ) + + extra_cut_shapes = [tf] + + # creates pf coil + for case_thickness, height, width, center_point in zip( + [10, 15, 15, 10], [20, 50, 50, 20], [20, 50, 50, 20], + [(730, 370), (810, 235), (810, -235), (730, -370)] + ): + extra_cut_shapes.append( + paramak.poloidal_field_coil( + height=height, width=width, center_point=center_point, rotation_angle=180 + ) + ) + extra_cut_shapes.append( + paramak.poloidal_field_coil_case( + coil_height=height, + coil_width=width, + casing_thickness=case_thickness, + rotation_angle=180, + center_point=center_point, + ) + ) + + result = paramak.tokamak( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 30), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + vertical_build=[ + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 650), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + ], + triangularity=0.55, + rotation_angle=180, + extra_cut_shapes=extra_cut_shapes, + extra_intersect_shapes=[divertor_lower] + ).toCompound() + +.. code-block:: python + + import paramak + from cadquery import Workplane + + # makes a rectangle that overlaps the lower blanket under the plasma + # the intersection of this and the layers will form the lower divertor + points = [(300, -700), (300, 0), (400, 0), (400, -700)] + divertor_lower = Workplane('XZ', origin=(0,0,0)).polyline(points).close().revolve(180) + + # creates a toroidal + tf = paramak.toroidal_field_coil_rectangle( + horizontal_start_point = (10, 520), + vertical_mid_point = (860, 0), + thickness = 50, + distance = 40, + with_inner_leg = True, + azimuthal_placement_angles = [0, 30, 60, 90, 120, 150, 180], + ) + + extra_cut_shapes = [tf] + + # creates pf coil + for case_thickness, height, width, center_point in zip( + [10, 15, 15, 10], [20, 50, 50, 20], [20, 50, 50, 20], + [(730, 370), (810, 235), (810, -235), (730, -370)] + ): + extra_cut_shapes.append( + paramak.poloidal_field_coil( + height=height, width=width, center_point=center_point, rotation_angle=180 + ) + ) + extra_cut_shapes.append( + paramak.poloidal_field_coil_case( + coil_height=height, + coil_width=width, + casing_thickness=case_thickness, + rotation_angle=180, + center_point=center_point, + ) + ) + + my_reactor = paramak.tokamak( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 30), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + vertical_build=[ + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 650), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + ], + triangularity=0.55, + rotation_angle=180, + extra_cut_shapes=extra_cut_shapes, + extra_intersect_shapes=[divertor_lower] + ) + my_reactor.save(f"tokamak_with_customizations.step") \ No newline at end of file diff --git a/examples/run_all_examples.sh b/examples/run_all_examples.sh new file mode 100644 index 00000000..180e7bff --- /dev/null +++ b/examples/run_all_examples.sh @@ -0,0 +1,13 @@ +python examples/example_util_functions.py +python examples/plasma.py +python examples/spherical_tokamak_from_plasma_minimal.py +python examples/spherical_tokamak_from_plasma_with_divertor.py +python examples/spherical_tokamak_from_plasma_with_pf_magnets_and_divertors.py +python examples/spherical_tokamak_from_plasma_with_pf_magnets.py +python examples/spherical_tokamak_from_plasma_with_tf_magnets.py +python examples/spherical_tokamak_minimal.py +python examples/tokamak_from_plasma_minimal.py +python examples/tokamak_from_plasma_with_divertor.py +python examples/tokamak_minimal.py +python examples/tokamak_with_pf_magnets.py +python examples/tokamak_with_pf_tf_magnets_divertor.py diff --git a/examples/spherical_tokamak_from_plasma_minimal.py b/examples/spherical_tokamak_from_plasma_minimal.py index a821a25e..a3b23ac0 100644 --- a/examples/spherical_tokamak_from_plasma_minimal.py +++ b/examples/spherical_tokamak_from_plasma_minimal.py @@ -6,18 +6,16 @@ import paramak my_reactor = paramak.spherical_tokamak_from_plasma( - radial_builds=[ - [ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ] + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), ], elongation=2, triangularity=0.55, diff --git a/examples/spherical_tokamak_from_plasma_with_divertor.py b/examples/spherical_tokamak_from_plasma_with_divertor.py index 94e7eb07..09b45a96 100644 --- a/examples/spherical_tokamak_from_plasma_with_divertor.py +++ b/examples/spherical_tokamak_from_plasma_with_divertor.py @@ -4,31 +4,35 @@ from example_util_functions import transport_particles_on_h5m_geometry import paramak +from cadquery import Workplane, vis + + +# makes a rectangle that overlaps the lower blanket under the plasma +# the intersection of this and the layers will form the lower divertor +points = [(150, -700), (150, 0), (270, 0), (270, -700)] +divertor_lower = Workplane('XZ', origin=(0,0,0)).polyline(points).close().revolve(180) my_reactor = paramak.spherical_tokamak_from_plasma( - radial_builds=[ - [ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ], - [(paramak.LayerType.GAP, 75), ("lower_divertor", 100)], # this divertor connects to the center column - [(paramak.LayerType.GAP, 120), ("upper_divertor", 140)], # this divertor has some blanket between the center colum and itself + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), ], elongation=2, triangularity=0.55, rotation_angle=180, + extra_intersect_shapes=[divertor_lower] ) my_reactor.save("spherical_tokamak_from_plasma_with_divertor.step") print('written spherical_tokamak_from_plasma_with_divertor.step') - +# vis.show(my_reactor) # my_model = CadToDagmc() # material_tags = ["mat1"] * 21 # the two divertors split the 3 blanket layers into 9 and the magnets also splt the blanket. # my_model.add_cadquery_object(cadquery_object=my_reactor, material_tags=material_tags) diff --git a/examples/spherical_tokamak_from_plasma_with_pf_magnets.py b/examples/spherical_tokamak_from_plasma_with_pf_magnets.py index f4db3c8f..2f93d6ae 100644 --- a/examples/spherical_tokamak_from_plasma_with_pf_magnets.py +++ b/examples/spherical_tokamak_from_plasma_with_pf_magnets.py @@ -3,17 +3,17 @@ import paramak -add_extra_cut_shapes = [] +extra_cut_shapes = [] for case_thickness, height, width, center_point in zip( [10, 15, 15, 10], [20, 50, 50, 20], [20, 50, 50, 20], [(500, 300), (560, 100), (560, -100), (500, -300)] ): - add_extra_cut_shapes.append( + extra_cut_shapes.append( paramak.poloidal_field_coil( height=height, width=width, center_point=center_point, rotation_angle=270 ) ) - add_extra_cut_shapes.append( + extra_cut_shapes.append( paramak.poloidal_field_coil_case( coil_height=height, coil_width=width, @@ -25,7 +25,7 @@ my_reactor = paramak.spherical_tokamak_from_plasma( - radial_builds=[ + radial_build=[ (paramak.LayerType.GAP, 10), (paramak.LayerType.SOLID, 50), (paramak.LayerType.SOLID, 15), @@ -39,7 +39,7 @@ elongation=2, triangularity=0.55, rotation_angle=270, - add_extra_cut_shapes=add_extra_cut_shapes, + extra_cut_shapes=extra_cut_shapes, ) my_reactor.save(f"spherical_tokamak_from_plasma_with_pf_magnets.step") diff --git a/examples/spherical_tokamak_from_plasma_with_pf_magnets_and_divertors.py b/examples/spherical_tokamak_from_plasma_with_pf_magnets_and_divertors.py index 4343321a..78161fb5 100644 --- a/examples/spherical_tokamak_from_plasma_with_pf_magnets_and_divertors.py +++ b/examples/spherical_tokamak_from_plasma_with_pf_magnets_and_divertors.py @@ -25,26 +25,24 @@ ) ) - +#TODO +# [(paramak.LayerType.GAP, 75), ("lower_divertor", 100)], my_reactor = paramak.spherical_tokamak_from_plasma( - radial_builds=[ - [ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ], - [(paramak.LayerType.GAP, 75), ("lower_divertor", 100)], + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), ], elongation=2, triangularity=0.55, rotation_angle=rotation_angle, - add_extra_cut_shapes=poloidal_field_coils, + extra_cut_shapes=poloidal_field_coils, ) my_reactor.save(f"spherical_tokamak_from_plasma_with_pf_magnets_and_divertor.step") diff --git a/examples/spherical_tokamak_from_plasma_with_tf_magnets.py b/examples/spherical_tokamak_from_plasma_with_tf_magnets.py index 4297e6c6..42595d97 100644 --- a/examples/spherical_tokamak_from_plasma_with_tf_magnets.py +++ b/examples/spherical_tokamak_from_plasma_with_tf_magnets.py @@ -15,7 +15,7 @@ ) result = paramak.spherical_tokamak_from_plasma( - radial_builds=[ + radial_build=[ (paramak.LayerType.GAP, 70), (paramak.LayerType.SOLID, 10), (paramak.LayerType.SOLID, 10), @@ -29,7 +29,7 @@ elongation=2.5, rotation_angle=180, triangularity=0.55, - add_extra_cut_shapes=[tf] + extra_cut_shapes=[tf] ) result.save(f"spherical_tokamak_minimal.step") diff --git a/examples/spherical_tokamak_minimal.py b/examples/spherical_tokamak_minimal.py index 95ba4b71..a5aad263 100644 --- a/examples/spherical_tokamak_minimal.py +++ b/examples/spherical_tokamak_minimal.py @@ -6,18 +6,16 @@ import paramak my_reactor = paramak.spherical_tokamak( - radial_builds=[ - [ - (paramak.LayerType.GAP, 10), - (paramak.LayerType.SOLID, 50), - (paramak.LayerType.SOLID, 15), - (paramak.LayerType.GAP, 50), - (paramak.LayerType.PLASMA, 300), - (paramak.LayerType.GAP, 60), - (paramak.LayerType.SOLID, 40), - (paramak.LayerType.SOLID, 60), - (paramak.LayerType.SOLID, 10), - ] + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 15), + (paramak.LayerType.GAP, 50), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 40), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), ], vertical_build=[ (paramak.LayerType.SOLID, 15), diff --git a/examples/tokamak_from_plasma_minimal.py b/examples/tokamak_from_plasma_minimal.py index 4c81c745..f9e0cf52 100644 --- a/examples/tokamak_from_plasma_minimal.py +++ b/examples/tokamak_from_plasma_minimal.py @@ -4,7 +4,7 @@ import paramak my_reactor = paramak.tokamak_from_plasma( - radial_builds=[ + radial_build=[ (paramak.LayerType.GAP, 10), (paramak.LayerType.SOLID, 30), (paramak.LayerType.SOLID, 50), diff --git a/examples/tokamak_from_plasma_with_divertor.py b/examples/tokamak_from_plasma_with_divertor.py index 359b2f44..bf7e0065 100644 --- a/examples/tokamak_from_plasma_with_divertor.py +++ b/examples/tokamak_from_plasma_with_divertor.py @@ -1,10 +1,17 @@ from example_util_functions import transport_particles_on_h5m_geometry - +from paramak.utils import create_wire_workplane_from_points import paramak +from cadquery import vis, Workplane + +# makes a rectangle that overlaps the lower blanket under the plasma +# the intersection of this and the layers will form the lower divertor +points = [(300, -700), (300, 0), (400, 0), (400, -700)] +divertor_lower = Workplane('XZ', origin=(0,0,0)).polyline(points).close().revolve(180) + my_reactor = paramak.tokamak_from_plasma( - radial_builds=[ + radial_build=[ [ (paramak.LayerType.GAP, 10), (paramak.LayerType.SOLID, 30), @@ -19,14 +26,16 @@ (paramak.LayerType.SOLID, 120), (paramak.LayerType.SOLID, 10), ], - [(paramak.LayerType.GAP, 300), ("lower_divertor", 150)], + # [(paramak.LayerType.GAP, 300), ("lower_divertor", 150)], ], elongation=2, triangularity=0.55, rotation_angle=180, + extra_intersect_shapes=[divertor_lower] ) my_reactor.save(f"tokamak_with_divertor.step") print(f"Saved as tokamak_with_divertor.step") +# vis.show(my_reactor) # from cad_to_dagmc import CadToDagmc # my_model = CadToDagmc() diff --git a/examples/tokamak_minimal.py b/examples/tokamak_minimal.py index c8c04eb6..b24ae32a 100644 --- a/examples/tokamak_minimal.py +++ b/examples/tokamak_minimal.py @@ -4,7 +4,7 @@ import paramak my_reactor = paramak.tokamak( - radial_builds=[ + radial_build=[ (paramak.LayerType.GAP, 10), (paramak.LayerType.SOLID, 30), (paramak.LayerType.SOLID, 50), diff --git a/examples/tokamak_with_pf_magnets.py b/examples/tokamak_with_pf_magnets.py index 0fcb4f69..9c0c84c1 100644 --- a/examples/tokamak_with_pf_magnets.py +++ b/examples/tokamak_with_pf_magnets.py @@ -3,17 +3,17 @@ import paramak -add_extra_cut_shapes = [] +extra_cut_shapes = [] for case_thickness, height, width, center_point in zip( [10, 15, 15, 10], [20, 50, 50, 20], [20, 50, 50, 20], [(700, 300), (800, 100), (800, -100), (700, -300)] ): - add_extra_cut_shapes.append( + extra_cut_shapes.append( paramak.poloidal_field_coil( height=height, width=width, center_point=center_point, rotation_angle=180 ) ) - add_extra_cut_shapes.append( + extra_cut_shapes.append( paramak.poloidal_field_coil_case( coil_height=height, coil_width=width, @@ -24,7 +24,7 @@ ) my_reactor = paramak.tokamak( - radial_builds=[ + radial_build=[ (paramak.LayerType.GAP, 10), (paramak.LayerType.SOLID, 30), (paramak.LayerType.SOLID, 50), @@ -51,7 +51,7 @@ ], triangularity=0.55, rotation_angle=180, - add_extra_cut_shapes=add_extra_cut_shapes, + extra_cut_shapes=extra_cut_shapes, ) my_reactor.save(f"tokamak_minimal.step") diff --git a/examples/tokamak_with_pf_tf_magnets_divertor.py b/examples/tokamak_with_pf_tf_magnets_divertor.py new file mode 100644 index 00000000..1f87440d --- /dev/null +++ b/examples/tokamak_with_pf_tf_magnets_divertor.py @@ -0,0 +1,96 @@ + +from example_util_functions import transport_particles_on_h5m_geometry + +import paramak +from cadquery import vis, Workplane + +# makes a rectangle that overlaps the lower blanket under the plasma +# the intersection of this and the layers will form the lower divertor +points = [(300, -700), (300, 0), (400, 0), (400, -700)] +divertor_lower = Workplane('XZ', origin=(0,0,0)).polyline(points).close().revolve(180) + +# creates a toroidal +tf = paramak.toroidal_field_coil_rectangle( + horizontal_start_point = (10, 520), + vertical_mid_point = (860, 0), + thickness = 50, + distance = 40, + with_inner_leg = True, + azimuthal_placement_angles = [0, 30, 60, 90, 120, 150, 180], +) + +extra_cut_shapes = [tf] + +# creates pf coil +for case_thickness, height, width, center_point in zip( + [10, 15, 15, 10], [20, 50, 50, 20], [20, 50, 50, 20], + [(730, 370), (810, 235), (810, -235), (730, -370)] +): + extra_cut_shapes.append( + paramak.poloidal_field_coil( + height=height, width=width, center_point=center_point, rotation_angle=180 + ) + ) + extra_cut_shapes.append( + paramak.poloidal_field_coil_case( + coil_height=height, + coil_width=width, + casing_thickness=case_thickness, + rotation_angle=180, + center_point=center_point, + ) + ) + +my_reactor = paramak.tokamak( + radial_build=[ + (paramak.LayerType.GAP, 10), + (paramak.LayerType.SOLID, 30), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 300), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 60), + (paramak.LayerType.SOLID, 10), + ], + vertical_build=[ + (paramak.LayerType.SOLID, 10), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.PLASMA, 650), + (paramak.LayerType.GAP, 60), + (paramak.LayerType.SOLID, 20), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 50), + (paramak.LayerType.SOLID, 10), + ], + triangularity=0.55, + rotation_angle=180, + extra_cut_shapes=extra_cut_shapes, + extra_intersect_shapes=[divertor_lower] +) +my_reactor.save(f"tokamak_with_divertor.step") +print(f"Saved as tokamak_with_divertor.step") +# vis.show(my_reactor) + +# from cad_to_dagmc import CadToDagmc +# my_model = CadToDagmc() +# material_tags = ["mat1"] * 6 # as inner and outer layers are one solid there are only 6 solids in model +# my_model.add_cadquery_object(cadquery_object=my_reactor, material_tags=material_tags) +# my_model.export_dagmc_h5m_file(min_mesh_size=3.0, max_mesh_size=20.0) + +# h5m_filename = "dagmc.h5m" +# flux = transport_particles_on_h5m_geometry( +# h5m_filename=h5m_filename, +# material_tags=material_tags, +# nuclides=["H1"] * len(material_tags), +# cross_sections_xml="tests/cross_sections.xml", +# ) +# assert flux > 0.0 diff --git a/src/paramak/assemblies/spherical_tokamak.py b/src/paramak/assemblies/spherical_tokamak.py index f3a5ed0a..9103b326 100644 --- a/src/paramak/assemblies/spherical_tokamak.py +++ b/src/paramak/assemblies/spherical_tokamak.py @@ -1,11 +1,8 @@ from typing import Optional, Sequence, Tuple, Union import cadquery as cq -import numpy as np from ..utils import ( - build_divertor_modify_blanket, - extract_radial_builds, get_plasma_index, get_plasma_value, sum_up_to_gap_before_plasma, @@ -106,11 +103,12 @@ def create_center_column_shield_cylinders(radial_build, vertical_build, rotation def spherical_tokamak_from_plasma( - radial_builds: Union[Sequence[Sequence[Tuple[str, float]]], Sequence[Tuple[str, float]]], + radial_build: Sequence[Tuple[LayerType, float]], elongation: float = 2.0, triangularity: float = 0.55, rotation_angle: float = 180.0, - add_extra_cut_shapes: Sequence[cq.Workplane] = [], + extra_cut_shapes: Sequence[cq.Workplane] = [], + extra_intersect_shapes: Sequence[cq.Workplane] = [], ): """_summary_ @@ -119,16 +117,14 @@ def spherical_tokamak_from_plasma( elongation (float, optional): _description_. Defaults to 2.0. triangularity (float, optional): _description_. Defaults to 0.55. rotation_angle (Optional[str], optional): _description_. Defaults to 180.0. - add_extra_cut_shapes (Sequence, optional): _description_. Defaults to []. + extra_cut_shapes (Sequence, optional): _description_. Defaults to []. Returns: _type_: _description_ """ - plasma_radial_build, _ = extract_radial_builds(radial_builds) - - inner_equatorial_point = sum_up_to_plasma(plasma_radial_build) - plasma_radial_thickness = get_plasma_value(plasma_radial_build) + inner_equatorial_point = sum_up_to_plasma(radial_build) + plasma_radial_thickness = get_plasma_value(radial_build) outer_equatorial_point = inner_equatorial_point + plasma_radial_thickness # sets major radius and minor radius from equatorial_points to allow a @@ -138,28 +134,30 @@ def spherical_tokamak_from_plasma( minor_radius = major_radius - inner_equatorial_point # make vertical build from outer radial build - pi = get_plasma_index(plasma_radial_build) - upper_vertical_build = plasma_radial_build[pi:] + pi = get_plasma_index(radial_build) + upper_vertical_build = radial_build[pi:] plasma_height = 2 * minor_radius * elongation # slice opperation reverses the list and removes the last value to avoid two plasmas vertical_build = upper_vertical_build[::-1][:-1] + [(LayerType.PLASMA, plasma_height)] + upper_vertical_build[1:] return spherical_tokamak( - radial_builds=radial_builds, + radial_build=radial_build, vertical_build=vertical_build, triangularity=triangularity, rotation_angle=rotation_angle, - add_extra_cut_shapes=add_extra_cut_shapes, + extra_cut_shapes=extra_cut_shapes, + extra_intersect_shapes=extra_intersect_shapes ) def spherical_tokamak( - radial_builds: Union[Sequence[Sequence[Tuple[str, float]]], Sequence[Tuple[str, float]]], + radial_build: Union[Sequence[Sequence[Tuple[str, float]]], Sequence[Tuple[str, float]]], vertical_build: Sequence[Tuple[str, float]], triangularity: float = 0.55, rotation_angle: Optional[str] = 180.0, - add_extra_cut_shapes: Sequence[cq.Workplane] = [], + extra_cut_shapes: Sequence[cq.Workplane] = [], + extra_intersect_shapes: Sequence[cq.Workplane] = [], ): """_summary_ @@ -169,16 +167,14 @@ def spherical_tokamak( elongation (float, optional): _description_. Defaults to 2.0. triangularity (float, optional): _description_. Defaults to 0.55. rotation_angle (Optional[str], optional): _description_. Defaults to 180.0. - add_extra_cut_shapes (Sequence, optional): _description_. Defaults to []. + extra_cut_shapes (Sequence, optional): _description_. Defaults to []. Returns: _type_: _description_ """ - plasma_radial_build, divertor_radial_builds = extract_radial_builds(radial_builds) - - inner_equatorial_point = sum_up_to_plasma(plasma_radial_build) - plasma_radial_thickness = get_plasma_value(plasma_radial_build) + inner_equatorial_point = sum_up_to_plasma(radial_build) + plasma_radial_thickness = get_plasma_value(radial_build) plasma_vertical_thickness = get_plasma_value(vertical_build) outer_equatorial_point = inner_equatorial_point + plasma_radial_thickness @@ -201,20 +197,20 @@ def spherical_tokamak( ) inner_radial_build = create_center_column_shield_cylinders( - radial_build=plasma_radial_build, + radial_build=radial_build, vertical_build=vertical_build, rotation_angle=rotation_angle, ) blanket_cutting_cylinder = center_column_shield_cylinder( inner_radius=0, - thickness=sum_up_to_gap_before_plasma(plasma_radial_build), + thickness=sum_up_to_gap_before_plasma(radial_build), rotation_angle=360, height=2 * blanket_rear_wall_end_height, ) blanket_layers = create_blanket_layers_after_plasma( - radial_build=plasma_radial_build, + radial_build=radial_build, vertical_build=vertical_build, minor_radius=minor_radius, major_radius=major_radius, @@ -224,30 +220,44 @@ def spherical_tokamak( center_column=blanket_cutting_cylinder, ) - divertor_layers, blanket_layers = build_divertor_modify_blanket( - blanket_layers, divertor_radial_builds, blanket_rear_wall_end_height, rotation_angle - ) my_assembly = cq.Assembly() - for i, entry in enumerate(add_extra_cut_shapes): + for i, entry in enumerate(extra_cut_shapes): if isinstance(entry, cq.Workplane): my_assembly.add(entry, name=f"add_extra_cut_shape_{i+1}") else: - raise ValueError(f"add_extra_cut_shapes should only contain cadquery Workplanes, not {type(entry)}") - - if len(add_extra_cut_shapes) == 0: + raise ValueError(f"extra_cut_shapes should only contain cadquery Workplanes, not {type(entry)}") + + # builds up the intersect shapes + intersect_shapes_to_cut = [] + if len(extra_intersect_shapes)>0: + all_shapes = [] + for shape in inner_radial_build + blanket_layers: + all_shapes.extend(shape) + + # makes a union of the the radial build to use as a base for the intersect shapes + reactor_compound=inner_radial_build[0] + for i, entry in enumerate(inner_radial_build[1:] + blanket_layers): + reactor_compound = reactor_compound.union(entry) + + # adds the extra intersect shapes to the assembly + for i, entry in enumerate(extra_intersect_shapes): + reactor_entry_intersection = entry.intersect(reactor_compound) + intersect_shapes_to_cut.append(reactor_entry_intersection) + my_assembly.add(reactor_entry_intersection, name=f"extra_intersect_shapes_{i+1}") + + # builds just the core if there are no extra parts + if len(extra_cut_shapes) == 0 and len(intersect_shapes_to_cut) == 0: for i, entry in enumerate(inner_radial_build): my_assembly.add(entry, name=f"inboard_layer_{i+1})") for i, entry in enumerate(blanket_layers): my_assembly.add(entry, name=f"outboard_layer_{i+1})") - for i, entry in enumerate(divertor_layers): - my_assembly.add(entry, name=f"{entry.name})") # gets upper or lower name else: shapes_and_components = [] - for i, entry in enumerate(inner_radial_build + blanket_layers + divertor_layers): - for cutter in add_extra_cut_shapes: + for i, entry in enumerate(inner_radial_build + blanket_layers): + for cutter in extra_cut_shapes + extra_intersect_shapes: entry = entry.cut(cutter) # TODO use something like this to return a list of material tags for the solids in order, as some solids get split into multiple # for subentry in entry.objects: diff --git a/src/paramak/assemblies/tokamak.py b/src/paramak/assemblies/tokamak.py index 6fd46391..0a778c43 100644 --- a/src/paramak/assemblies/tokamak.py +++ b/src/paramak/assemblies/tokamak.py @@ -2,7 +2,7 @@ import cadquery as cq -from ..utils import build_divertor_modify_blanket, extract_radial_builds, get_plasma_index, sum_after_plasma, LayerType +from ..utils import get_plasma_index, LayerType from ..workplanes.blanket_from_plasma import blanket_from_plasma from ..workplanes.center_column_shield_cylinder import center_column_shield_cylinder from ..workplanes.plasma_simplified import plasma_simplified @@ -157,17 +157,16 @@ def create_layers_from_plasma( return layers def tokamak_from_plasma( - radial_builds: Union[Sequence[Sequence[Tuple[str, float]]], Sequence[Tuple[str, float]]], + radial_build: Sequence[Tuple[LayerType, float]], elongation: float = 2.0, triangularity: float = 0.55, rotation_angle: float = 180.0, - add_extra_cut_shapes: Sequence[cq.Workplane] = [], + extra_cut_shapes: Sequence[cq.Workplane] = [], + extra_intersect_shapes: Sequence[cq.Workplane] = [], ): - - plasma_radial_build, _ = extract_radial_builds(radial_builds) - inner_equatorial_point = sum_up_to_plasma(plasma_radial_build) - plasma_radial_thickness = get_plasma_value(plasma_radial_build) + inner_equatorial_point = sum_up_to_plasma(radial_build) + plasma_radial_thickness = get_plasma_value(radial_build) outer_equatorial_point = inner_equatorial_point + plasma_radial_thickness # sets major radius and minor radius from equatorial_points to allow a @@ -177,46 +176,47 @@ def tokamak_from_plasma( minor_radius = major_radius - inner_equatorial_point # make vertical build from outer radial build - pi = get_plasma_index(plasma_radial_build) - upper_vertical_build = plasma_radial_build[pi:] + pi = get_plasma_index(radial_build) + upper_vertical_build = radial_build[pi:] plasma_height = 2 * minor_radius * elongation # slice opperation reverses the list and removes the last value to avoid two plasmas vertical_build = upper_vertical_build[::-1][:-1] + [(LayerType.PLASMA, plasma_height)] + upper_vertical_build[1:] return tokamak( - radial_builds=radial_builds, + radial_build=radial_build, vertical_build=vertical_build, triangularity=triangularity, rotation_angle=rotation_angle, - add_extra_cut_shapes=add_extra_cut_shapes, + extra_cut_shapes=extra_cut_shapes, + extra_intersect_shapes=extra_intersect_shapes, ) def tokamak( - radial_builds: Union[Sequence[Sequence[Tuple[str, float]]], Sequence[Tuple[str, float]]], + radial_build: Union[Sequence[Sequence[Tuple[str, float]]], Sequence[Tuple[str, float]]], vertical_build: Sequence[Tuple[str, float]], triangularity: float = 0.55, rotation_angle: float = 180.0, - add_extra_cut_shapes: Sequence[cq.Workplane] = [], + extra_cut_shapes: Sequence[cq.Workplane] = [], + extra_intersect_shapes: Sequence[cq.Workplane] = [], ): """ Creates a tokamak fusion reactor from a radial build and plasma parameters. Args: - radial_builds (Sequence[tuple[str, float]]): A list of tuples containing the radial build of the reactor. - elongation (float, optional): The elongation of the plasma. Defaults to 2.0. - triangularity (float, optional): The triangularity of the plasma. Defaults to 0.55. - rotation_angle (float, optional): The rotation angle of the plasma. Defaults to 180.0. - add_extra_cut_shapes (Sequence, optional): A list of extra shapes to cut the reactor with. Defaults to []. + radial_build: A list of tuples containing the radial build of the reactor. + elongation: The elongation of the plasma. Defaults to 2.0. + triangularity: The triangularity of the plasma. Defaults to 0.55. + rotation_angle: The rotation angle of the plasma. Defaults to 180.0. + extra_cut_shapes: A list of extra shapes to cut the reactor with. Defaults to []. + extra_intersect_shapes: A list of extra shapes to intersect the reactor with. Defaults to []. Returns: CadQuery.Assembly: A CadQuery Assembly object representing the tokamak fusion reactor. """ - plasma_radial_build, divertor_radial_builds = extract_radial_builds(radial_builds) - - inner_equatorial_point = sum_up_to_plasma(plasma_radial_build) - plasma_radial_thickness = get_plasma_value(plasma_radial_build) + inner_equatorial_point = sum_up_to_plasma(radial_build) + plasma_radial_thickness = get_plasma_value(radial_build) plasma_vertical_thickness = get_plasma_value(vertical_build) outer_equatorial_point = inner_equatorial_point + plasma_radial_thickness @@ -235,11 +235,11 @@ def tokamak( ) inner_radial_build = create_center_column_shield_cylinders( - plasma_radial_build, rotation_angle, blanket_rear_wall_end_height + radial_build, rotation_angle, blanket_rear_wall_end_height ) blanket_layers = create_layers_from_plasma( - radial_build=plasma_radial_build, + radial_build=radial_build, vertical_build=vertical_build, minor_radius=minor_radius, major_radius=major_radius, @@ -249,30 +249,42 @@ def tokamak( center_column=inner_radial_build[0], # blanket_cutting_cylinder, ) - divertor_layers, blanket_layers = build_divertor_modify_blanket( - blanket_layers, divertor_radial_builds, blanket_rear_wall_end_height, rotation_angle - ) - my_assembly = cq.Assembly() - for i, entry in enumerate(add_extra_cut_shapes): - + for i, entry in enumerate(extra_cut_shapes): if isinstance(entry, cq.Workplane): my_assembly.add(entry, name=f"add_extra_cut_shape_{i+1}") else: - raise ValueError(f"add_extra_cut_shapes should only contain cadquery Workplanes, not {type(entry)}") - - if len(add_extra_cut_shapes) == 0: + raise ValueError(f"extra_cut_shapes should only contain cadquery Workplanes, not {type(entry)}") + + # builds up the intersect shapes + intersect_shapes_to_cut = [] + if len(extra_intersect_shapes)>0: + all_shapes = [] + for shape in inner_radial_build + blanket_layers: + all_shapes.extend(shape) + + # makes a union of the the radial build to use as a base for the intersect shapes + reactor_compound=inner_radial_build[0] + for i, entry in enumerate(inner_radial_build[1:] + blanket_layers): + reactor_compound = reactor_compound.union(entry) + + # adds the extra intersect shapes to the assembly + for i, entry in enumerate(extra_intersect_shapes): + reactor_entry_intersection = entry.intersect(reactor_compound) + intersect_shapes_to_cut.append(reactor_entry_intersection) + my_assembly.add(reactor_entry_intersection, name=f"extra_intersect_shapes_{i+1}") + + # builds just the core if there are no extra parts + if len(extra_cut_shapes) == 0 and len(intersect_shapes_to_cut) == 0: for i, entry in enumerate(inner_radial_build): my_assembly.add(entry, name=f"inboard_layer_{i+1})") for i, entry in enumerate(blanket_layers): my_assembly.add(entry, name=f"outboard_layer_{i+1})") - for i, entry in enumerate(divertor_layers): - my_assembly.add(entry, name=f"{entry.name})") # gets upper or lower name else: shapes_and_components = [] - for i, entry in enumerate(inner_radial_build + blanket_layers + divertor_layers): - for cutter in add_extra_cut_shapes: + for i, entry in enumerate(inner_radial_build + blanket_layers): + for cutter in extra_cut_shapes + extra_intersect_shapes: entry = entry.cut(cutter) # TODO use something like this to return a list of material tags for the solids in order, as some solids get split into multiple # for subentry in entry.objects: diff --git a/src/paramak/utils.py b/src/paramak/utils.py index 19fc15e9..a06974ac 100644 --- a/src/paramak/utils.py +++ b/src/paramak/utils.py @@ -178,30 +178,6 @@ def create_divertor_envelope(divertor_radial_build, blanket_height, rotation_ang return divertor_solid -def build_divertor_modify_blanket(outer_layers, divertor_radial_builds, blanket_rear_wall_end_height, rotation_angle): - - divertor_layers = [] - for divertor_radial_build in divertor_radial_builds: - - divertor_solid = create_divertor_envelope(divertor_radial_build, blanket_rear_wall_end_height, rotation_angle) - - # finds the intersection of the blanket and divertor rectangle envelope. - outer_layer_envelope = outer_layers[0] - for outer_layer in outer_layers[1:]: - outer_layer_envelope = outer_layer_envelope.union(outer_layer) - - divertor_solid = divertor_solid.intersect(outer_layer_envelope) - # we reapply this name as it appears to get lost and we might need it when adding to assembly - divertor_solid.name = is_lower_or_upper_divertor(divertor_radial_build) - - # cuts the diverter out of the outer layers of the blanket - for i, layer in enumerate(outer_layers): - layer = layer.cut(divertor_solid) - outer_layers[i] = layer - divertor_layers.append(divertor_solid) - return divertor_layers, outer_layers - - def is_plasma_radial_build(radial_build): for entry in radial_build: # if entry == LayerType.PLASMA: @@ -211,28 +187,6 @@ def is_plasma_radial_build(radial_build): return False -def extract_radial_builds(radial_build): - # TODO more rubust method of finding if it is a single list of tupes or multiple lists - # only one radial build so it should be a plasma based radial build - divertor_radial_builds = [] - if isinstance(radial_build[0][0], LayerType) and ( - isinstance(radial_build[0][1], float) or isinstance(radial_build[0][1], int) - ): - plasma_radial_build = radial_build - else: - for entry in radial_build: - if is_plasma_radial_build(entry): - # TODO this assumes there is only one radial build, which needs to e checked - plasma_radial_build = entry - else: - divertor_radial_builds.append(entry) - - validate_plasma_radial_build(plasma_radial_build) - for divertor_radial_build in divertor_radial_builds: - validate_divertor_radial_build(divertor_radial_build) - return plasma_radial_build, divertor_radial_builds - - def validate_divertor_radial_build(radial_build): if len(radial_build) != 2: raise ValidationError( diff --git a/tests/test_assemblies/test_spherical_tokamak.py b/tests/test_assemblies/test_spherical_tokamak.py index 53c692c5..424026fb 100644 --- a/tests/test_assemblies/test_spherical_tokamak.py +++ b/tests/test_assemblies/test_spherical_tokamak.py @@ -33,7 +33,7 @@ def test_transport_with_magnets(rotation_angle): ) my_reactor = paramak.spherical_tokamak_from_plasma( - radial_builds=[ + radial_build=[ (paramak.LayerType.GAP, 10), (paramak.LayerType.SOLID, 50), (paramak.LayerType.SOLID, 15), @@ -48,7 +48,7 @@ def test_transport_with_magnets(rotation_angle): elongation=2, triangularity=0.55, rotation_angle=rotation_angle, - add_extra_cut_shapes=poloidal_field_coils, + extra_cut_shapes=poloidal_field_coils, ) my_reactor.save(f"spherical_tokamak_with_magnets_{rotation_angle}.step") assert Path(f"spherical_tokamak_with_magnets_{rotation_angle}.step").exists() @@ -70,7 +70,7 @@ def test_transport_with_magnets(rotation_angle): def test_transport_without_magnets(): reactor = paramak.spherical_tokamak_from_plasma( - radial_builds=[ + radial_build=[ (paramak.LayerType.GAP, 10), (paramak.LayerType.SOLID, 50), (paramak.LayerType.SOLID, 15),