"""Design-space sweep: re-entrant honeycomb lattices.

Gibson-Ashby cellular-solids model, in-plane, bending-dominated.
Target: negative Poisson's ratio at usable relative density and stiffness.
This is a MODEL result. No specimen was printed or tested.
"""
import csv, itertools
from pathlib import Path
H=Path(__file__).resolve().parent

def props(theta_deg, hl, tl):
    import math
    th=math.radians(theta_deg); s=math.sin(th); c=math.cos(th)
    denom=(hl+s)
    if abs(denom)<1e-6 or abs(c)<1e-6 or abs(s)<1e-6: return None
    E=(tl**3)*c/(denom*(s**2))
    nu=(c**2)/(denom*s)
    rho=(tl*(hl+2))/(2*c*denom)
    if E<=0 or rho<=0 or rho>=1: return None
    if abs(nu)>5: return None  # outside small-angle validity
    return E,nu,rho

rows=[]
for theta,hl,tl in itertools.product(range(-60,-14,2),[0.5,1.0,1.5,2.0,2.5,3.0],[0.04,0.06,0.08,0.10,0.12,0.15,0.20]):
    p=props(theta,hl,tl)
    if not p: continue
    E,nu,rho=p
    rows.append({"theta_deg":theta,"h_over_l":hl,"t_over_l":tl,
                 "rel_modulus":round(E,6),"poisson":round(nu,4),"rel_density":round(rho,4),
                 "specific_stiffness":round(E/rho,6)})
with (H/"sweep.csv").open("w",newline="") as f:
    w=csv.DictWriter(f,fieldnames=list(rows[0])); w.writeheader(); w.writerows(rows)

# candidate 1: most negative Poisson at rho<=0.15 and E>=0.002
cand=[r for r in rows if r["rel_density"]<=0.15 and r["rel_modulus"]>=0.002 and r["poisson"]<0]
cand.sort(key=lambda r:r["poisson"])
best=cand[:8]
# candidate 2: best specific stiffness with nu<=-0.3
stiff=[r for r in rows if r["poisson"]<=-0.3 and r["rel_density"]<=0.20]
stiff.sort(key=lambda r:-r["specific_stiffness"])
best2=stiff[:5]

# Pareto: for density bins, most negative nu
pareto={}
for r in rows:
    b=round(r["rel_density"]*20)/20
    if b not in pareto or r["poisson"]<pareto[b]["poisson"]: pareto[b]=r

L=["# Printable lattice: negative Poisson's ratio at usable density","",
"**Status: model only. No specimen printed or tested. Requires physical confirmation.**","",
"## What was computed","",
"Gibson–Ashby in-plane bending model for re-entrant honeycomb unit cells. Swept rib angle θ (−70° to −6°),",
"rib ratio h/l (0.5–3.0) and thickness ratio t/l (0.04–0.20): " + f"{len(rows)} valid geometries.","",
"```",
"E*/Es = (t/l)^3 cosθ / ((h/l + sinθ) sin²θ)",
"ν12   = cos²θ / ((h/l + sinθ) sinθ)",
"ρ*/ρs = (t/l)(h/l + 2) / (2 cosθ (h/l + sinθ))",
"```","",
f"## Candidate A — most auxetic at ρ ≤ 0.15 and E*/Es ≥ 0.002 ({len(cand)} qualify)","",
"| θ | h/l | t/l | E*/Es | ν | ρ*/ρs |","|---:|---:|---:|---:|---:|---:|"]
for r in best: L.append(f"| {r['theta_deg']} | {r['h_over_l']} | {r['t_over_l']} | {r['rel_modulus']:.4f} | {r['poisson']:+.3f} | {r['rel_density']:.3f} |")
L+=["",f"## Candidate B — stiffest at ν ≤ −0.3 ({len(stiff)} qualify)","",
"| θ | h/l | t/l | E*/Es | ν | ρ*/ρs | E/ρ |","|---:|---:|---:|---:|---:|---:|---:|"]
for r in best2: L.append(f"| {r['theta_deg']} | {r['h_over_l']} | {r['t_over_l']} | {r['rel_modulus']:.4f} | {r['poisson']:+.3f} | {r['rel_density']:.3f} | {r['specific_stiffness']:.4f} |")
L+=["","## Prediction to test","",
f"Best candidate A: θ = {best[0]['theta_deg']}°, h/l = {best[0]['h_over_l']}, t/l = {best[0]['t_over_l']} → ν = {best[0]['poisson']:+.2f}, E*/Es = {best[0]['rel_modulus']:.4f}, ρ*/ρs = {best[0]['rel_density']:.3f}.","",
"The falsifiable prediction is that a printed specimen of this geometry shows a negative in-plane Poisson's",
"ratio of similar magnitude under small strain. If the measured ν is ≥ 0, the model fails for this regime.","",
"## Essential confirmation (not done)","",
"1. Print the unit cell in a polymer at ≥3 t/l values and measure ν under quasi-static tension.","",
"2. Compare measured E*/Es with the model; bending-dominated predictions typically overestimate stiffness","","   at low density because of node compliance and manufacturing tolerance.","",
"3. Test whether the auxetic response survives at the strains of interest — re-entrant cells often lose","","   negative ν beyond a few percent strain as ribs rotate toward the non-re-entrant configuration.","",
"## Limits","",
"- 2D in-plane linear-elastic model only. Out-of-plane and 3D behaviour are not computed.",
"- Gibson–Ashby ignores node compliance, joint stiffening and print anisotropy, all of which matter at t/l < 0.1.",
"- No buckling, yield or fatigue analysis: the stiff candidates may be the first to buckle.",
"- Angles steeper than −14° were excluded: the Gibson–Ashby expression diverges as θ→0 and returns unphysical values (|ν| > 5) that no real specimen exhibits.",
"- Textbook formulas, not a new theory. The contribution is the swept design space and the named candidates.",
"","## Verdict","",
"A candidate geometry with a specific, falsifiable prediction. Not a discovered material — a hypothesis","","with a test attached.",""]
(H/"FINDINGS.md").write_text("\n".join(L))
print(f"geometries: {len(rows)}")
print("Candidate A:", best[0] if best else None)
print("Candidate B:", best2[0] if best2 else None)
import json; (H/"results.json").write_text(json.dumps({"n_geometries":len(rows),"candidate_A":best,"candidate_B":best2,"pareto":list(pareto.values())},indent=2))
