from __future__ import annotations import logging from pathlib import Path import sys sys.path.insert(0, str(Path(__file__).parent.parent / "src")) from pino.registry import AromaRegistry logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") logger = logging.getLogger("build_registry") # Curated list of ~150 common fragrance materials. Approximate room-temperature # vapor pressures (Pa), boiling points (K), and odor thresholds (ug/m3) are # literature estimates. Natural oils are included as multi-component entries; # they may fail fragmentation, which is acceptable because the registry # builder skips unresolvable entries. AROMA_CHEMICALS = [ # Solvents / carriers {"cas": "64-17-5", "vapor_pressure_pa": 7900.0, "boiling_point_k": 351.45, "odor_threshold_ug_m3": 250000.0}, {"cas": "67-63-0", "vapor_pressure_pa": 5700.0, "boiling_point_k": 355.5, "odor_threshold_ug_m3": 400000.0}, {"cas": "25265-71-8", "vapor_pressure_pa": 1.0, "boiling_point_k": 503.0, "odor_threshold_ug_m3": 5000.0}, {"cas": "120-51-4", "vapor_pressure_pa": 0.02, "boiling_point_k": 597.0, "odor_threshold_ug_m3": 50.0}, {"cas": "84-66-2", "vapor_pressure_pa": 0.002, "boiling_point_k": 568.0, "odor_threshold_ug_m3": 100.0}, # Citrus / terpenes {"cas": "5989-27-5", "vapor_pressure_pa": 195.0, "boiling_point_k": 449.0, "odor_threshold_ug_m3": 30.0}, {"cas": "138-86-3", "vapor_pressure_pa": 195.0, "boiling_point_k": 449.0, "odor_threshold_ug_m3": 30.0}, {"cas": "5392-40-5", "vapor_pressure_pa": 25.0, "boiling_point_k": 501.0, "odor_threshold_ug_m3": 5.0}, {"cas": "106-24-1", "vapor_pressure_pa": 2.0, "boiling_point_k": 503.0, "odor_threshold_ug_m3": 10.0}, {"cas": "106-25-2", "vapor_pressure_pa": 2.0, "boiling_point_k": 503.0, "odor_threshold_ug_m3": 10.0}, {"cas": "106-22-9", "vapor_pressure_pa": 1.0, "boiling_point_k": 493.0, "odor_threshold_ug_m3": 5.0}, {"cas": "624-15-7", "vapor_pressure_pa": 1.5, "boiling_point_k": 503.0, "odor_threshold_ug_m3": 10.0}, {"cas": "111-71-7", "vapor_pressure_pa": 12.0, "boiling_point_k": 477.0, "odor_threshold_ug_m3": 10.0}, {"cas": "99-85-4", "vapor_pressure_pa": 160.0, "boiling_point_k": 446.0, "odor_threshold_ug_m3": 50.0}, {"cas": "68647-72-3", "vapor_pressure_pa": 55.0, "boiling_point_k": 453.0, "odor_threshold_ug_m3": 30.0}, {"cas": "93-58-3", "vapor_pressure_pa": 14.0, "boiling_point_k": 472.0, "odor_threshold_ug_m3": 10.0}, {"cas": "115-95-7", "vapor_pressure_pa": 0.1, "boiling_point_k": 498.0, "odor_threshold_ug_m3": 1.0}, {"cas": "105-87-3", "vapor_pressure_pa": 1.0, "boiling_point_k": 493.0, "odor_threshold_ug_m3": 5.0}, {"cas": "150-84-5", "vapor_pressure_pa": 1.0, "boiling_point_k": 493.0, "odor_threshold_ug_m3": 5.0}, {"cas": "140-11-4", "vapor_pressure_pa": 2.0, "boiling_point_k": 486.0, "odor_threshold_ug_m3": 10.0}, {"cas": "103-45-7", "vapor_pressure_pa": 0.5, "boiling_point_k": 499.0, "odor_threshold_ug_m3": 5.0}, # Floral alcohols / aldehydes {"cas": "78-70-6", "vapor_pressure_pa": 22.0, "boiling_point_k": 471.0, "odor_threshold_ug_m3": 6.0}, {"cas": "60-12-8", "vapor_pressure_pa": 3.0, "boiling_point_k": 488.0, "odor_threshold_ug_m3": 10.0}, {"cas": "100-51-6", "vapor_pressure_pa": 5.0, "boiling_point_k": 478.0, "odor_threshold_ug_m3": 20.0}, {"cas": "104-54-1", "vapor_pressure_pa": 1.0, "boiling_point_k": 516.0, "odor_threshold_ug_m3": 10.0}, {"cas": "104-55-2", "vapor_pressure_pa": 2.0, "boiling_point_k": 531.0, "odor_threshold_ug_m3": 5.0}, {"cas": "124-13-0", "vapor_pressure_pa": 120.0, "boiling_point_k": 421.0, "odor_threshold_ug_m3": 50.0}, {"cas": "112-31-2", "vapor_pressure_pa": 18.0, "boiling_point_k": 480.0, "odor_threshold_ug_m3": 10.0}, {"cas": "112-54-9", "vapor_pressure_pa": 1.5, "boiling_point_k": 520.0, "odor_threshold_ug_m3": 1.0}, {"cas": "122-40-7", "vapor_pressure_pa": 0.8, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 1.0}, {"cas": "101-86-0", "vapor_pressure_pa": 0.1, "boiling_point_k": 548.0, "odor_threshold_ug_m3": 0.5}, {"cas": "80-54-6", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 1.0}, {"cas": "31906-04-4", "vapor_pressure_pa": 0.05, "boiling_point_k": 533.0, "odor_threshold_ug_m3": 0.5}, # Jasmine / muguet / ionones {"cas": "24851-98-7", "vapor_pressure_pa": 1.2, "boiling_point_k": 548.0, "odor_threshold_ug_m3": 1.0}, {"cas": "1211-29-0", "vapor_pressure_pa": 0.05, "boiling_point_k": 573.0, "odor_threshold_ug_m3": 0.2}, {"cas": "18871-14-9", "vapor_pressure_pa": 0.3, "boiling_point_k": 573.0, "odor_threshold_ug_m3": 0.5}, {"cas": "127-41-3", "vapor_pressure_pa": 0.2, "boiling_point_k": 518.0, "odor_threshold_ug_m3": 0.5}, {"cas": "14901-07-6", "vapor_pressure_pa": 0.2, "boiling_point_k": 518.0, "odor_threshold_ug_m3": 0.5}, {"cas": "127-51-5", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 0.3}, {"cas": "1335-46-2", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 0.3}, {"cas": "23726-91-0", "vapor_pressure_pa": 0.05, "boiling_point_k": 533.0, "odor_threshold_ug_m3": 0.1}, {"cas": "43052-87-5", "vapor_pressure_pa": 0.05, "boiling_point_k": 533.0, "odor_threshold_ug_m3": 0.1}, {"cas": "706-14-9", "vapor_pressure_pa": 1.0, "boiling_point_k": 450.0, "odor_threshold_ug_m3": 5.0}, {"cas": "713-95-1", "vapor_pressure_pa": 0.2, "boiling_point_k": 478.0, "odor_threshold_ug_m3": 1.0}, # Musks {"cas": "1222-05-5", "vapor_pressure_pa": 0.05, "boiling_point_k": 623.0, "odor_threshold_ug_m3": 0.1}, {"cas": "21145-77-7", "vapor_pressure_pa": 0.01, "boiling_point_k": 593.0, "odor_threshold_ug_m3": 0.05}, {"cas": "6790-58-5", "vapor_pressure_pa": 0.01, "boiling_point_k": 573.0, "odor_threshold_ug_m3": 0.02}, {"cas": "54464-57-2", "vapor_pressure_pa": 0.01, "boiling_point_k": 573.0, "odor_threshold_ug_m3": 0.05}, {"cas": "81-14-1", "vapor_pressure_pa": 0.004, "boiling_point_k": 613.0, "odor_threshold_ug_m3": 0.02}, {"cas": "81-15-2", "vapor_pressure_pa": 0.001, "boiling_point_k": 603.0, "odor_threshold_ug_m3": 0.05}, {"cas": "105-95-3", "vapor_pressure_pa": 0.003, "boiling_point_k": 573.0, "odor_threshold_ug_m3": 0.02}, {"cas": "541-91-3", "vapor_pressure_pa": 0.02, "boiling_point_k": 600.0, "odor_threshold_ug_m3": 0.05}, {"cas": "83-66-9", "vapor_pressure_pa": 0.001, "boiling_point_k": 583.0, "odor_threshold_ug_m3": 0.05}, # Woods / ambers {"cas": "77-53-2", "vapor_pressure_pa": 0.5, "boiling_point_k": 549.0, "odor_threshold_ug_m3": 1.0}, {"cas": "77-42-9", "vapor_pressure_pa": 0.3, "boiling_point_k": 553.0, "odor_threshold_ug_m3": 1.0}, {"cas": "19870-74-7", "vapor_pressure_pa": 0.05, "boiling_point_k": 563.0, "odor_threshold_ug_m3": 0.5}, {"cas": "32388-55-9", "vapor_pressure_pa": 0.05, "boiling_point_k": 563.0, "odor_threshold_ug_m3": 0.5}, {"cas": "33704-61-9", "vapor_pressure_pa": 0.01, "boiling_point_k": 573.0, "odor_threshold_ug_m3": 0.2}, {"cas": "198404-98-7", "vapor_pressure_pa": 0.005, "boiling_point_k": 583.0, "odor_threshold_ug_m3": 0.1}, {"cas": "115-71-9", "vapor_pressure_pa": 1.5, "boiling_point_k": 477.0, "odor_threshold_ug_m3": 5.0}, {"cas": "87-44-5", "vapor_pressure_pa": 6.0, "boiling_point_k": 447.0, "odor_threshold_ug_m3": 10.0}, # Spicy / gourmand {"cas": "97-53-0", "vapor_pressure_pa": 2.0, "boiling_point_k": 527.0, "odor_threshold_ug_m3": 5.0}, {"cas": "97-54-1", "vapor_pressure_pa": 0.5, "boiling_point_k": 543.0, "odor_threshold_ug_m3": 1.0}, {"cas": "121-33-5", "vapor_pressure_pa": 0.01, "boiling_point_k": 558.0, "odor_threshold_ug_m3": 0.2}, {"cas": "91-64-5", "vapor_pressure_pa": 0.05, "boiling_point_k": 574.0, "odor_threshold_ug_m3": 0.5}, {"cas": "120-57-0", "vapor_pressure_pa": 0.1, "boiling_point_k": 531.0, "odor_threshold_ug_m3": 1.0}, {"cas": "119-36-8", "vapor_pressure_pa": 8.0, "boiling_point_k": 449.0, "odor_threshold_ug_m3": 50.0}, {"cas": "118-58-1", "vapor_pressure_pa": 0.01, "boiling_point_k": 586.0, "odor_threshold_ug_m3": 5.0}, {"cas": "90-05-1", "vapor_pressure_pa": 5.0, "boiling_point_k": 477.0, "odor_threshold_ug_m3": 10.0}, {"cas": "120-72-9", "vapor_pressure_pa": 0.5, "boiling_point_k": 540.0, "odor_threshold_ug_m3": 0.5}, {"cas": "83-34-1", "vapor_pressure_pa": 0.5, "boiling_point_k": 540.0, "odor_threshold_ug_m3": 0.5}, {"cas": "134-20-3", "vapor_pressure_pa": 0.05, "boiling_point_k": 546.0, "odor_threshold_ug_m3": 0.5}, {"cas": "103-82-2", "vapor_pressure_pa": 0.05, "boiling_point_k": 553.0, "odor_threshold_ug_m3": 1.0}, # Naturals (may fail fragmentation; registry builder will skip them) {"cas": "8000-27-9", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8006-90-4", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8008-57-9", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8008-56-8", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8007-75-8", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8000-28-0", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8014-09-3", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8016-96-4", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8006-87-9", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8002-73-1", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8022-96-6", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8006-81-3", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8000-46-2", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8014-17-3", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8016-38-4", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8007-01-0", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8000-48-4", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8000-25-7", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "68647-73-4", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8006-78-8", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8000-34-8", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8007-08-7", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8006-84-6", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8007-70-3", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8007-02-1", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8000-29-1", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8006-75-5", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8008-31-9", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8008-79-5", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8000-66-6", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8002-66-2", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8015-91-6", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8008-45-5", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8006-82-4", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8016-20-4", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8008-26-2", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "72968-86-0", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8015-73-4", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8022-56-8", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8007-46-3", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8007-11-2", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8014-71-9", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8024-12-2", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "68855-99-2", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "68606-83-1", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8023-91-4", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8023-89-9", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8016-36-2", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8016-37-3", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8046-42-0", "vapor_pressure_pa": 0.2, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "9000-05-9", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "9000-50-4", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "68606-12-6", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8024-08-6", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "9000-64-0", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8007-00-9", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "90045-23-1", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "89958-31-6", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8023-75-2", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8031-03-6", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "8024-05-3", "vapor_pressure_pa": 0.1, "boiling_point_k": 523.0, "odor_threshold_ug_m3": 50.0}, {"cas": "76-22-2", "vapor_pressure_pa": 10.0, "boiling_point_k": 481.0, "odor_threshold_ug_m3": 50.0}, {"cas": "2216-51-5", "vapor_pressure_pa": 5.0, "boiling_point_k": 489.0, "odor_threshold_ug_m3": 50.0}, {"cas": "16409-43-1", "vapor_pressure_pa": 0.5, "boiling_point_k": 480.0, "odor_threshold_ug_m3": 5.0}, {"cas": "6259-76-3", "vapor_pressure_pa": 0.05, "boiling_point_k": 533.0, "odor_threshold_ug_m3": 5.0}, {"cas": "4602-84-0", "vapor_pressure_pa": 0.001, "boiling_point_k": 543.0, "odor_threshold_ug_m3": 0.5}, {"cas": "7212-44-4", "vapor_pressure_pa": 0.001, "boiling_point_k": 543.0, "odor_threshold_ug_m3": 0.5}, {"cas": "515-69-5", "vapor_pressure_pa": 0.001, "boiling_point_k": 543.0, "odor_threshold_ug_m3": 0.5}, {"cas": "5986-55-0", "vapor_pressure_pa": 0.001, "boiling_point_k": 543.0, "odor_threshold_ug_m3": 0.5}, {"cas": "515-03-7", "vapor_pressure_pa": 0.001, "boiling_point_k": 543.0, "odor_threshold_ug_m3": 0.5}, {"cas": "7779-50-2", "vapor_pressure_pa": 0.001, "boiling_point_k": 573.0, "odor_threshold_ug_m3": 0.5}, {"cas": "104-67-6", "vapor_pressure_pa": 0.3, "boiling_point_k": 480.0, "odor_threshold_ug_m3": 1.0}, {"cas": "104-61-0", "vapor_pressure_pa": 0.3, "boiling_point_k": 480.0, "odor_threshold_ug_m3": 1.0}, ] logger.info("Starting registry build with %d entries", len(AROMA_CHEMICALS)) with AromaRegistry() as registry: failed = registry.populate(AROMA_CHEMICALS, skip_failures=True) count = registry._conn.execute( "SELECT COUNT(*) FROM aroma_chemicals" ).fetchone()[0] logger.info("Registry built: %d entries, %d failures", count, len(failed)) if failed: logger.warning("Failed entries: %s", [f["cas"] for f in failed])