{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://schemas.optics-design.com/glamac/v0.1/glamac.schema.json",
  "title": "Unified Optical Glass Data Schema",
  "description": "GlaMaC unified optical-glass catalog format, version 0.1. Covers SCHOTT, HOYA, CDGM and OHARA; includes full mechanical/thermal/chemical extraction, native per-manufacturer chemical classes, coloring/CCI/chromaticity, provenance, and raw fine-grained dn/dT & CTE tables. The keys the native loader reads (dispersion_formula, temperature_coefficients, internal_transmittance) keep their established shape.",
  "type": "object",
  "required": ["schema_version"],
  "oneOf": [
    { "required": ["glasses"] },
    { "required": ["catalogs"] }
  ],
  "additionalProperties": false,
  "properties": {
    "$schema": { "type": "string" },
    "schema_version": { "type": "string", "const": "0.1" },
    "generated": { "type": "string", "format": "date-time" },
    "generator": { "type": "string" },
    "source": { "$ref": "#/definitions/source" },
    "glasses": { "$ref": "#/definitions/glasses" },
    "catalogs": {
      "type": "object",
      "description": "Per-manufacturer sub-catalogs (merged-file format)",
      "additionalProperties": {
        "type": "object",
        "required": ["source", "glasses"],
        "additionalProperties": false,
        "properties": {
          "source": { "$ref": "#/definitions/source" },
          "glasses": { "$ref": "#/definitions/glasses" }
        }
      }
    }
  },
  "definitions": {
    "source": {
      "type": "object",
      "required": ["manufacturer"],
      "additionalProperties": false,
      "properties": {
        "manufacturer": {
          "type": "string",
          "minLength": 1,
          "description": "Catalog manufacturer name. Any non-empty name is valid; SCHOTT, HOYA, CDGM, OHARA are the catalogs GlaMaC currently ships."
        },
        "source_file": { "type": "string" },
        "source_date": { "type": "string" },
        "source_file_sha256": { "type": "string", "pattern": "^[0-9a-fA-F]{64}$" },
        "source_files": {
          "type": "array",
          "description": "Per-file provenance for multi-file catalogs (e.g. OHARA)",
          "minItems": 1,
          "items": {
            "type": "object",
            "required": ["source_file", "source_file_sha256"],
            "additionalProperties": false,
            "properties": {
              "source_file": { "type": "string" },
              "source_file_sha256": { "type": "string", "pattern": "^[0-9a-fA-F]{64}$" }
            }
          }
        },
        "sheet": { "type": "string" }
      }
    },
    "glasses": {
      "type": "object",
      "description": "Glass entries keyed by glass name",
      "additionalProperties": { "$ref": "#/definitions/glass" }
    },
    "glass": {
      "type": "object",
      "required": ["nd", "vd"],
      "additionalProperties": false,
      "properties": {
        "nd": { "type": "number", "exclusiveMinimum": 0 },
        "vd": { "type": "number", "exclusiveMinimum": 0 },
        "ne": { "type": "number" },
        "ve": { "type": "number" },

        "glass_code":   { "type": "string" },
        "glass_code_e": { "type": "string" },
        "status":       { "type": "string", "enum": ["preferred", "standard", "inquiry", "special"] },
        "category":     { "type": "string" },
        "color_code":   { "type": "string" },
        "comment":      { "type": "string" },
        "remarks":      { "type": "string" },
        "datasheet_date":  { "type": "string" },
        "update_date":     { "type": "string" },
        "relative_price":  { "type": "number" },
        "availability_note": { "type": "string", "description": "OHARA i-line custom-order timing (特注化時期): the period the glass became special-order/made-to-order, e.g. '2000年以前' = before 2000. A production-status indicator, NOT a melt or discontinuation date." },
        "stress_optical_coefficient": { "type": "number", "description": "Photoelastic constant, normalized to Brewsters (all makers tabulate the same magnitude; factor 1.0)" },
        "stress_optical_coefficient_units": { "type": "string" },
        "stress_optical_coefficient_wavelength_nm": { "type": "number", "description": "Measurement wavelength: SCHOTT 589.3 (d), others 546.07 (e)" },
        "cross_references": { "type": "object" },
        "_computed_fields": { "type": "array", "items": { "type": "string" } },

        "refractive_indices": { "$ref": "#/definitions/refractive_indices" },
        "dispersions":         { "$ref": "#/definitions/dispersions" },
        "partial_dispersions": { "$ref": "#/definitions/partial_dispersions" },
        "partial_dispersions_extra": {
          "type": "object",
          "description": "Native, manufacturer-specific partial-dispersion ratios beyond the canonical set (e.g. primed/e-line systems, OHARA theta values). Keys are the maker's own labels; values numeric.",
          "additionalProperties": { "type": "number" }
        },
        "partial_dispersion_deviations": {
          "type": "object",
          "description": "Vendor deviation-from-normal-line values (DeltaP / Delta-theta), stored raw. The app computes its own DeltaPg,F vs the K7/F2 line and does NOT use these.",
          "additionalProperties": { "type": "number" }
        },
        "dispersion_formula":  { "$ref": "#/definitions/dispersion_formula" },
        "temperature_coefficients": { "$ref": "#/definitions/temperature_coefficients" },
        "dn_dt_table":         { "$ref": "#/definitions/dn_dt_table" },
        "thermal_properties":    { "$ref": "#/definitions/thermal_properties" },
        "mechanical_properties": { "$ref": "#/definitions/mechanical_properties" },
        "chemical_properties":   { "$ref": "#/definitions/chemical_properties" },
        "coloring":              { "$ref": "#/definitions/coloring" },
        "cci":                   { "$ref": "#/definitions/cci" },
        "chromaticity":          { "$ref": "#/definitions/chromaticity" },
        "internal_transmittance":{ "$ref": "#/definitions/internal_transmittance" },
        "internal_transmittance_extra": {
          "type": "array",
          "description": "Additional internal-transmittance blocks at non-10mm path lengths (SCHOTT 25mm, HOYA 2/5mm, CDGM 5mm). The 10mm block stays in internal_transmittance for the loader.",
          "items": { "$ref": "#/definitions/internal_transmittance" }
        }
      }
    },
    "refractive_indices": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "nd":       { "type": "number" },
        "ne":       { "type": "number" },
        "nC":       { "type": "number" },
        "nC_prime": { "type": "number" },
        "nF":       { "type": "number" },
        "nF_prime": { "type": "number" },
        "ng":       { "type": "number" },
        "nh":       { "type": "number" },
        "ni":       { "type": "number" },
        "nD":       { "type": "number" },
        "nt":       { "type": "number" },
        "ns":       { "type": "number" },
        "nr":       { "type": "number" },
        "nA_prime": { "type": "number" },
        "nHe_Ne":   { "type": "number" },
        "nHe_Cd":   { "type": "number" },
        "n248":     { "type": "number" },
        "n280":     { "type": "number" },
        "n296":     { "type": "number" },
        "n302":     { "type": "number" },
        "n312":     { "type": "number" },
        "n313":     { "type": "number" },
        "n334":     { "type": "number" },
        "n1060":    { "type": "number" },
        "n1129":    { "type": "number" },
        "n1530":    { "type": "number" },
        "n1970":    { "type": "number" },
        "n2325":    { "type": "number" }
      }
    },
    "dispersions": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "nF_nC":             { "type": "number", "description": "nF - nC" },
        "nF_prime_nC_prime": { "type": "number", "description": "nF' - nC'" }
      }
    },
    "partial_dispersions": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Ps_t":  { "type": "number", "description": "(ns-nt)/(nF-nC)" },
        "PC_s":  { "type": "number", "description": "(nC-ns)/(nF-nC)" },
        "Pd_C":  { "type": "number", "description": "(nd-nC)/(nF-nC)" },
        "Pe_d":  { "type": "number", "description": "(ne-nd)/(nF-nC)" },
        "Pg_F":  { "type": "number", "description": "(ng-nF)/(nF-nC)" },
        "Pi_g":  { "type": "number", "description": "(ni-ng)/(nF-nC)" },
        "Pi_h":  { "type": "number", "description": "(ni-nh)/(nF-nC)" }
      }
    },
    "dispersion_formula": {
      "type": "object",
      "required": ["type"],
      "oneOf": [
        {
          "required": ["type", "B1", "B2", "B3", "C1", "C2", "C3"],
          "additionalProperties": false,
          "properties": {
            "type": { "const": "Sellmeier" },
            "B1": { "type": "number" },
            "B2": { "type": "number" },
            "B3": { "type": "number" },
            "C1": { "type": "number", "description": "um^2" },
            "C2": { "type": "number", "description": "um^2" },
            "C3": { "type": "number", "description": "um^2" },
            "lambda_min_um": { "type": "number", "exclusiveMinimum": 0, "description": "Fit validity lower bound (um), from tabulated spectral indices" },
            "lambda_max_um": { "type": "number", "exclusiveMinimum": 0, "description": "Fit validity upper bound (um), from tabulated spectral indices" }
          }
        },
        {
          "required": ["type", "terms"],
          "additionalProperties": false,
          "properties": {
            "type": { "const": "SchottEquation" },
            "terms": {
              "type": "array",
              "minItems": 1,
              "items": {
                "type": "object",
                "required": ["coefficient", "exponent"],
                "additionalProperties": false,
                "properties": {
                  "coefficient": { "type": "number" },
                  "exponent":    { "type": "number" }
                }
              }
            },
            "lambda_min_um": { "type": "number", "exclusiveMinimum": 0, "description": "Fit validity lower bound (um), from tabulated spectral indices" },
            "lambda_max_um": { "type": "number", "exclusiveMinimum": 0, "description": "Fit validity upper bound (um), from tabulated spectral indices" }
          }
        }
      ]
    },
    "temperature_coefficients": {
      "type": "object",
      "additionalProperties": false,
      "description": "Schott TIE-19 temperature coefficients for dn/dT",
      "properties": {
        "formula":                { "type": "string" },
        "reference_temperature_C":{ "type": "number" },
        "D0":           { "type": "number" },
        "D1":           { "type": "number" },
        "D2":           { "type": "number" },
        "E0":           { "type": "number" },
        "E1":           { "type": "number" },
        "lambda_tk_um": { "type": "number", "description": "Reference wavelength (um)" }
      }
    },
    "dn_dt_table": {
      "type": "object",
      "description": "Raw per-spectral-line dn/dT (and, for HOYA, dnu/dT) tables across temperature bands. Reference data, not used by the app. Structure is maker-specific; documented per source.",
      "additionalProperties": false,
      "properties": {
        "_units":           { "type": "string" },
        "temperature_bands_C": {
          "type": "array",
          "description": "List of [low_C, high_C] band edges that index the per-line value arrays.",
          "items": { "type": "array", "items": { "type": "number" }, "minItems": 2, "maxItems": 2 }
        },
        "lines": {
          "type": "object",
          "description": "Per-spectral-line series keyed by line name (e.g. 'd','e','g','nC','1550'). Each holds relative and/or absolute arrays aligned to temperature_bands_C.",
          "additionalProperties": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "relative": { "type": "array", "items": { "type": ["number", "null"] } },
              "absolute": { "type": "array", "items": { "type": ["number", "null"] } }
            }
          }
        },
        "abbe": {
          "type": "object",
          "description": "Optional dnu/dT (Abbe-number temperature coefficient) series, e.g. HOYA nu_d / nu_e.",
          "additionalProperties": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "relative": { "type": "array", "items": { "type": ["number", "null"] } },
              "absolute": { "type": "array", "items": { "type": ["number", "null"] } }
            }
          }
        }
      }
    },
    "thermal_properties": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "Tg":                   { "type": "number", "description": "Transformation temperature (C)" },
        "Ts":                   { "type": "number", "description": "Sag / dilatometric softening temperature (C)" },
        "softening_point_C":    { "type": "number", "description": "Softening point, viscosity 10^7.6 dPa.s (C)" },
        "annealing_point_C":    { "type": "number", "description": "Annealing point, viscosity 10^13 dPa.s (C)" },
        "strain_point_C":       { "type": "number", "description": "Strain point, viscosity 10^14.5 dPa.s (C)" },
        "yield_point_C":        { "type": "number", "description": "Yield / sag-under-load point At (NOT the softening point) (C)" },
        "Cp":                   { "type": "number", "description": "Specific heat capacity (J/(g*K))" },
        "thermal_conductivity": { "type": "number", "description": "W/(m*K)" },
        "CTE_low":              { "type": "number", "description": "CTE -30/+70C (x10^-7/K)" },
        "CTE_high":             { "type": "number", "description": "CTE high band (x10^-7/K); band is +100/+300 except SCHOTT +20/+300 (see _units)" },
        "cte_table":            { "$ref": "#/definitions/cte_table" },
        "_units": {
          "type": "object",
          "additionalProperties": { "type": "string" }
        }
      }
    },
    "cte_table": {
      "type": "object",
      "description": "Raw fine-grained CTE table at small temperature steps. Reference data.",
      "additionalProperties": false,
      "properties": {
        "_units": { "type": "string" },
        "bands": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["low_C", "high_C"],
            "additionalProperties": false,
            "properties": {
              "low_C":  { "type": "number" },
              "high_C": { "type": "number" },
              "value":  { "type": ["number", "null"] }
            }
          }
        }
      }
    },
    "mechanical_properties": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "density":           { "type": "number", "description": "Specific gravity (g/cm^3)" },
        "youngs_modulus":    { "type": "number", "description": "Young's modulus E (GPa)" },
        "shear_modulus":     { "type": "number", "description": "Shear / rigidity modulus G (GPa)" },
        "poisson_ratio":     { "type": "number" },
        "knoop_hardness":    { "type": "number" },
        "knoop_group":       { "type": "number", "description": "Knoop hardness class 1-7 (100-unit HK bands: 1=<150 ... 7=>=650). OHARA 'Group' and HOYA 'HKrank' (Table 12) use the same banding." },
        "abrasion_hardness": { "type": "number", "description": "Generic abrasion hardness" },
        "abrasion":          { "type": "number", "description": "Relative abrasion (OHARA Aa, JOGIS; higher = softer)" },
        "abrasion_FA":       { "type": "number", "description": "CDGM relative abrasion FA (vs K9 = 100)" },
        "grindability_HG":   { "type": ["number", "string"], "description": "SCHOTT grindability class HG (ISO 12844)" },
        "grindability_HG_J": { "type": ["number", "string"], "description": "SCHOTT JOGIS-method grindability class (sparse legacy)" },
        "flexural_strength": { "type": "number", "description": "HOYA flexural (bending) strength (MPa)" },
        "_units": {
          "type": "object",
          "additionalProperties": { "type": "string" }
        }
      }
    },
    "chemical_properties": {
      "type": "object",
      "description": "Native per-manufacturer chemical-durability classes, verbatim under the maker's own keys (never cross-mapped); 'standard' names the test method(s). Lower class = more durable (SCHOTT FR starts at 0). SR/PR are ISO 8424/9689 coded as class.surface_change: SR classes 1-4 = pH 0.3, 5/51/52/53 = pH 4.6 (keep 51/52/53 literal); the .0-.4 decimal = surface-change severity (0 none, 1 clear/irregular, 2 interference colors, 3 thin whitish layer, 4 thick layer). OHARA W(S)max/W(S)min are the upper/lower bound of one weathering-surface class 1-4 (1=best), not two measurements. Note CR collision: SCHOTT CR=climatic, CDGM CR=weathering (CDGM climatic is RC(S)).",
      "additionalProperties": false,
      "required": ["classes"],
      "properties": {
        "standard": { "type": "string" },
        "classes": {
          "type": "object",
          "minProperties": 1,
          "additionalProperties": { "type": ["string", "number"] }
        },
        "semantic": {
          "type": "object",
          "description": "Maker-agnostic controlled-vocabulary aliases (climatic_humidity/weathering/acid/alkali/phosphate/stain/water) -> the maker's native class key. A NAME POINTER only; class numbers are NOT comparable across makers (different standards).",
          "additionalProperties": { "type": "string" }
        }
      }
    },
    "coloring": {
      "type": "object",
      "description": "Coloration / transmittance-edge wavelengths (nm).",
      "additionalProperties": false,
      "properties": {
        "lambda80_nm":      { "type": "number", "description": "External-transmittance 80% edge wavelength" },
        "lambda70_nm":      { "type": "number", "description": "External-transmittance 70% edge wavelength" },
        "lambda5_nm":       { "type": "number", "description": "External-transmittance 5% edge wavelength" },
        "lambda_i80_nm":    { "type": "number", "description": "Internal-transmittance 80% edge wavelength" },
        "lambda_i70_nm":    { "type": "number", "description": "Internal-transmittance 70% edge wavelength" },
        "lambda_i5_nm":     { "type": "number", "description": "Internal-transmittance 5% edge wavelength" },
        "raw":              { "type": "string", "description": "Verbatim coloring string where the source gives a packed 'lambdaHigh/lambda5' form" },
        "_thickness_mm":    { "type": "number" }
      }
    },
    "cci": {
      "type": "object",
      "description": "Color Contribution Index (ISO 6728) triplet; B is the 0 reference where only G/R are tabulated.",
      "additionalProperties": false,
      "properties": {
        "B": { "type": "number" },
        "G": { "type": "number" },
        "R": { "type": "number" }
      }
    },
    "chromaticity": {
      "type": "object",
      "description": "CIE chromaticity of transmitted color (illuminant/observer per source; see _note).",
      "additionalProperties": false,
      "properties": {
        "x": { "type": "number" },
        "y": { "type": "number" },
        "_note": { "type": "string" }
      }
    },
    "internal_transmittance": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "thickness_mm":  { "type": "number" },
        "wavelengths_nm":{ "type": "array", "items": { "type": "number" } },
        "values":        { "type": "array", "items": { "type": "number" } },
        "color_code":    { "type": "string" }
      }
    }
  }
}
