from semi_cr.core.lab.measurements.profiles.dc_profiles import (
VoltageSource,
VoltageMeter,
RoutedVoltageMeter,
CurrentSource,
CurrentMeter,
)
import networkx as nx
from semi_cr.core.lab.station.routing_v1.queries import objects_on_electrical_net
from semi_cr.core.lab.station.routing_v1.resolution import (
find_backend_object_for_pin,
)
[docs]
def find_voltage_source_for_pin(
graph: nx.MultiDiGraph,
device,
pin_name: str,
) -> VoltageSource:
for obj in objects_on_electrical_net(graph, device, pin_name):
if isinstance(obj, VoltageSource):
return obj
raise LookupError(f"No voltage source found for {device}.{pin_name}")
[docs]
def find_voltage_meter_for_pin_pair(
graph: nx.MultiDiGraph,
device,
high_pin: str,
low_pin: str,
mode: str = "2probe",
) -> RoutedVoltageMeter:
high_objects = objects_on_electrical_net(graph, device, high_pin)
low_objects = objects_on_electrical_net(graph, device, low_pin)
high_meters = [
obj for obj in high_objects
if isinstance(obj, VoltageMeter)
]
low_meters = [
obj for obj in low_objects
if isinstance(obj, VoltageMeter)
]
if not high_meters:
raise LookupError(f"No voltage meter found for {device}.{high_pin}")
compatible_meter = next(
(
high_meter
for high_meter in high_meters
if any(
high_meter is low_meter
for low_meter in low_meters
)
),
None,
)
if compatible_meter is None:
raise LookupError(
"No compatible voltage meter found for "
f"{device.short_name}.{high_pin} and "
f"{device.short_name}.{low_pin}."
)
return RoutedVoltageMeter(
meter=high_meters[0],
high_pin=high_pin,
low_pin=low_pin,
mode=mode,
)
[docs]
def find_current_source_for_pin(
graph: nx.MultiDiGraph,
device,
pin_name: str,
) -> CurrentSource:
for obj in objects_on_electrical_net(graph, device, pin_name):
if isinstance(obj, CurrentSource):
return obj
raise LookupError(f"No current source found for {device}.{pin_name}")
# def find_current_meter_for_pin(
# graph: nx.MultiDiGraph,
# device,
# pin_name: str,
# ):
# route = trace_pin_route(
# graph,
# device,
# pin_name,
# )
# for node_id in route:
# if graph.nodes[node_id].get("kind") != "terminal":
# continue
# for pred in graph.predecessors(node_id):
# obj = graph.nodes[pred].get("obj")
# if isinstance(obj, CurrentMeter):
# return obj
# raise LookupError(
# f"No current measurement found for "
# f"{device.short_name}.{pin_name}"
# )
[docs]
def find_current_meter_for_pin(
graph: nx.MultiDiGraph,
device,
pin_name: str,
) -> CurrentMeter:
backend = find_backend_object_for_pin(
graph=graph,
device=device,
pin_name=pin_name,
role="meter",
quantity="current",
modality="dc",
)
if not isinstance(
backend,
CurrentMeter,
):
raise LookupError(
"Resolved backend for "
f"{device.short_name}.{pin_name} "
"is not a CurrentMeter."
)
return backend
[docs]
def find_voltage_source_for_method(
graph: nx.MultiDiGraph,
device,
profile_name: str,
method_name: str,
):
profile = device.get_measurement_profile(profile_name)
method = profile.methods[method_name]
source_role = method.roles["voltage_source"] # e.g. force_hi
source_pin = profile.pins[source_role].device_pin # e.g. source
return find_voltage_source_for_pin(
graph,
device,
source_pin,
)
[docs]
def find_voltage_meter_for_method(
graph: nx.MultiDiGraph,
device,
profile_name: str,
method_name: str,
) -> RoutedVoltageMeter:
profile = device.get_measurement_profile(profile_name)
method = profile.methods[method_name]
high_role = method.roles["voltage_meter"]["high"]
low_role = method.roles["voltage_meter"]["low"]
high_pin = profile.pins[high_role].device_pin
low_pin = profile.pins[low_role].device_pin
return find_voltage_meter_for_pin_pair(
graph,
device,
high_pin,
low_pin,
mode=getattr(method, "mode", "2probe"),
)
[docs]
def find_current_meter_for_method(
graph: nx.MultiDiGraph,
device,
profile_name: str,
method_name: str,
):
profile = device.get_measurement_profile(profile_name)
method = profile.methods[method_name]
current_role = method.roles["current_meter"]
current_pin = profile.pins[current_role].device_pin
return find_current_meter_for_pin(
graph,
device,
current_pin,
)