emerge 0.6.11__tar.gz → 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of emerge might be problematic. Click here for more details.
- {emerge-0.6.11 → emerge-1.0.1}/.bumpversion.toml +1 -1
- {emerge-0.6.11 → emerge-1.0.1}/PKG-INFO +6 -8
- {emerge-0.6.11 → emerge-1.0.1}/README.md +3 -7
- {emerge-0.6.11 → emerge-1.0.1}/emerge/__init__.py +2 -2
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/bc.py +8 -3
- emerge-1.0.1/emerge/_emerge/cacherun.py +79 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo/__init__.py +1 -1
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo/pcb.py +160 -71
- emerge-1.0.1/emerge/_emerge/geo/pcb_tools/dxf.py +360 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo/polybased.py +21 -15
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo/shapes.py +31 -16
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geometry.py +147 -21
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/material.py +2 -1
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/mesh3d.py +39 -12
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/periodic.py +19 -17
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/assembly/assembler.py +12 -12
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/microwave_3d.py +29 -6
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/microwave_bc.py +22 -9
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/microwave_data.py +3 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/plot/pyvista/display.py +20 -6
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/plot/pyvista/display_settings.py +2 -1
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/plot/simple_plots.py +4 -1
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/selection.py +10 -8
- emerge-1.0.1/emerge/_emerge/settings.py +12 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/simmodel.py +182 -48
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/solver.py +9 -2
- emerge-1.0.1/emerge/beta/dxf.py +1 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/lib.py +4 -1
- emerge-1.0.1/emerge/materials/__init__.py +1 -0
- emerge-1.0.1/emerge/materials/isola.py +294 -0
- emerge-1.0.1/emerge/materials/rogers.py +58 -0
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo10_sgh.py +14 -10
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo11_lumped_element_filter.py +2 -6
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo12_mode_alignment.py +3 -3
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo13_helix_antenna.py +1 -1
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo14_boundary_selection.py +1 -1
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo1_stepped_imp_filter.py +2 -5
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo2_combline_filter.py +1 -1
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo3_coupled_line_filter.py +20 -20
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo4_patch_antenna.py +4 -6
- emerge-1.0.1/examples/demo5_revolve.py +98 -0
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo6_striplines_with_vias.py +3 -5
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo7_periodic_cells.py +3 -3
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo8_waveguide_bpf_synthesis.py +2 -2
- {emerge-0.6.11 → emerge-1.0.1}/examples/demo9_dielectric_resonator.py +9 -10
- {emerge-0.6.11 → emerge-1.0.1}/pyproject.toml +5 -1
- {emerge-0.6.11 → emerge-1.0.1}/uv.lock +64 -2
- emerge-0.6.11/.opt +0 -714
- emerge-0.6.11/examples/demo5_revolve.py +0 -15
- {emerge-0.6.11 → emerge-1.0.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/.gitignore +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/.python-version +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/LICENSE +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/THIRD_PARTY_LICENSES.md +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/UMFPACK_Install_windows.md +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/UMFPACK_installer_windows.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/__main__.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/__init__.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/_cache_check.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/const.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/coord.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/cs.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/dataset.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/elements/__init__.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/elements/femdata.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/elements/index_interp.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/elements/ned2_interp.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/elements/nedelec2.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/elements/nedleg2.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo/horn.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo/modeler.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo/operations.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo/pcb_tools/calculator.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo/pcb_tools/macro.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo/pmlbox.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo/step.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/geo2d.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/howto.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/logsettings.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/mesher.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/mth/common_functions.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/mth/integrals.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/mth/optimized.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/mth/pairing.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/__init__.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/__init__.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/adaptive_freq.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/assembly/curlcurl.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/assembly/generalized_eigen.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/assembly/generalized_eigen_hb.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/assembly/periodicbc.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/assembly/robinbc.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/periodic.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/port_functions.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/sc.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/simjob.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/sparam.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/physics/microwave/touchstone.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/plot/__init__.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/plot/display.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/plot/matplotlib/mpldisplay.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/plot/pyvista/__init__.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/plot.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/projects/__init__.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/projects/_gen_base.txt +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/projects/_load_base.txt +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/projects/generate_project.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/simulation_data.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/solve_interfaces/cudss_interface.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/solve_interfaces/pardiso_interface.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/_emerge/system.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/cli.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/ext.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/plot.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/emerge/pyvista.py +0 -0
- {emerge-0.6.11 → emerge-1.0.1}/src/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: emerge
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: An open source EM FEM simulator in Python
|
|
5
5
|
Project-URL: Homepage, https://github.com/FennisRobert/EMerge
|
|
6
6
|
Project-URL: Issues, https://github.com/FennisRobert/EMerge/issues
|
|
@@ -20,6 +20,8 @@ Provides-Extra: cudss
|
|
|
20
20
|
Requires-Dist: cupy-cuda12x; extra == 'cudss'
|
|
21
21
|
Requires-Dist: nvidia-cudss-cu12; extra == 'cudss'
|
|
22
22
|
Requires-Dist: nvmath-python[cu12]; extra == 'cudss'
|
|
23
|
+
Provides-Extra: dxf
|
|
24
|
+
Requires-Dist: ezdxf; extra == 'dxf'
|
|
23
25
|
Provides-Extra: umfpack
|
|
24
26
|
Requires-Dist: scikit-umfpack; (sys_platform != 'win32') and extra == 'umfpack'
|
|
25
27
|
Description-Content-Type: text/markdown
|
|
@@ -82,17 +84,13 @@ To run this FEM library you need the following libraries
|
|
|
82
84
|
- numba
|
|
83
85
|
- matplotlib (for the matplotlib base display)
|
|
84
86
|
- pyvista (for the PyVista base display)
|
|
85
|
-
-
|
|
87
|
+
- cloudpickle
|
|
86
88
|
- mkl (x86 devices only)
|
|
87
89
|
|
|
88
90
|
Optional:
|
|
89
91
|
- scikit-umfpack
|
|
90
92
|
- cudss
|
|
91
93
|
|
|
92
|
-
##
|
|
94
|
+
## Resources / Manual
|
|
93
95
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
## Third Party License Notice
|
|
97
|
-
|
|
98
|
-
“This package depends on Intel® Math Kernel Library (MKL), which is licensed separately under the Intel Simplified Software License (October 2022). Installing with pip will fetch the MKL wheel and prompt you to accept that licence.”
|
|
96
|
+
You can find the latest versions of the manual on: **https://www.emerge-software.com/resources/**
|
|
@@ -56,17 +56,13 @@ To run this FEM library you need the following libraries
|
|
|
56
56
|
- numba
|
|
57
57
|
- matplotlib (for the matplotlib base display)
|
|
58
58
|
- pyvista (for the PyVista base display)
|
|
59
|
-
-
|
|
59
|
+
- cloudpickle
|
|
60
60
|
- mkl (x86 devices only)
|
|
61
61
|
|
|
62
62
|
Optional:
|
|
63
63
|
- scikit-umfpack
|
|
64
64
|
- cudss
|
|
65
65
|
|
|
66
|
-
##
|
|
66
|
+
## Resources / Manual
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
## Third Party License Notice
|
|
71
|
-
|
|
72
|
-
“This package depends on Intel® Math Kernel Library (MKL), which is licensed separately under the Intel Simplified Software License (October 2022). Installing with pip will fetch the MKL wheel and prompt you to accept that licence.”
|
|
68
|
+
You can find the latest versions of the manual on: **https://www.emerge-software.com/resources/**
|
|
@@ -18,7 +18,7 @@ along with this program; if not, see
|
|
|
18
18
|
"""
|
|
19
19
|
import os
|
|
20
20
|
|
|
21
|
-
__version__ = "0.
|
|
21
|
+
__version__ = "1.0.1"
|
|
22
22
|
|
|
23
23
|
############################################################
|
|
24
24
|
# HANDLE ENVIRONMENT VARIABLES #
|
|
@@ -27,7 +27,7 @@ __version__ = "0.6.11"
|
|
|
27
27
|
NTHREADS = "1"
|
|
28
28
|
os.environ["EMERGE_STD_LOGLEVEL"] = os.getenv("EMERGE_STD_LOGLEVEL", default="INFO")
|
|
29
29
|
os.environ["EMERGE_FILE_LOGLEVEL"] = os.getenv("EMERGE_FILE_LOGLEVEL", default="DEBUG")
|
|
30
|
-
os.environ["OMP_NUM_THREADS"] = os.getenv("OMP_NUM_THREADS", default="
|
|
30
|
+
os.environ["OMP_NUM_THREADS"] = os.getenv("OMP_NUM_THREADS", default="1")
|
|
31
31
|
os.environ["MKL_NUM_THREADS"] = os.getenv("MKL_NUM_THREADS", default="4")
|
|
32
32
|
os.environ["OPENBLAS_NUM_THREADS"] = NTHREADS
|
|
33
33
|
os.environ["VECLIB_MAXIMUM_THREADS"] = NTHREADS
|
|
@@ -83,7 +83,7 @@ class BoundaryCondition:
|
|
|
83
83
|
raise ValueError(f'All tags must have the same dimension, instead its {tags}')
|
|
84
84
|
dimension = tags[0][0]
|
|
85
85
|
if self.dimension is BCDimension.ANY:
|
|
86
|
-
logger.info(f'Assigning dimension
|
|
86
|
+
logger.info(f'Assigning {self} to dimension{BCDimension(dimension)}')
|
|
87
87
|
self.dimension = BCDimension(dimension)
|
|
88
88
|
elif self.dimension != BCDimension(dimension):
|
|
89
89
|
raise ValueError(f'Current boundary condition has dimension {self.dimension}, but tags have dimension {BCDimension(dimension)}')
|
|
@@ -131,6 +131,13 @@ class BoundaryConditionSet:
|
|
|
131
131
|
self.boundary_conditions: list[BoundaryCondition] = []
|
|
132
132
|
self._initialized: bool = False
|
|
133
133
|
|
|
134
|
+
def cleanup(self) -> None:
|
|
135
|
+
""" Removes non assigned boundary conditions"""
|
|
136
|
+
logger.trace("Cleaning up boundary conditions.")
|
|
137
|
+
toremove = [bc for bc in self.boundary_conditions if len(bc.tags)==0]
|
|
138
|
+
logger.trace(f"Removing: {toremove}")
|
|
139
|
+
self.boundary_conditions = [bc for bc in self.boundary_conditions if len(bc.tags)>0]
|
|
140
|
+
|
|
134
141
|
def _construct_bc(self, constructor: type) -> type:
|
|
135
142
|
def constr(*args, **kwargs):
|
|
136
143
|
obj = constructor(*args, **kwargs)
|
|
@@ -201,8 +208,6 @@ class BoundaryConditionSet:
|
|
|
201
208
|
|
|
202
209
|
bc.add_tags(bc.selection.dimtags)
|
|
203
210
|
|
|
204
|
-
logger.info('Excluding other possible boundary conditions')
|
|
205
|
-
|
|
206
211
|
for existing_bc in self.boundary_conditions:
|
|
207
212
|
excluded = existing_bc.exclude_bc(bc)
|
|
208
213
|
if excluded:
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# inside your module, e.g. utils.py
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
import ast
|
|
6
|
+
import textwrap
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _is_plain_check_run(test: ast.AST) -> bool:
|
|
11
|
+
"""True only for a bare call to check_run() as the entire if-test."""
|
|
12
|
+
if not isinstance(test, ast.Call) or test.args or test.keywords:
|
|
13
|
+
return False
|
|
14
|
+
f = test.func
|
|
15
|
+
return (
|
|
16
|
+
isinstance(f, ast.Attribute) and f.attr == "cache_run"
|
|
17
|
+
) or (
|
|
18
|
+
isinstance(f, ast.Name) and f.id == "cache_run"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
def get_run_block_str(source: str) -> str:
|
|
22
|
+
"""
|
|
23
|
+
Return all source text before the first `if check_run():` / `if *.check_run():`.
|
|
24
|
+
Returns None if no matching if-statement exists.
|
|
25
|
+
"""
|
|
26
|
+
tree = ast.parse(source)
|
|
27
|
+
candidates = [n for n in ast.walk(tree) if isinstance(n, ast.If) and _is_plain_check_run(n.test)]
|
|
28
|
+
if not candidates:
|
|
29
|
+
return None
|
|
30
|
+
first = min(candidates, key=lambda n: n.lineno)
|
|
31
|
+
lines = source.splitlines(keepends=True)
|
|
32
|
+
return "".join(lines[: first.lineno - 1])
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_build_block_str(source: str) -> str | None:
|
|
36
|
+
"""Return the code string inside the first `if *.checkrun(...):` block, or None."""
|
|
37
|
+
tree = ast.parse(source)
|
|
38
|
+
for node in ast.walk(tree):
|
|
39
|
+
if isinstance(node, ast.If) and isinstance(node.test, ast.Call):
|
|
40
|
+
f = node.test.func
|
|
41
|
+
called = (isinstance(f, ast.Attribute) and f.attr == "cache_build") or \
|
|
42
|
+
(isinstance(f, ast.Name) and f.id == "cache_build")
|
|
43
|
+
if called and node.body:
|
|
44
|
+
start = node.body[0].lineno - 1 # 0-based start line
|
|
45
|
+
end = node.body[-1].end_lineno # 1-based end line (inclusive)
|
|
46
|
+
lines = source.splitlines()
|
|
47
|
+
block = "\n".join(lines[start:end])
|
|
48
|
+
return textwrap.dedent(block)
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
def entry_script_path():
|
|
52
|
+
main = sys.modules.get("__main__")
|
|
53
|
+
# Most normal runs: python path/to/app.py
|
|
54
|
+
if main and hasattr(main, "__file__"):
|
|
55
|
+
return os.path.abspath(main.__file__)
|
|
56
|
+
# Fallbacks (e.g. python -m pkg.mod)
|
|
57
|
+
if sys.argv and sys.argv[0] not in ("", "-c"):
|
|
58
|
+
return os.path.abspath(sys.argv[0])
|
|
59
|
+
# Interactive sessions, notebooks, or embedded interpreters
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_build_section() -> str:
|
|
64
|
+
""" Returns the string section inside the check_build() if statement"""
|
|
65
|
+
name = entry_script_path()
|
|
66
|
+
|
|
67
|
+
lines = get_build_block_str(Path(name).read_text())
|
|
68
|
+
return lines
|
|
69
|
+
|
|
70
|
+
def get_run_section() -> str:
|
|
71
|
+
"""Return sthe string section before the check_run() if statement
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
str: _description_
|
|
75
|
+
"""
|
|
76
|
+
name = entry_script_path()
|
|
77
|
+
|
|
78
|
+
lines = get_run_block_str(Path(name).read_text())
|
|
79
|
+
return lines
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
# along with this program; if not, see
|
|
16
16
|
# <https://www.gnu.org/licenses/>.
|
|
17
17
|
|
|
18
|
-
from .pcb import PCB
|
|
18
|
+
from .pcb import PCB, PCBLayer
|
|
19
19
|
from .pmlbox import pmlbox
|
|
20
20
|
from .horn import Horn
|
|
21
21
|
from .shapes import Cylinder, CoaxCylinder, Box, XYPlate, HalfSphere, Sphere, Plate, OldBox, Alignment, Cone
|