app: stacked_cores: define an "or gate" sim + script for post-processing
extract transfer characteristics with e.g. ``` extract_meas.py ../../../out/applications/stacked_cores/52-or--0.0004rad-5000ctl_cond-20000coupling_cond-2000ps-100ps-3ctl-3coupling-3_1_winding-49999998976e0-drive- 2e-9 4e-9 8e-9 ```
This commit is contained in:
102
crates/applications/stacked_cores/scripts/extract_meas.py
Executable file
102
crates/applications/stacked_cores/scripts/extract_meas.py
Executable file
@@ -0,0 +1,102 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
invoke with the path to a meas.csv file for the stacked_core 51-xx or later demos
|
||||||
|
to extract higher-level info from them.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
from stacked_cores import load_csv, labeled_rows, last_row_before_t, extract_m
|
||||||
|
from stacked_cores_39xx import extract_polarity
|
||||||
|
|
||||||
|
class MeasRow:
|
||||||
|
def __init__(self, t_sec: float, m: list):
|
||||||
|
self.t_sec = t_sec
|
||||||
|
self.m = m
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
m = ", ".join(f"{v:6}" for v in self.m)
|
||||||
|
return f"MeasRow({self.t_sec}, [{m}])"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_dict(row_data: dict) -> 'MeasRow':
|
||||||
|
t_sec = row_data["time"]
|
||||||
|
m = [int(m + 0.5) for m in extract_m(row_data)]
|
||||||
|
return MeasRow(t_sec, m)
|
||||||
|
|
||||||
|
def format_float_tuple(t: tuple) -> str:
|
||||||
|
formatted_elems = [f"{e:= 05.3f}," for e in t]
|
||||||
|
return f"({' '.join(formatted_elems)})"
|
||||||
|
|
||||||
|
def format_list(l: list) -> str:
|
||||||
|
if len(l) == 0: return "[]"
|
||||||
|
if len(l) == 1: return f"{l}"
|
||||||
|
formatted_elems = [f"\t{e}" for e in l]
|
||||||
|
return "\n".join(["["] + formatted_elems + ["]"])
|
||||||
|
|
||||||
|
def indented(s: str) -> str:
|
||||||
|
return s.replace('\n', '\n\t')
|
||||||
|
|
||||||
|
class ParameterizedMeas:
|
||||||
|
def __init__(self, meas = None):
|
||||||
|
self.meas = meas or {}
|
||||||
|
|
||||||
|
def add_meas(self, params: tuple, meas_rows: list):
|
||||||
|
self.meas[tuple(params)] = meas_rows
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
meas_entries = "\n".join(
|
||||||
|
f"\t{format_float_tuple(k)}: {indented(format_list(v))}," for (k, v) in sorted(self.meas.items())
|
||||||
|
)
|
||||||
|
return f"ParameterizedMeas({{\n{meas_entries}\n}})"
|
||||||
|
|
||||||
|
def extract_rows(path: str, times: list) -> list:
|
||||||
|
header, raw_rows = load_csv(path)
|
||||||
|
rows = labeled_rows(header, raw_rows)
|
||||||
|
|
||||||
|
meas_rows = []
|
||||||
|
for t in times:
|
||||||
|
row = last_row_before_t(rows, t)
|
||||||
|
if not row: return None
|
||||||
|
meas_rows.append(MeasRow.from_dict(row))
|
||||||
|
|
||||||
|
# validate the sim has run to completion
|
||||||
|
if meas_rows[-1].t_sec < 0.95 * t: return None
|
||||||
|
meas_rows[-1].t_sec = t # make pretty
|
||||||
|
|
||||||
|
return meas_rows
|
||||||
|
|
||||||
|
def parse_param(s: str) -> float:
|
||||||
|
""" parse a parameter in the form of 'p050' or 'n0015' or '000' """
|
||||||
|
if s == "000":
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
sign = {'n': -1, 'p': 1}[s[0]]
|
||||||
|
mag = int(s[1:])
|
||||||
|
max_mag = 10**(len(s[1:]) - 1)
|
||||||
|
return sign * mag / max_mag
|
||||||
|
|
||||||
|
def extract_params(pstr: str) -> list:
|
||||||
|
""" extract parameters from a string like -n100-000 """
|
||||||
|
pieces = [p for p in pstr.split("-") if p]
|
||||||
|
return [parse_param(p) for p in pieces]
|
||||||
|
|
||||||
|
def extract_parameterized_meas(stem: str, times: list) -> ParameterizedMeas:
|
||||||
|
""" given some stem, parse all parameterized measurements associated with that stem """
|
||||||
|
base_dir, prefix = os.path.split(stem)
|
||||||
|
|
||||||
|
built = ParameterizedMeas()
|
||||||
|
for entry in os.listdir(base_dir):
|
||||||
|
if entry.startswith(prefix):
|
||||||
|
meas_rows = extract_rows(os.path.join(base_dir, entry, "meas.csv"), times)
|
||||||
|
if not meas_rows: continue
|
||||||
|
params = extract_params(entry[len(prefix):])
|
||||||
|
built.add_meas(params, meas_rows)
|
||||||
|
|
||||||
|
return built
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(extract_parameterized_meas(sys.argv[1], [float(f) for f in sys.argv[2:]]))
|
@@ -1324,6 +1324,25 @@ fn drive_map_fork_then_join_m2_out(amp0: f32) -> [[ClockState; 4]; 3] {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn drive_map_or_gate(amp0: f32, amp1: f32) -> [[ClockState; 4]; 4] {
|
||||||
|
use ClockState as C;
|
||||||
|
// amplitudes are inverted from what you would expect.
|
||||||
|
// hold(-1) puts the core into a positive M
|
||||||
|
[
|
||||||
|
// init S0 pos, S1 pos; charge S2 neg, S3 neg
|
||||||
|
[C::release(-amp0), C::release(-amp1), C::release_high(), C::release_high()],
|
||||||
|
// clear S0 -> S2, S1 -> S2
|
||||||
|
// NB: we might slightly prefer to do this in two separate steps, but doing it in one cycle is
|
||||||
|
// quicker to simulate.
|
||||||
|
[C::hold_high(), C::hold_high(), C::float(), C::float()],
|
||||||
|
// relax S0, S1, so that S2 isn't unnecessarily loaded in the next cycle
|
||||||
|
[C::release_high(), C::release_high(), C::float(), C::float()],
|
||||||
|
// clear S2 -> S3
|
||||||
|
[C::hold_high(), C::hold_high(), C::hold_high(), C::float()],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
fn asymmetric_inverter_name(p: &Params, sim_id: &str, windings: u32, init_flt: f32) -> String {
|
fn asymmetric_inverter_name(p: &Params, sim_id: &str, windings: u32, init_flt: f32) -> String {
|
||||||
let init_int = (init_flt.abs() * 100.0 + 0.5) as u32;
|
let init_int = (init_flt.abs() * 100.0 + 0.5) as u32;
|
||||||
let init_level = if init_flt > 0.0 {
|
let init_level = if init_flt > 0.0 {
|
||||||
@@ -1337,13 +1356,8 @@ fn asymmetric_inverter_name(p: &Params, sim_id: &str, windings: u32, init_flt: f
|
|||||||
let s_major = p.s_major;
|
let s_major = p.s_major;
|
||||||
let coupling_loops = p.coupling_loops;
|
let coupling_loops = p.coupling_loops;
|
||||||
|
|
||||||
let mut input_leading = p.input_magnitude as u64;
|
let input_str = exp_format(p.input_magnitude);
|
||||||
let mut input_exp = 0;
|
format!("{sim_id}-{s_major}rad-{coupling_loops}coupling-{windings}_1_winding-{input_str}-drive-{init_level}")
|
||||||
while input_leading != 0 && input_leading % 10 == 0 {
|
|
||||||
input_leading /= 10;
|
|
||||||
input_exp += 1;
|
|
||||||
}
|
|
||||||
format!("{sim_id}-{s_major}rad-{coupling_loops}coupling-{windings}_1_winding-{input_leading}e{input_exp}-drive-{init_level}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1360,18 +1374,11 @@ fn asymmetric_inverter_name_v2(p: &Params, sim_id: &str, ctl_loops: u32, couplin
|
|||||||
|
|
||||||
let s_major = p.s_major;
|
let s_major = p.s_major;
|
||||||
|
|
||||||
let mut input_leading = p.input_magnitude as u64;
|
let input_str = exp_format(p.input_magnitude);
|
||||||
let mut input_exp = 0;
|
format!("{sim_id}-{s_major}rad-{ctl_loops}ctl-{coupling_loops}coupling-{windings}_1_winding-{input_str}-drive-{init_level}")
|
||||||
while input_leading != 0 && input_leading % 10 == 0 {
|
|
||||||
input_leading /= 10;
|
|
||||||
input_exp += 1;
|
|
||||||
}
|
|
||||||
format!("{sim_id}-{s_major}rad-{ctl_loops}ctl-{coupling_loops}coupling-{windings}_1_winding-{input_leading}e{input_exp}-drive-{init_level}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// v3 has coupling_loops specified externally,
|
fn init_float_str(init_flt: f32) -> String {
|
||||||
/// and encodes conductivities + clocks
|
|
||||||
fn asymmetric_inverter_name_v3(p: &Params, sim_id: &str, ctl_loops: u32, coupling_loops: u32, windings: u32, init_flt: f32) -> String {
|
|
||||||
let init_int = (init_flt.abs() * 1000.0 + 0.5) as u32;
|
let init_int = (init_flt.abs() * 1000.0 + 0.5) as u32;
|
||||||
let init_int_str = if init_int % 10 == 0 {
|
let init_int_str = if init_int % 10 == 0 {
|
||||||
format!("{:03}", init_int / 10)
|
format!("{:03}", init_int / 10)
|
||||||
@@ -1379,13 +1386,29 @@ fn asymmetric_inverter_name_v3(p: &Params, sim_id: &str, ctl_loops: u32, couplin
|
|||||||
format!("{:04}", init_int)
|
format!("{:04}", init_int)
|
||||||
};
|
};
|
||||||
|
|
||||||
let init_level = if init_flt > 0.0 {
|
if init_flt > 0.0 {
|
||||||
format!("p{init_int_str}")
|
format!("p{init_int_str}")
|
||||||
} else if init_flt < 0.0 {
|
} else if init_flt < 0.0 {
|
||||||
format!("n{init_int_str}")
|
format!("n{init_int_str}")
|
||||||
} else {
|
} else {
|
||||||
init_int_str
|
init_int_str
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exp_format(e: f32) -> String {
|
||||||
|
let mut e_leading = e as u64;
|
||||||
|
let mut e_exp = 0;
|
||||||
|
while e_leading != 0 && e_leading % 10 == 0 {
|
||||||
|
e_leading /= 10;
|
||||||
|
e_exp += 1;
|
||||||
|
}
|
||||||
|
format!("{}e{}", e_leading, e_exp)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// v3 has coupling_loops specified externally,
|
||||||
|
/// and encodes conductivities + clocks
|
||||||
|
fn asymmetric_inverter_name_v3(p: &Params, sim_id: &str, ctl_loops: u32, coupling_loops: u32, windings: u32, init_flt: f32) -> String {
|
||||||
|
let init_level = init_float_str(init_flt);
|
||||||
|
|
||||||
let s_major = p.s_major;
|
let s_major = p.s_major;
|
||||||
let ctl_cond = p.ctl_conductivity as u64;
|
let ctl_cond = p.ctl_conductivity as u64;
|
||||||
@@ -1393,13 +1416,22 @@ fn asymmetric_inverter_name_v3(p: &Params, sim_id: &str, ctl_loops: u32, couplin
|
|||||||
let clock_length = (p.clock_phase_duration * 1e12 + 0.5) as u64;
|
let clock_length = (p.clock_phase_duration * 1e12 + 0.5) as u64;
|
||||||
let clock_decay = (p.clock_decay * 1e12 + 0.5) as u64;
|
let clock_decay = (p.clock_decay * 1e12 + 0.5) as u64;
|
||||||
|
|
||||||
let mut input_leading = p.input_magnitude as u64;
|
let input_str = exp_format(p.input_magnitude);
|
||||||
let mut input_exp = 0;
|
format!("{sim_id}-{s_major}rad-{ctl_cond}ctl_cond-{coupling_cond}coupling_cond-{clock_length}ps-{clock_decay}ps-{ctl_loops}ctl-{coupling_loops}coupling-{windings}_1_winding-{input_str}-drive-{init_level}")
|
||||||
while input_leading != 0 && input_leading % 10 == 0 {
|
}
|
||||||
input_leading /= 10;
|
|
||||||
input_exp += 1;
|
fn asymmetric_binary_gate_name(p: &Params, sim_id: &str, ctl_loops: u32, coupling_loops: u32, windings: u32, init_flt_a: f32, init_flt_b: f32) -> String {
|
||||||
}
|
let init_level_a = init_float_str(init_flt_a);
|
||||||
format!("{sim_id}-{s_major}rad-{ctl_cond}ctl_cond-{coupling_cond}coupling_cond-{clock_length}ps-{clock_decay}ps-{ctl_loops}ctl-{coupling_loops}coupling-{windings}_1_winding-{input_leading}e{input_exp}-drive-{init_level}")
|
let init_level_b = init_float_str(init_flt_b);
|
||||||
|
|
||||||
|
let s_major = p.s_major;
|
||||||
|
let ctl_cond = p.ctl_conductivity as u64;
|
||||||
|
let coupling_cond = p.coupling_conductivity as u64;
|
||||||
|
let clock_length = (p.clock_phase_duration * 1e12 + 0.5) as u64;
|
||||||
|
let clock_decay = (p.clock_decay * 1e12 + 0.5) as u64;
|
||||||
|
|
||||||
|
let input_str = exp_format(p.input_magnitude);
|
||||||
|
format!("{sim_id}-{s_major}rad-{ctl_cond}ctl_cond-{coupling_cond}coupling_cond-{clock_length}ps-{clock_decay}ps-{ctl_loops}ctl-{coupling_loops}coupling-{windings}_1_winding-{input_str}-drive-{init_level_a}-{init_level_b}")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// couple `sender` to the `sender+1` core by using `loops` loops, including a crossover so that
|
/// couple `sender` to the `sender+1` core by using `loops` loops, including a crossover so that
|
||||||
@@ -5135,7 +5167,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if true {
|
if false {
|
||||||
for init_set in [
|
for init_set in [
|
||||||
&[
|
&[
|
||||||
// targeted for (5e2, 5e3, ps(1000), ps(50), 9, 1, um(400), 1e10)
|
// targeted for (5e2, 5e3, ps(1000), ps(50), 9, 1, um(400), 1e10)
|
||||||
@@ -5647,6 +5679,74 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if true {
|
||||||
|
for init_set in [
|
||||||
|
&[
|
||||||
|
// targeted
|
||||||
|
][..],
|
||||||
|
&[
|
||||||
|
// establish the domain/range
|
||||||
|
( 1.00, 1.00),
|
||||||
|
(-1.00, -1.00),
|
||||||
|
(-1.00, 1.00),
|
||||||
|
( 1.00, -1.00),
|
||||||
|
][..],
|
||||||
|
&[
|
||||||
|
(0.00, 0.00),
|
||||||
|
(-1.00, 0.00),
|
||||||
|
][..],
|
||||||
|
] {
|
||||||
|
for (ctl_cond, coupling_cond, clock_duration, clock_decay, coupling_loops, s0_loops, s_major, cur_flt) in [
|
||||||
|
(5e3, 2e4, ps(2000), ps(100), 3, 1, um(400), 5e10),
|
||||||
|
(5e2, 2e4, ps(2000), ps(100), 3, 1, um(400), 5e10),
|
||||||
|
|
||||||
|
(1e3, 2e4, ps(2000), ps(100), 3, 1, um(400), 2e10),
|
||||||
|
(2e3, 2e4, ps(2000), ps(100), 3, 1, um(400), 1e10),
|
||||||
|
(2e3, 2e4, ps(2000), ps(100), 3, 1, um(400), 2e10),
|
||||||
|
(2e3, 2e4, ps(2000), ps(100), 3, 1, um(400), 3e10),
|
||||||
|
(5e3, 2e4, ps(2000), ps(100), 3, 1, um(400), 3e10),
|
||||||
|
|
||||||
|
] {
|
||||||
|
for &(init_flt_a, init_flt_b) in init_set {
|
||||||
|
// coupling loops (M0 -> M2) + (M1 -> M2) + (M2 -> M3) + control slots
|
||||||
|
let slots_per_asym = 2*s0_loops;
|
||||||
|
let net_slots = 3*slots_per_asym + 1;
|
||||||
|
let mut params = params_v2
|
||||||
|
.with_clock_phase_duration(clock_duration)
|
||||||
|
.with_clock_decay(clock_decay)
|
||||||
|
.with_ctl_conductivity(ctl_cond)
|
||||||
|
.with_coupling_conductivity(coupling_cond)
|
||||||
|
.with_s_major(s_major)
|
||||||
|
.with_coupling_loops(coupling_loops)
|
||||||
|
.with_input_magnitude(cur_flt)
|
||||||
|
// control loops
|
||||||
|
.with_coupling(0, 0, 0, net_slots, CouplingMethod::Control)
|
||||||
|
.with_coupling(1, 1, 0, net_slots, CouplingMethod::Control)
|
||||||
|
.with_coupling(2, 2, 0, net_slots, CouplingMethod::Control)
|
||||||
|
.with_coupling(3, 3, 0, net_slots, CouplingMethod::Control)
|
||||||
|
;
|
||||||
|
for i in 0..slots_per_asym {
|
||||||
|
// couple input core 0 to core 2
|
||||||
|
params = params.with_coupling(0, 2, 1+i, net_slots, CouplingMethod::Outside);
|
||||||
|
// couple input core 1 to core 2
|
||||||
|
params = params.with_coupling(1, 2, 1+i + slots_per_asym, net_slots, CouplingMethod::Direct);
|
||||||
|
}
|
||||||
|
// couple OR gate core 2 to output core 3
|
||||||
|
params = couple_asymmetric_buffer(¶ms, 2 /* sender core */, s0_loops, 1 + 2*slots_per_asym /* slot offset */, net_slots);
|
||||||
|
|
||||||
|
let name = asymmetric_binary_gate_name(
|
||||||
|
¶ms, "52-or-", coupling_loops /* ctl loops */, coupling_loops, 2*s0_loops + 1, init_flt_a, init_flt_b
|
||||||
|
);
|
||||||
|
run_sim(
|
||||||
|
&name,
|
||||||
|
drive_map_or_gate(init_flt_a, init_flt_b),
|
||||||
|
params,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user