Skip to content

Updated Parchmint Valve spec to new RFC. #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion parchmint/benchmarking.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ def characterize_devices(devices: List[Device]) -> npt.NDArray[Any]:

# Save yes if the device has a layer of type CONTROL
file_info[index, 5] = (
"YES" if "CONTROL" in [layer.type for layer in device.layers] else "NO"
"YES"
if "CONTROL" in [layer.layer_type for layer in device.layers]
else "NO"
)

# Save the max connectiveity of the connection in the device
Expand Down
73 changes: 38 additions & 35 deletions parchmint/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,9 @@ def rotation(self) -> float:
"""
try:
return self.params.get_param("rotation")
except Exception:
print("Could not find rotation for component")
raise KeyError
except Exception as error:
print("Could not find rotation for component", error)
raise Exception("Could not find rotation for component") from error

@rotation.setter
def rotation(self, value):
Expand Down Expand Up @@ -258,15 +258,16 @@ def rotate_point(
Returns:
Tuple[float, float]: A tuple containing the rotated coordinates
"""
# pylint: disable=invalid-name, too-many-locals
# Setup the center to be used the translation matrices
center_x = self.xspan / 2
center_y = self.yspan / 2

# Setup all the corner points
old_topLeft = np.array((0, 0, 1)).transpose()
old_topRight = np.array((self.xspan, 0, 1)).transpose()
old_bottomLeft = np.array((0, self.yspan, 1)).transpose()
old_bottomRight = np.array((self.xspan, self.yspan, 1)).transpose()
old_topleft = np.array((0, 0, 1)).transpose()
old_topright = np.array((self.xspan, 0, 1)).transpose()
old_bottomleft = np.array((0, self.yspan, 1)).transpose()
old_bottomright = np.array((self.xspan, self.yspan, 1)).transpose()

pos = np.array(((xpos), (ypos), (1)))

Expand All @@ -278,23 +279,23 @@ def rotate_point(
T2 = np.array(((1, 0, center_x), (0, 1, center_y), (0, 0, 1)))

# Rotate the topRight corner and the bottomLeft corner about the center
rotated_topLeft = T2.dot(R.dot(T1.dot(old_bottomLeft)))
rotated_topRight = T2.dot(R.dot(T1.dot(old_topLeft)))
rotated_bottomRight = T2.dot(R.dot(T1.dot(old_topRight)))
rotated_bottomLeft = T2.dot(R.dot(T1.dot(old_bottomRight)))
rotated_topleft = T2.dot(R.dot(T1.dot(old_bottomleft)))
rotated_topright = T2.dot(R.dot(T1.dot(old_topleft)))
rotated_bottomright = T2.dot(R.dot(T1.dot(old_topright)))
rotated_bottomleft = T2.dot(R.dot(T1.dot(old_bottomright)))

# Find the new position of the topleft corner by finding the min of all the corner points
xmin = min(
rotated_topLeft[0],
rotated_topRight[0],
rotated_bottomLeft[0],
rotated_bottomRight[0],
rotated_topleft[0],
rotated_topright[0],
rotated_bottomleft[0],
rotated_bottomright[0],
)
ymin = min(
rotated_topLeft[1],
rotated_topRight[1],
rotated_bottomLeft[1],
rotated_bottomRight[1],
rotated_topleft[1],
rotated_topright[1],
rotated_bottomleft[1],
rotated_bottomright[1],
)

T3 = np.array(((1, 0, -xmin), (0, 1, -ymin), (0, 0, 1)))
Expand All @@ -315,6 +316,8 @@ def rotate_point_around_center(
Returns:
Tuple[float, float]: A tuple containing the rotated coordinates
"""
# pylint: disable=invalid-name,too-many-locals

# Setup the center to be used the translation matrices
center_x = self.xpos + self.xspan / 2
center_y = self.ypos + self.yspan / 2
Expand All @@ -340,23 +343,23 @@ def get_rotated_component_definition(self, angle: int) -> Component:
Returns:
Component: [description]
"""
new_topLeft = self.rotate_point(0, 0, angle)
new_topRight = self.rotate_point(self.xspan, 0, angle)
new_bottomLeft = self.rotate_point(0, self.yspan, angle)
new_bottomRight = self.rotate_point(self.xspan, self.yspan, angle)
new_topleft = self.rotate_point(0, 0, angle)
new_topright = self.rotate_point(self.xspan, 0, angle)
new_bottomleft = self.rotate_point(0, self.yspan, angle)
new_bottomright = self.rotate_point(self.xspan, self.yspan, angle)

# Find xmin, ymin, xmax, ymax for all the corner points
xmin = min(
new_topLeft[0], new_topRight[0], new_bottomLeft[0], new_bottomRight[0]
new_topleft[0], new_topright[0], new_bottomleft[0], new_bottomright[0]
)
ymin = min(
new_topLeft[1], new_topRight[1], new_bottomLeft[1], new_bottomRight[1]
new_topleft[1], new_topright[1], new_bottomleft[1], new_bottomright[1]
)
xmax = max(
new_topLeft[0], new_topRight[0], new_bottomLeft[0], new_bottomRight[0]
new_topleft[0], new_topright[0], new_bottomleft[0], new_bottomright[0]
)
ymax = max(
new_topLeft[1], new_topRight[1], new_bottomLeft[1], new_bottomRight[1]
new_topleft[1], new_topright[1], new_bottomleft[1], new_bottomright[1]
)

# Find the new xspan and yspan
Expand Down Expand Up @@ -408,31 +411,31 @@ def rotate_component(self) -> None:
port.x = new_location[0]
port.y = new_location[1]

new_topLeft = self.rotate_point_around_center(
new_topleft = self.rotate_point_around_center(
self.xpos + 0, self.ypos + 0, self.rotation
)
new_topRight = self.rotate_point_around_center(
new_topright = self.rotate_point_around_center(
self.xpos + self.xspan, self.ypos + 0, self.rotation
)
new_bottomLeft = self.rotate_point_around_center(
new_bottomleft = self.rotate_point_around_center(
self.xpos + 0, self.ypos + self.yspan, self.rotation
)
new_bottomRight = self.rotate_point_around_center(
new_bottomright = self.rotate_point_around_center(
self.xpos + self.xspan, self.ypos + self.yspan, self.rotation
)

# Find xmin, ymin, xmax, ymax for all the corner points
xmin = min(
new_topLeft[0], new_topRight[0], new_bottomLeft[0], new_bottomRight[0]
new_topleft[0], new_topright[0], new_bottomleft[0], new_bottomright[0]
)
ymin = min(
new_topLeft[1], new_topRight[1], new_bottomLeft[1], new_bottomRight[1]
new_topleft[1], new_topright[1], new_bottomleft[1], new_bottomright[1]
)
xmax = max(
new_topLeft[0], new_topRight[0], new_bottomLeft[0], new_bottomRight[0]
new_topleft[0], new_topright[0], new_bottomleft[0], new_bottomright[0]
)
ymax = max(
new_topLeft[1], new_topRight[1], new_bottomLeft[1], new_bottomRight[1]
new_topleft[1], new_topright[1], new_bottomleft[1], new_bottomright[1]
)

# Find the new xspan and yspan
Expand Down
62 changes: 38 additions & 24 deletions parchmint/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,17 +201,17 @@ def remove_valve(self, valve_id) -> None:

self.remove_component(valve_id)

def compare(self, device: Device, ignore_parameter_diffs: bool = True) -> bool:
def compare(self, device: Device, compare_params: bool = False) -> bool:
"""compare against the input device. Return true if they are semnatcally feasible.

Args:
device (Device): expected device
ignore_parameter_diffs (bool): ignore parameter differences. Defaults to True.
compare_params (bool): comparision includes parameter differences. Defaults to False.

Returns:
bool: If semntically feasible, return true. Else false.
"""
matcher = SimilarityMatcher(self, device)
matcher = SimilarityMatcher(self, device, compare_params=compare_params)

is_same = matcher.is_isomorphic()
matcher.print_params_diff()
Expand Down Expand Up @@ -384,7 +384,7 @@ def remove_layer(self, layer_id: str) -> None:

# Remove all the components and connections associated with the layer
for component in self.components:
if set([layer.ID for layer in component.layers]) == set(layer_to_delete.ID):
if {[layer.ID for layer in component.layers]} == set(layer_to_delete.ID):
self.remove_component(component.ID)
else:
warn(
Expand Down Expand Up @@ -429,7 +429,8 @@ def merge_netlist(self, netlist: Device) -> None:
self.add_layer(layer)
layer_mapping[layer] = layer
else:
assert layer.ID is not None
if layer.ID is None:
raise Exception("Layer ID is None, cannot merge the layers")
layer_mapping[layer] = self.get_layer(layer.ID)

for component in netlist.components:
Expand Down Expand Up @@ -634,14 +635,16 @@ def to_parchmint_v1_2(self) -> Dict:
ret["version"] = "1.2"

# Add the valvemap information
valve_map = {}
valve_type_map = {}
valve_objects = []
for valve, connection in self._valve_map.items():
valve_map[valve.ID] = connection.ID
ret["valveMap"] = valve_map
for valve, valve_type in self._valve_type_map.items():
valve_type_map[valve.ID] = str(valve_type)
ret["valveTypeMap"] = valve_type_map
valve_object = {
"componentid": valve.ID,
"connectionid": connection.ID,
"type": str(self._valve_type_map[valve]),
}
valve_objects.append(valve_object)
ret["valves"] = valve_objects

return ret

@staticmethod
Expand Down Expand Up @@ -727,7 +730,7 @@ def from_parchmint_v1(json_data: Dict) -> Device:
# First always add the layers
if "layers" in json_data.keys():
for layer in json_data["layers"]:
device_ref.add_layer(Layer(layer))
device_ref.add_layer(Layer(json_data=layer))
else:
print("no layers found")

Expand Down Expand Up @@ -799,10 +802,16 @@ def from_parchmint_v1_2(json_data: Dict) -> Device:
# First always add the layers
if "layers" in json_data.keys():
for layer in json_data["layers"]:
device_ref.add_layer(Layer(layer))
device_ref.add_layer(Layer(json_data=layer))
else:
print("no layers found")

# Second add all the features
if "features" in json_data.keys():
for feature_json in json_data["features"]:
feature = Feature.from_parchmint_v1_2(feature_json, device_ref)
device_ref.add_feature(feature)

# Loop through the components
if "components" in json_data.keys():
for component_json in json_data["components"]:
Expand All @@ -829,23 +838,28 @@ def from_parchmint_v1_2(json_data: Dict) -> Device:
else:
print("no params found")

def get_valve_type(value: str):
if value is ValveType.NORMALLY_OPEN:
def get_valve_type(value: str) -> ValveType:
if value == ValveType.NORMALLY_OPEN:
return ValveType.NORMALLY_OPEN
elif value is ValveType.NORMALLY_CLOSED:
elif value == ValveType.NORMALLY_CLOSED:
return ValveType.NORMALLY_CLOSED
else:
raise Exception("Unknown valve type {}".format(value))

if "valveMap" in json_data.keys():
valve_map = json_data["valveMap"]
valve_type_map = json_data["valveTypeMap"]
if "valves" in json_data.keys():
valve_objects = json_data["valves"]

for key, value in valve_map.items():
for valve_object in valve_objects:
componentid = valve_object["componentid"]
connectionid = valve_object["connectionid"]
# Note - Sets it to default normally open if nothign is specified
valve_type = valve_object["type"] if "type" in valve_object else None
device_ref.map_valve(
device_ref.get_component(key),
device_ref.get_connection(value),
get_valve_type(valve_type_map[key]),
device_ref.get_component(componentid),
device_ref.get_connection(connectionid),
get_valve_type(valve_type)
if valve_type is not None
else ValveType.NORMALLY_OPEN,
)

return device_ref
44 changes: 35 additions & 9 deletions parchmint/layer.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import Dict, Optional

from parchmint.params import Params

Expand All @@ -9,17 +9,25 @@ class Layer:
Used to define a layer object that can be used in the device model.
"""

def __init__(self, json_data=None) -> None:
def __init__(
self,
layer_id: Optional[str] = None,
name: Optional[str] = None,
layer_type: Optional[str] = None,
group: Optional[str] = None,
params: Optional[Params] = None,
json_data: Optional[Dict] = None,
) -> None:
"""Creates a new instance Layer

Args:
json (dict, optional): json dict after json.loads(). Defaults to None.
"""
self._id: str = ""
self.name: str = ""
self.type: str = ""
self.group: str = ""
self.params: Params = Params()
self._id: str = "" if layer_id is None else layer_id
self.name: str = "" if name is None else name
self.layertype: str = "" if layer_type is None else layer_type
self.group: str = "" if group is None else group
self.params: Params = Params() if params is None else params

if json_data:
self.parse_from_json(json_data)
Expand All @@ -45,6 +53,24 @@ def ID(self, value: str) -> None:
"""
self._id = value

@property
def layer_type(self) -> str:
"""Returns the layer type

Returns:
str: layer type
"""
return self.layertype

@layer_type.setter
def layer_type(self, value: str) -> None:
"""Sets the layer type

Args:
value (str): layer type
"""
self.layertype = value

def parse_from_json(self, json_data):
"""Loads instance data json dict from json.loads()

Expand All @@ -53,7 +79,7 @@ def parse_from_json(self, json_data):
"""
self.name = json_data["name"]
self.ID = json_data["id"]
self.type = json_data["type"]
self.layertype = json_data["type"]
self.group = json_data["group"]
self.params = Params(json_data["params"])

Expand All @@ -66,7 +92,7 @@ def to_parchmint_v1(self):
return {
"name": self.name,
"id": self.ID,
"type": self.type,
"type": self.layertype,
"params": self.params.to_parchmint_v1(),
"group": self.group,
}
Expand Down
2 changes: 1 addition & 1 deletion parchmint/port.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def __init__(
layer: Optional[str] = None,
x: float = -1,
y: float = -1,
json_data: Dict = {},
json_data: Optional[Dict] = None,
):
"""Creates a ComponentPort which is used to represent the points
where a connection connects on the component
Expand Down
2 changes: 1 addition & 1 deletion parchmint/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def __init__(
self,
component_id: Optional[str] = None,
port: Optional[str] = None,
json_data: Dict = {},
json_data: Optional[Dict] = None,
):
"""Creates a Target object that describes where the connection will connect to

Expand Down
Loading