#!/usr/bin/env python3
"""Recompute generated cell-to-atom scale comparisons with Python's standard library.
Adopted lengths and display cutoffs are not specimen measurements or microscope resolution.
"""
import argparse,csv,hashlib,json,math,sys
from pathlib import Path
PREFIX_URL='https://www.bipm.org/en/measurement-units/si-prefixes'
CELL_URL='https://openstax.org/books/biology-2e/pages/4-2-prokaryotic-cells'
REFS=[('micrometer',1e-6,'m','exact_prefix',PREFIX_URL),('nanometer',1e-9,'m','exact_prefix',PREFIX_URL),('picometer',1e-12,'m','exact_prefix',PREFIX_URL),('inch',.0254,'m','exact_conversion','https://www.nist.gov/pml/owm/si-units-length'),('cell_diameter',20,'um','adopted_teaching_value',CELL_URL),('mitochondrion_length',2,'um','adopted_teaching_value','https://pmc.ncbi.nlm.nih.gov/articles/PMC10932015/'),('atomic_extent',.1,'nm','adopted_teaching_reference',CELL_URL)]
CASES=[('A',20,2,.1,50e-6),('B',20,2,.1,5e-6),('C',20,2,.1,.5e-9),('D',40,2,.1,50e-6)]
OBJECTS=['cell','mitochondrion','atomic-reference']
def require(test,message):
    if not test:raise ValueError(message)
def close(a,b):return math.isfinite(a) and math.isclose(a,b,rel_tol=3e-14,abs_tol=1e-18)
def analyze(folder):
    ref_file=folder/'reference-inputs.csv';data_file=folder/'generated-scale-cases.csv'
    refs=list(csv.DictReader(ref_file.open(newline='',encoding='utf-8')));rows=list(csv.DictReader(data_file.open(newline='',encoding='utf-8')))
    require(len(refs)==7,'Expected seven pinned reference rows');require(len(rows)==12,'Expected twelve generated object rows');values={}
    for row,(key,value,unit,kind,url) in zip(refs,REFS):
        require(row['quantity']==key and float(row['reference_value'])==value and row['unit']==unit and row['reference_kind']==kind and row['source_url']==url,'Reference transcription mismatch');values[key]=value
    results=[]
    for i,(case,cell,mito,atom,field) in enumerate(CASES):
        lengths=[cell*values['micrometer'],mito*values['micrometer'],atom*values['nanometer']];objects=[]
        for j,name in enumerate(OBJECTS):
            row=rows[3*i+j];require(row['case_id']==case and row['object']==name,'Case/object identity mismatch')
            require(float(row['cell_um'])==cell and float(row['mito_um'])==mito and float(row['atom_nm'])==atom,'Adopted dimension mismatch')
            zoom=math.log10(field);actual_field=10**zoom;width=lengths[j]/actual_field*360;state='small' if width<1 else 'large' if width>720 else 'visible'
            expected={'field_m':actual_field,'zoom_log10_m':zoom,'object_m':lengths[j],'object_inches':lengths[j]/values['inch'],'drawn_width':width}
            for key,value in expected.items():require(close(float(row[key]),value),'Generated value mismatch: '+key)
            require(row['display_state']==state,'Display-state mismatch');objects.append(dict(object=name,lengthM=lengths[j],lengthInches=lengths[j]/values['inch'],drawnWidthUnits=width,displayState=state))
        ratios=[lengths[0]/lengths[1],lengths[0]/lengths[2],lengths[1]/lengths[2]]
        results.append(dict(case=case,cellUm=cell,mitochondrionUm=mito,atomicNm=atom,nominalFieldM=field,modelFieldM=10**math.log10(field),zoomLog10M=math.log10(field),ratios=dict(cellToMitochondrion=ratios[0],cellToAtomicReference=ratios[1],mitochondrionToAtomicReference=ratios[2]),objects=objects))
    for i in [1,2]:
        for key,value in results[0]['ratios'].items():require(close(results[i]['ratios'][key],value),'Zoom changed a physical ratio')
    return dict(methodVersion='1.0',resourceRelease='270',activity='https://darksciencedocs.com/exploration-guides/cell-to-atom/',sourceReviewDate='2026-10-25',provenance='Chosen teaching lengths and generated scale drawings; not microscopy, specimen measurements, molecular counts or quantum probability maps. Paper/reference fields are nominal 50um/5um/0.5nm; the live logarithmic slider rounds to 0.001 exponent steps.',constants=dict(micrometerM=values['micrometer'],nanometerM=values['nanometer'],picometerM=values['picometer'],inchM=values['inch'],diagramWidthUnits=360,smallCutoffUnits=1,largeCutoffUnits=720),cases=results,comparisons=dict(cell20UmInNm=20000,cellToAtomicReference=200000,fieldAtoBReduction=10,drawnWidthAtoBIncrease=10,caseDCellToMitochondrion=20,caseDCellToAtomicReference=400000),checks=dict(referenceSha256=hashlib.sha256(ref_file.read_bytes()).hexdigest(),generatedCasesSha256=hashlib.sha256(data_file.read_bytes()).hexdigest(),lengthsInchesRatiosZoomAndDisplayStatesAgree=True),limits='Chosen cell diameter, mitochondrial length and atomic characteristic extent are illustrative, not universal sizes. Ratios compare one linear dimension only, not counts or volume occupancy. Shapes/colors/internal folds are artistic. Atomic extent has no hard edge and glow has no measured probability meaning. Display thresholds are UI rules, not optical or electron-microscope resolution. Zoom does not change physical sizes; editing a dimension changes the adopted model. No independent scientific review or formal curriculum alignment claimed.')
def main():
    p=argparse.ArgumentParser(description=__doc__);p.add_argument('--data-dir',type=Path,default=Path('.'));args=p.parse_args()
    try:print(json.dumps(analyze(args.data_dir),indent=2,allow_nan=False))
    except (OSError,ValueError,KeyError,ZeroDivisionError) as error:print('Verification failed: '+str(error),file=sys.stderr);return 1
    return 0
if __name__=='__main__':sys.exit(main())
