Skip to content

Commit

Permalink
Add support for 'inverted fins' to Finocyl grains
Browse files Browse the repository at this point in the history
  • Loading branch information
reilleya committed Dec 6, 2023
1 parent 8af88ed commit a364c84
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 15 deletions.
46 changes: 33 additions & 13 deletions motorlib/grains/finocyl.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import numpy as np

from ..grain import FmmGrain
from ..properties import FloatProperty, IntProperty
from ..properties import FloatProperty, IntProperty, BooleanProperty
from ..simResult import SimAlert, SimAlertLevel, SimAlertType

class Finocyl(FmmGrain):
Expand All @@ -16,13 +16,17 @@ def __init__(self):
self.props['finWidth'] = FloatProperty('Fin width', 'm', 0, 1)
self.props['finLength'] = FloatProperty('Fin length', 'm', 0, 1)
self.props['coreDiameter'] = FloatProperty('Core diameter', 'm', 0, 1)
self.props['invertedFins'] = BooleanProperty('Inverted fins')

def generateCoreMap(self):
coreRadius = self.normalize(self.props['coreDiameter'].getValue()) / 2
numFins = self.props['numFins'].getValue()
finWidth = self.normalize(self.props['finWidth'].getValue())
# The user enters the length that the fin protrudes from the core, so we add the radius on
finLength = self.normalize(self.props['finLength'].getValue()) + coreRadius
finLength = self.normalize(self.props['finLength'].getValue())
invertedFins = self.props['invertedFins'].getValue()

finStart = coreRadius - finLength if invertedFins else 0
finEnd = coreRadius if invertedFins else finLength + coreRadius

# Open up core
self.coreMap[self.mapX**2 + self.mapY**2 < coreRadius**2] = 0
Expand All @@ -36,11 +40,11 @@ def generateCoreMap(self):
# Select all points within half the width of the vector
vect = abs(vect0*self.mapX + vect1*self.mapY) < finWidth / 2
# Set up two perpendicular vectors to cap off the ends
near = (vect1 * self.mapX) - (vect0 * self.mapY) > 0 # Inside of the core
far = (vect1 * self.mapX) - (vect0 * self.mapY) < finLength # At the casting tube end of the vector
near = (vect1 * self.mapX) - (vect0 * self.mapY) > finStart
far = (vect1 * self.mapX) - (vect0 * self.mapY) < finEnd
ends = np.logical_and(far, near)
# Open up the fin
self.coreMap[np.logical_and(vect, ends)] = 0
# For inverted fins, we are filling propellant back in. For regular fins, we are removing it.
self.coreMap[np.logical_and(vect, ends)] = invertedFins

def getDetailsString(self, lengthUnit='m'):
return 'Length: {}, Core: {}, Fins: {}'.format(self.props['length'].dispFormat(lengthUnit),
Expand All @@ -60,18 +64,34 @@ def getGeometryErrors(self):
if self.props['finLength'].getValue() * 2 > self.props['diameter'].getValue():
aText = 'Fin length should be less than or equal to grain radius'
errors.append(SimAlert(SimAlertLevel.WARNING, SimAlertType.GEOMETRY, aText))
coreWidth = self.props['coreDiameter'].getValue() + (2 * self.props['finLength'].getValue())
if coreWidth > self.props['diameter'].getValue():
aText = 'Core radius plus fin length should be less than or equal to grain radius'
errors.append(SimAlert(SimAlertLevel.WARNING, SimAlertType.GEOMETRY, aText))

if self.props['invertedFins'].getValue():
coreRadius = self.props['coreDiameter'].getValue() / 2
# In the weird case of one fin that extends beyond the core, we need to make sure it doesn't
# intersect the core again on the other side as that would divide the port
if self.props['finLength'].getValue() > coreRadius:
lengthPastCenter = self.props['finLength'].getValue() - coreRadius
halfWidth = self.props['finWidth'].getValue() / 2
tipRadius = (lengthPastCenter ** 2 + halfWidth ** 2) ** 0.5
if tipRadius > coreRadius and self.props['numFins'].getValue() > 0:
aText = 'Fin tips outside of core'
errors.append(SimAlert(SimAlertLevel.ERROR, SimAlertType.GEOMETRY, aText))
else:
coreWidth = self.props['coreDiameter'].getValue() + (2 * self.props['finLength'].getValue())
if coreWidth > self.props['diameter'].getValue():
aText = 'Core radius plus fin length should be less than or equal to grain radius'
errors.append(SimAlert(SimAlertLevel.WARNING, SimAlertType.GEOMETRY, aText))

if self.props['finWidth'].getValue() == 0:
errors.append(SimAlert(SimAlertLevel.ERROR, SimAlertType.GEOMETRY, 'Fin width must not be 0'))
if self.props['numFins'].getValue() > 1:
radius = self.props['coreDiameter'].getValue() / 2
apothem = radius + self.props['finLength'].getValue()
finLength = self.props['finLength'].getValue()
invertedFins = self.props['invertedFins'].getValue()
level = SimAlertLevel.ERROR if invertedFins else SimAlertLevel.WARNING
apothem = radius - finLength if invertedFins else radius + finLength
sideLength = 2 * apothem * np.tan(np.pi / self.props['numFins'].getValue())
if sideLength < self.props['finWidth'].getValue():
errors.append(SimAlert(SimAlertLevel.WARNING, SimAlertType.GEOMETRY, 'Fin tips intersect'))
errors.append(SimAlert(level, SimAlertType.GEOMETRY, 'Fin tips intersect'))

return errors
6 changes: 6 additions & 0 deletions motorlib/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ def __init__(self, dispName):
super().__init__(dispName, '', str)


class BooleanProperty(Property):
"""A property with a single boolean as the value"""
def __init__(self, dispName):
super().__init__(dispName, '', bool)


class PolygonProperty(Property):
"""A property that contains a list of polygons, each a list of points"""
def __init__(self, dispName):
Expand Down
3 changes: 3 additions & 0 deletions uilib/fileIO.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ def passthrough(data):
def migrateMotor_0_5_0_to_0_6_0(data):
data['config']['sepPressureRatio'] = DEFAULT_PREFERENCES['general']['sepPressureRatio']
data['config']['flowSeparationWarnPercent'] = DEFAULT_PREFERENCES['general']['flowSeparationWarnPercent']
for grain in data['grains']:
if grain['type'] == 'Finocyl':
grain['properties']['invertedFins'] = False
return data

# 0.4.0 to 0.5.0
Expand Down
13 changes: 11 additions & 2 deletions uilib/widgets/propertyEditor.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import math

from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLineEdit
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLineEdit, QCheckBox
from PyQt6.QtWidgets import QDoubleSpinBox, QSpinBox, QComboBox
from PyQt6.QtCore import pyqtSignal
from PyQt6.QtCore import pyqtSignal, Qt

import motorlib

Expand Down Expand Up @@ -56,6 +56,12 @@ def __init__(self, parent, prop, preferences):
self.editor.setText(self.prop.getValue())
self.layout().addWidget(self.editor)

elif isinstance(prop, motorlib.properties.BooleanProperty):
self.editor = QCheckBox()
self.editor.setCheckState(Qt.CheckState.Checked if self.prop.getValue() else Qt.CheckState.Unchecked)
self.editor.stateChanged.connect(self.valueChanged.emit)
self.layout().addWidget(self.editor)

elif isinstance(prop, motorlib.properties.EnumProperty):
self.editor = QComboBox()

Expand Down Expand Up @@ -94,6 +100,9 @@ def getValue(self):
if isinstance(self.prop, motorlib.properties.StringProperty):
return self.editor.text()

if isinstance(self.prop, motorlib.properties.BooleanProperty):
return self.editor.isChecked()

if isinstance(self.prop, motorlib.properties.EnumProperty):
return self.editor.currentText()

Expand Down

0 comments on commit a364c84

Please sign in to comment.