Skip to content

Commit

Permalink
Merge pull request #239 from fusion-energy/develop
Browse files Browse the repository at this point in the history
develop to main merge
  • Loading branch information
shimwell authored Apr 17, 2022
2 parents 2772653 + 33250ac commit dd6aa1b
Show file tree
Hide file tree
Showing 40 changed files with 1,472 additions and 438 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/auto_format_pep8.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: black
name: auto_format_pep8

on:
push:
Expand All @@ -23,7 +23,7 @@ jobs:
- name: Install black
run: |
python -m pip install --upgrade pip
pip install black==22.1.0
pip install black==22.3.0
- name: Run black
run: |
black .
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/auto_lint.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: black
name: auto_lint

on:
push:
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/test_demos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ on:
branches:
- main
- develop
paths:
- "**.py"
- "**.ipynb"
- "**.yml"
- "**.cfg"
- "**.toml"
- "**.sh"

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

[![codecov](https://codecov.io/gh/fusion-energy/paramak/branch/main/graph/badge.svg)](https://codecov.io/gh/fusion-energy/paramak)

[![Code Grade](https://www.code-inspector.com/project/25342/score/svg)](https://frontend.code-inspector.com/public/project/25342/paramak/dashboard)
[![Code Grade](https://www.code-inspector.com/project/25342/status/svg)](https://frontend.code-inspector.com/public/project/25342/paramak/dashboard)
[![Code Grade](https://api.codiga.io/project/25342/score/svg)](https://app.codiga.io/public/project/25342/paramak/dashboard)
[![Code Grade](https://api.codiga.io/project/25342/status/svg)](https://app.codiga.io/public/project/25342/paramak/dashboard)


[![Documentation Status](https://readthedocs.org/projects/paramak/badge/?version=main)](https://paramak.readthedocs.io/en/main/?badge=main)
Expand All @@ -17,16 +17,19 @@
[![Upload Python Package](https://github.com/fusion-energy/paramak/actions/workflows/python-publish.yml/badge.svg)](https://github.com/fusion-energy/paramak/actions/workflows/python-publish.yml)
[![PyPI](https://img.shields.io/pypi/v/paramak?color=brightgreen&label=pypi&logo=grebrightgreenen&logoColor=green)](https://pypi.org/project/paramak/)

[![anaconda-publish](https://github.com/fusion-energy/paramak/actions/workflows/anaconda-publish.yml/badge.svg)](https://github.com/fusion-energy/paramak/actions/workflows/anaconda-publish.yml)
[![anaconda.org](https://anaconda.org/fusion-energy/paramak/badges/version.svg)](https://anaconda.org/fusion-energy/paramak)

[![docker-publish-release](https://github.com/fusion-energy/paramak/actions/workflows/docker_publish.yml/badge.svg)](https://github.com/fusion-energy/paramak/actions/workflows/docker_publish.yml)

[![DOI](https://zenodo.org/badge/269635577.svg)](https://zenodo.org/badge/latestdoi/269635577)

# Paramak

The Paramak python package allows rapid production of 3D CAD models of fusion
reactors. The purpose of the Paramak is to provide geometry for parametric
studies. The paramak can create geometry in standard CAD formats such as STP,
STL and Brep.
Paramak python package allows rapid production of 3D CAD models and neutronics
models of fusion reactors. The purpose of Paramak is to provide geometry for
parametric studies. Paramak can create geometry in standard CAD formats such as
STP, STL, BRep, HTML and DAGMC h5m.

:point_right: [Documentation](https://paramak.readthedocs.io)

Expand Down
6 changes: 3 additions & 3 deletions conda/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ requirements:
- python {{ python }}
- cadquery {{ cadquery }}
- mpmath
- plasmaboundaries
- plasmaboundaries >=0.1.8
- plotly
- brep_part_finder # [not win]
- brep_to_h5m # [not win]
- brep_part_finder >=0.4.1 # [not win]
- brep_to_h5m >=0.3.1 # [not win]
# - jupyter-cadquery not available on conda

test:
Expand Down
37 changes: 37 additions & 0 deletions docs/source/API-Reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1516,6 +1516,43 @@ CapsuleVacuumVessel()
:show-inheritance:


DishedVacuumVessel()
^^^^^^^^^^^^^^^^^^^^
.. cadquery::
:select: cadquery_object
:gridsize: 0

import paramak
my_component = paramak.DishedVacuumVessel(rotation_angle=180)

cadquery_object = my_component.solid

.. image:: https://user-images.githubusercontent.com/8583900/160503281-3aabf145-22b0-4953-bc4f-3f75a6696b5e.png

.. automodule:: paramak.parametric_components.dished_vacuum_vessel
:members:
:show-inheritance:

ConstantThicknessDome()
^^^^^^^^^^^^^^^^^^^^^^^
.. cadquery::
:select: cadquery_object
:gridsize: 0

import paramak
my_component = paramak.ConstantThicknessDome(rotation_angle=180)

cadquery_object = my_component.solid

.. image:: https://user-images.githubusercontent.com/8583900/160503286-71a6d771-1d47-476e-a0cf-85fb94c9389c.png

.. automodule:: paramak.parametric_components.constant_thickness_dome
:members:
:show-inheritance:




Other components
----------------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
# animation. Two animations are made, of of a 3D render and one of a wireframe
# line drawing.

import math
import os

# to run this example you will need all of the following packages installed
import matplotlib.pyplot as plt
import numpy as np
import paramak

Expand Down
16 changes: 15 additions & 1 deletion paramak/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,18 @@

from .shape import Shape
from .reactor import Reactor
from .utils import rotate, extend, distance_between_two_points, diff_between_angles
from .utils import (
rotate,
extend,
distance_between_two_points,
diff_between_angles,
find_center_point_of_circle,
angle_between_two_points_on_circle,
find_radius_of_circle,
export_solids_to_brep,
export_solids_to_dagmc_h5m,
get_center_of_bounding_box,
)
from .utils import EdgeLengthSelector, FaceAreaSelector

from .parametric_shapes.extruded_mixed_shape import ExtrudeMixedShape
Expand Down Expand Up @@ -113,7 +124,10 @@
ToroidalFieldCoilRectangleRoundCorners,
)

from .parametric_components.constant_thickness_dome import ConstantThicknessDome
from .parametric_components.vacuum_vessel import VacuumVessel

from .parametric_components.dished_vacuum_vessel import DishedVacuumVessel
from .parametric_components.vacuum_vessel_inner_leg import VacuumVesselInnerLeg
from .parametric_components.capsule_vacuum_vessel import CapsuleVacuumVessel
from .parametric_components.hollow_cube import HollowCube
Expand Down
2 changes: 1 addition & 1 deletion paramak/parametric_components/capsule_vacuum_vessel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class CapsuleVacuumVessel(RotateMixedShape):
"""A cylindrical vessel volume with constant thickness that has addition
spherical edges.
hemispherical head.
Arguments:
outer_start_point: the x,z coordinates of the outer bottom of the
Expand Down
210 changes: 210 additions & 0 deletions paramak/parametric_components/constant_thickness_dome.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import math
from paramak import RotateMixedShape, RotateStraightShape, Shape, CuttingWedge
import cadquery as cq


class ConstantThicknessDome(RotateMixedShape):
"""A cylindrical vessel volume with constant thickness with a simple dished
head. This style of tank head has no knuckle radius or straight flange. The
dished shape is made from a chord of a circle.
Arguments:
thickness: the radial thickness of the dome.
chord_center_height: the vertical position of the chord center
chord_width: the width of the chord base
chord_height: the height of the chord which is also distance between
the chord_center_height and the inner surface of the dome
upper_or_lower: Curves the dish with a positive or negative direction
to allow the upper section or lower section of vacuum vessel
domes to be made.
name: the name of the shape, used in the graph legend and as a
filename prefix when exporting.
"""

def __init__(
self,
thickness: float = 10,
chord_center_height: float = 0,
chord_width: float = 100,
chord_height: float = 20,
upper_or_lower: str = "upper",
name: str = "constant_thickness_dome",
**kwargs,
):

self.thickness = thickness
self.chord_center_height = chord_center_height
self.chord_width = chord_width
self.chord_height = chord_height
self.upper_or_lower = upper_or_lower
self.name = name

super().__init__(name=name, **kwargs)

@property
def chord_width(self):
return self._chord_width

@chord_width.setter
def chord_width(self, value):
if not isinstance(value, (float, int)):
raise ValueError("ConstantThicknessDome.chord_width must be a number. Not", value)
if value <= 0:
msg = f"ConstantThicknessDome.chord_width must be a positive number above 0. Not {value}"
raise ValueError(msg)
self._chord_width = value

@property
def chord_height(self):
return self._chord_height

@chord_height.setter
def chord_height(self, value):
if not isinstance(value, (float, int)):
raise ValueError("ConstantThicknessDome.chord_height must be a number. Not", value)
if value <= 0:
msg = f"ConstantThicknessDome.chord_height must be a positive number above 0. Not {value}"
raise ValueError(msg)
self._chord_height = value

@property
def thickness(self):
return self._thickness

@thickness.setter
def thickness(self, value):
if not isinstance(value, (float, int)):
msg = f"VacuumVessel.thickness must be a number. Not {value}"
raise ValueError(msg)
if value <= 0:
msg = f"VacuumVessel.thickness must be a positive number above 0. Not {value}"
raise ValueError(msg)
self._thickness = value

def find_points(self):
"""
Finds the XZ points joined by straight and circle connections that
describe the 2D profile of the vessel shape.
"""

# Note these points are not used in the normal way when constructing
# the solid
#
# 6 -
# | -
# 7 - -
# - -
# - 3
# - |
# cc 1 -- 2
# chord center
#
#
# cp
# center point
#
#
#
#
# cc 1 -- 2
# - |
# - 3
# - -
# 7 - -
# | -
# 6 -
# far side

if self.chord_height * 2 >= self.chord_width:
msg = "ConstantThicknessDome requires that the self.chord_width is at least 2 times as large as the chord height"
raise ValueError(msg)

radius_of_sphere = ((math.pow(self.chord_width, 2)) + (4.0 * math.pow(self.chord_height, 2))) / (
8 * self.chord_height
)

# TODO set to 0 for now, add ability to shift the center of the chord left and right
chord_center = (0, self.chord_center_height)

point_1 = (chord_center[0] + (self.chord_width / 2), chord_center[1], "straight")

if self.upper_or_lower == "upper":
center_point = (chord_center[0], chord_center[1] + self.chord_height - radius_of_sphere)
inner_tri_angle = math.atan((center_point[1] - chord_center[1]) / (self.chord_width / 2))
outer_tri_adj = math.cos(inner_tri_angle) * self.thickness
point_2 = (point_1[0] + self.thickness, point_1[1], "straight")
outer_tri_opp = math.sqrt(math.pow(self.thickness, 2) - math.pow(outer_tri_adj, 2))
point_7 = (chord_center[0], chord_center[1] + radius_of_sphere, "straight")
point_6 = (chord_center[0], chord_center[1] + radius_of_sphere + self.thickness, "straight")
self.far_side = (center_point[0], center_point[1] - (radius_of_sphere + self.thickness))
point_3 = (point_2[0], point_2[1] + outer_tri_opp, "straight")
elif self.upper_or_lower == "lower":
center_point = (chord_center[0], chord_center[1] - self.chord_height + radius_of_sphere)
inner_tri_angle = math.atan((center_point[1] - chord_center[1]) / (self.chord_width / 2))
outer_tri_adj = math.cos(inner_tri_angle) * self.thickness
point_2 = (point_1[0] + self.thickness, point_1[1], "straight")
outer_tri_opp = math.sqrt(math.pow(self.thickness, 2) - math.pow(outer_tri_adj, 2))
point_7 = (chord_center[0], chord_center[1] - radius_of_sphere, "straight")
point_6 = (chord_center[0], chord_center[1] - (radius_of_sphere + self.thickness), "straight")
self.far_side = (center_point[0], center_point[1] + radius_of_sphere + self.thickness)
point_3 = (point_2[0], point_2[1] - outer_tri_opp, "straight")
else:
msg = f'upper_or_lower should be either "upper" or "lower". Not {self.upper_or_lower}'
raise ValueError(msg)

self.points = [point_1, point_2, point_3, point_6, point_7]

def create_solid(self):
"""Creates a rotated 3d solid using points with circular edges.
Returns:
A CadQuery solid: A 3D solid volume
"""

radius_of_sphere = ((math.pow(self.chord_width, 2)) + (4.0 * math.pow(self.chord_height, 2))) / (
8 * self.chord_height
)

# TODO set to 0 for now, add ability to shift the center of the chord left and right
chord_center = (0, self.chord_center_height)

if self.upper_or_lower == "upper":
center_point = (chord_center[0], chord_center[1] + self.chord_height - radius_of_sphere)
far_side = (center_point[0], center_point[1] - (radius_of_sphere + self.thickness))
elif self.upper_or_lower == "lower":
center_point = (chord_center[0], chord_center[1] - self.chord_height + radius_of_sphere)
far_side = (center_point[0], center_point[1] + radius_of_sphere + self.thickness)
else:
raise ValueError("self.upper_or_lower")

big_sphere = (
cq.Workplane(self.workplane)
.moveTo(center_point[0], center_point[1])
.sphere(radius_of_sphere + self.thickness)
)
small_sphere = cq.Workplane(self.workplane).moveTo(center_point[0], center_point[1]).sphere(radius_of_sphere)

outer_cylinder_cutter = RotateStraightShape(
workplane=self.workplane,
points=(
(chord_center[0], chord_center[1]), # cc
(self.points[1][0], self.points[1][1]), # point 2
(self.points[2][0], self.points[2][1]), # point 3
(self.points[2][0] + radius_of_sphere, self.points[2][1]), # point 3 wider
(self.points[2][0] + radius_of_sphere, far_side[1]),
far_side,
),
rotation_angle=360,
)

cap = Shape()
cap.solid = big_sphere.cut(small_sphere)

height = 2 * (radius_of_sphere + abs(center_point[1]) + self.thickness)
radius = 2 * (radius_of_sphere + abs(center_point[0]) + self.thickness)
cutter = CuttingWedge(height=height, radius=radius, rotation_angle=self.rotation_angle)

cap.solid = cap.solid.intersect(cutter.solid)
cap.solid = cap.solid.cut(outer_cylinder_cutter.solid)

self.solid = cap.solid
Loading

0 comments on commit dd6aa1b

Please sign in to comment.