Skip to content

Commit

Permalink
Merge with feature/autochop
Browse files Browse the repository at this point in the history
  • Loading branch information
FranzBangar committed Feb 17, 2025
2 parents 3690cd7 + 848dbd3 commit 3f3e72f
Show file tree
Hide file tree
Showing 41 changed files with 845 additions and 638 deletions.
5 changes: 4 additions & 1 deletion classy_blocks.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
"Pylance",
"scipy"
],
"editor.autoClosingBrackets": "never"
"editor.autoClosingBrackets": "never",
"isort.importStrategy": "fromEnvironment",
"editor.defaultFormatter": null,
"ruff.organizeImports": false
},
"extensions": {
"recommendations": [
Expand Down
2 changes: 2 additions & 0 deletions examples/advanced/edge_grading.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# NOT FINISHED!
# TODO: add operation.grade_edge() and show its usage in this example
import os

import classy_blocks as cb
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
# A terrible blocking of a rectangle for displaying SmoothGrader capabilities

import os

import numpy as np

import classy_blocks as cb
from classy_blocks.grading.autograding.grader import HighReGrader

mesh = cb.Mesh()

base = cb.Grid([0, 0, 0], [3, 2, 0], 3, 2)

shape = cb.ExtrudedShape(base, 1)

# turn one block around to test grader's skillz
shape.grid[1][0].rotate(np.pi, [0, 0, 1])

mesh.add(shape)

# move some points to get a mesh with uneven blocks
mesh.assemble()
finder = cb.GeometricFinder(mesh)

Expand All @@ -19,11 +28,8 @@
vertex.translate([0, 0.8, 0])

mesh.set_default_patch("walls", "wall")

# TODO: Hack! mesh.assemble() won't work here but wires et. al. must be updated
mesh.block_list.update()

grader = HighReGrader(mesh, 0.05)
grader = cb.SmoothGrader(mesh, 0.05)
grader.grade()

mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")
3 changes: 1 addition & 2 deletions examples/chaining/labyrinth.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from typing import List

import classy_blocks as cb
from classy_blocks.grading.autograding.grader import FixedCountGrader
from classy_blocks.util import functions as f

mesh = cb.Mesh()
Expand Down Expand Up @@ -34,7 +33,7 @@

mesh.set_default_patch("walls", "wall")

grader = FixedCountGrader(mesh, 5)
grader = cb.FixedCountGrader(mesh, 5)
grader.grade()

mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")
3 changes: 1 addition & 2 deletions examples/chaining/tank.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import os

import classy_blocks as cb
from classy_blocks.grading.autograding.grader import SimpleGrader

# a cylindrical tank with round end caps
diameter = 0.5
Expand All @@ -25,7 +24,7 @@
mesh.add(start_cap)
mesh.add(end_cap)

grader = SimpleGrader(mesh, 0.05)
grader = cb.SimpleGrader(mesh, 0.05)
grader.grade()

mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")
8 changes: 3 additions & 5 deletions examples/optimization/duct.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,10 @@

optimizer.optimize(tolerance=0.01)

# Quick'n'dirty chopping, don't do this at home
for operation in shape.operations:
for axis in range(3):
operation.chop(axis, count=10)

mesh.add(shape)

grader = cb.SmoothGrader(mesh, 0.08)
grader.grade()

mesh.set_default_patch("walls", "wall")
mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")
3 changes: 3 additions & 0 deletions examples/shape/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,8 @@ def add_edges(self) -> None:
mesh.add(shape)
mesh.assemble()

grader = cb.SmoothGrader(mesh, 0.03)
grader.grade(take="max")

mesh.set_default_patch("walls", "wall")
mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")
11 changes: 4 additions & 7 deletions examples/shape/cylinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import classy_blocks as cb
from classy_blocks.construct.flat.sketches.disk import DiskBase
from classy_blocks.grading.autograding.grader import HighReGrader

DiskBase.core_ratio = 0.4 # Default is 0.8

Expand All @@ -23,21 +22,19 @@
# remove them with this method:
cylinder.remove_inner_edges(start=False, end=True)

bl_thickness = 0.05
core_size = 0.2
bl_thickness = 1e-3
core_size = 0.1

# manual grading
# cylinder.chop_axial(count=30)
# cylinder.chop_radial(start_size=core_size, end_size=bl_thickness)
# cylinder.chop_tangential(start_size=core_size)

mesh.add(cylinder)

mesh.assemble()
mesh.block_list.update()
mesh.modify_patch("walls", "wall")

# automatic grading
grader = HighReGrader(mesh, 0.1)
grader = cb.SmoothGrader(mesh, 0.1)
grader.grade()

mesh.write(os.path.join("..", "case", "system", "blockMeshDict"), debug_path="debug.vtk")
3 changes: 1 addition & 2 deletions examples/shape/quarter_cylinder.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import classy_blocks as cb
from classy_blocks.construct.flat.sketches.disk import QuarterDisk
from classy_blocks.grading.autograding.grader import HighReGrader
from classy_blocks.util import functions as f

mesh = cb.Mesh()
Expand All @@ -21,7 +20,7 @@

mesh.assemble()

grader = HighReGrader(mesh, 0.05)
grader = cb.SmoothGrader(mesh, 0.05)
grader.grade()

mesh.set_default_patch("walls", "wall")
Expand Down
6 changes: 6 additions & 0 deletions src/classy_blocks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
from .construct.shapes.shell import Shell
from .construct.shapes.sphere import Hemisphere
from .construct.stack import ExtrudedStack, RevolvedStack, TransformedStack
from .grading.autograding.fixed.grader import FixedCountGrader
from .grading.autograding.simple.grader import SimpleGrader
from .grading.autograding.smooth.grader import SmoothGrader
from .mesh import Mesh
from .modify.find.geometric import GeometricFinder
from .modify.find.shape import RoundSolidFinder
Expand Down Expand Up @@ -123,4 +126,7 @@
"ViewpointReorienter",
"Wedge",
"WrappedDisk",
"FixedCountGrader",
"SimpleGrader",
"SmoothGrader",
]
4 changes: 4 additions & 0 deletions src/classy_blocks/base/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ class CornerPairError(Exception):
"""Raised when given pair of corners is not valid (for example, edge between 0 and 2)"""


class PatchNotFoundError(Exception):
"""Raised when searching for a non-existing Patch"""


### Grading
class UndefinedGradingsError(Exception):
"""Raised when the user hasn't supplied enough grading data to
Expand Down
8 changes: 5 additions & 3 deletions src/classy_blocks/cbtyping.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from typing import Any, Callable, List, Literal, Sequence, Tuple, TypedDict, Union
from typing import Any, Callable, List, Literal, Optional, Sequence, Tuple, TypedDict, Union

from nptyping import NDArray, Shape
from nptyping import Float, NDArray, Shape

# A plain list of floats
FloatListType = NDArray[Shape["1, *"], Any]
FloatListType = NDArray[Shape["1, *"], Float]

# A single point can be specified as a list of floats or as a numpy array
NPPointType = NDArray[Shape["3, 1"], Any]
Expand Down Expand Up @@ -54,3 +54,5 @@ class ChopArgs(TypedDict, total=False):

# what goes into blockMeshDict's block grading specification
GradingSpecType = Tuple[float, int, float]
# Used by autograders
CellSizeType = Optional[float]
2 changes: 0 additions & 2 deletions src/classy_blocks/construct/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
from classy_blocks.util import functions as f
from classy_blocks.util.constants import DTYPE, TOL

# TODO! Tests


class Series(ElementBase):
def __init__(self, points: PointListType):
Expand Down
1 change: 0 additions & 1 deletion src/classy_blocks/construct/shapes/frustum.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ def __init__(
radius_vector_1 = radius_point_1 - axis_point_1
radius_1 = f.norm(radius_vector_1)

# TODO: TEST
diff = np.dot(axis, radius_vector_1)
if diff > TOL:
raise FrustumCreationError(
Expand Down
90 changes: 90 additions & 0 deletions src/classy_blocks/grading/autograding/catalogue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import functools
from typing import Dict, List, get_args

from classy_blocks.base.exceptions import BlockNotFoundError, NoInstructionError
from classy_blocks.cbtyping import DirectionType
from classy_blocks.grading.autograding.row import Row
from classy_blocks.items.block import Block
from classy_blocks.items.wires.axis import Axis
from classy_blocks.mesh import Mesh


@functools.lru_cache(maxsize=3000) # that's for 1000 blocks
def get_block_from_axis(mesh: Mesh, axis: Axis) -> Block:
for block in mesh.blocks:
if axis in block.axes:
return block

raise RuntimeError("Block for Axis not found!")


class Instruction:
"""A descriptor that tells in which direction the specific block can be chopped."""

def __init__(self, block: Block):
self.block = block
self.directions: List[bool] = [False] * 3

@property
def is_defined(self):
return all(self.directions)

def __hash__(self) -> int:
return id(self)


class RowCatalogue:
"""A collection of rows on a specified axis"""

def __init__(self, mesh: Mesh):
self.mesh = mesh

self.rows: Dict[DirectionType, List[Row]] = {0: [], 1: [], 2: []}
self.instructions = [Instruction(block) for block in mesh.blocks]

for i in get_args(DirectionType):
self._populate(i)

def _get_undefined_instructions(self, direction: DirectionType) -> List[Instruction]:
return [i for i in self.instructions if not i.directions[direction]]

def _find_instruction(self, block: Block):
# TODO: perform dedumbing on this exquisite piece of code
for instruction in self.instructions:
if instruction.block == block:
return instruction

raise NoInstructionError(f"No instruction found for block {block}")

def _add_block_to_row(self, row: Row, instruction: Instruction, direction: DirectionType) -> None:
row.add_block(instruction.block, direction)
instruction.directions[direction] = True

block = instruction.block

for neighbour_axis in block.axes[direction].neighbours:
neighbour_block = get_block_from_axis(self.mesh, neighbour_axis)

if neighbour_block in row.blocks:
continue

instruction = self._find_instruction(neighbour_block)

self._add_block_to_row(row, instruction, neighbour_block.get_axis_direction(neighbour_axis))

def _populate(self, direction: DirectionType) -> None:
while True:
undefined_instructions = self._get_undefined_instructions(direction)
if len(undefined_instructions) == 0:
break

row = Row()
self._add_block_to_row(row, undefined_instructions[0], direction)
self.rows[direction].append(row)

def get_row_blocks(self, block: Block, direction: DirectionType) -> List[Block]:
for row in self.rows[direction]:
if block in row.blocks:
return row.blocks

raise BlockNotFoundError(f"Direction {direction} of {block} not in catalogue")
Empty file.
11 changes: 11 additions & 0 deletions src/classy_blocks/grading/autograding/fixed/grader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from classy_blocks.grading.autograding.fixed.rules import FixedCountRules
from classy_blocks.grading.autograding.grader import GraderBase
from classy_blocks.mesh import Mesh


class FixedCountGrader(GraderBase):
"""The simplest possible mesh grading: use a constant cell count for all axes on all blocks;
useful during mesh building and some tutorial cases"""

def __init__(self, mesh: Mesh, count: int = 8):
super().__init__(mesh, FixedCountRules(count))
19 changes: 19 additions & 0 deletions src/classy_blocks/grading/autograding/fixed/rules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import dataclasses
from typing import List

from classy_blocks.grading.autograding.rules import ChopRules
from classy_blocks.grading.chop import Chop


@dataclasses.dataclass
class FixedCountRules(ChopRules):
count: int = 8

def get_count(self, _length, _start_at_wall, _end_at_wall):
return self.count

def is_squeezed(self, _count, _info) -> bool:
return True # grade everything in first pass

def get_chops(self, count, _info) -> List[Chop]:
return [Chop(count=count)]
Loading

0 comments on commit 3f3e72f

Please sign in to comment.