44[ ![ Python] ( https://img.shields.io/pypi/pyversions/cdl-parser.svg )] ( https://pypi.org/project/cdl-parser/ )
55[ ![ License: MIT] ( https://img.shields.io/badge/License-MIT-yellow.svg )] ( https://opensource.org/licenses/MIT )
66
7- ** Crystal Description Language (CDL) Parser** - A Python library for parsing compact string notation describing crystal morphology for gemmological and mineralogical visualization.
7+ ** Crystal Description Language (CDL) Parser** - A Python library for parsing compact string notation describing crystal morphology for gemmological and mineralogical visualization. CDL v2.0 adds support for amorphous materials, nested growth, and crystal aggregates.
88
99Part of the [ Gemmology Project] ( https://gemmology.dev ) .
1010
@@ -31,19 +31,40 @@ print(len(desc.forms)) # 2
3131# Parse with twin specification
3232desc = parse_cdl(" cubic[m3m]:{111} | twin(spinel)" )
3333print (desc.twin.law) # 'spinel'
34+
35+ # Parse an amorphous material (v2.0)
36+ desc = parse_cdl(" amorphous[opalescent]:{botryoidal} " )
37+ print (desc.system) # 'amorphous'
38+ print (desc.subtype) # 'opalescent'
39+
40+ # Parse nested growth (v2.0)
41+ desc = parse_cdl(" trigonal[32]:({10-10}@1.0 + {10-11}@0.8) > ({10-10}@0.5 + {10-11}@0.4)" )
42+
43+ # Parse an aggregate (v2.0)
44+ desc = parse_cdl(" trigonal[32]:{10-10}@1.0 + {10-11}@0.8 ~ cluster[12]" )
3445```
3546
3647## CDL Specification
3748
3849### Syntax Overview
3950
4051```
52+ # Crystalline materials
4153system[point_group]:{form}@scale + {form}@scale | modification | twin(law)
54+
55+ # Amorphous materials (v2.0)
56+ amorphous[subtype]:{shape1, shape2}[features] | phenomenon[type]
57+
58+ # Nested growth (v2.0)
59+ system[point_group]:(forms) > (overgrowth_forms)
60+
61+ # Aggregates (v2.0)
62+ system[point_group]:forms ~ arrangement[count]
4263```
4364
4465### Crystal Systems
4566
46- All 7 crystal systems are supported with their standard point groups:
67+ All 7 crystal systems are supported with their standard point groups, plus amorphous materials :
4768
4869| System | Default Point Group | All Point Groups |
4970| --------| ---------------------| ------------------|
@@ -54,6 +75,59 @@ All 7 crystal systems are supported with their standard point groups:
5475| orthorhombic | mmm | mmm, 222, mm2 |
5576| monoclinic | 2/m | 2/m, m, 2 |
5677| triclinic | -1 | -1, 1 |
78+ | amorphous | none | (n/a) |
79+
80+ ### Amorphous Materials (v2.0)
81+
82+ Materials without crystalline structure use the ` amorphous ` keyword instead of a crystal system:
83+
84+ ``` python
85+ # Syntax: amorphous[subtype]:{shape1, shape2}[features]
86+ " amorphous[opalescent]:{botryoidal}"
87+ " amorphous[cryptocrystalline]:{massive, nodular}[colour:blue]"
88+ " amorphous[waxy]:{mammillary}[banding:concentric]"
89+ ```
90+
91+ ** Subtypes:** ` opalescent ` , ` glassy ` , ` waxy ` , ` resinous ` , ` cryptocrystalline `
92+
93+ ** Shapes:** ` massive ` , ` botryoidal ` , ` reniform ` , ` stalactitic ` , ` mammillary ` , ` nodular ` , ` conchoidal `
94+
95+ ### Nested Growth (v2.0)
96+
97+ The ` > ` operator describes overgrowth relationships (base > overgrowth), where an outer crystal grows on an inner one. Right-associative: ` a > b > c ` = ` a > (b > c) ` .
98+
99+ ``` python
100+ # Scepter quartz — enlarged head on thin stem
101+ " trigonal[32]:({10-10}@1.0 + {10-11}@0.8) > ({10-10}@0.5 + {10-11}@0.4)"
102+
103+ # Diamond phantom
104+ " cubic[m3m]:{111}@1.0 > {111}@1.0"
105+ ```
106+
107+ ### Aggregates (v2.0)
108+
109+ The ` ~ ` operator describes crystal aggregates — multiple copies of a form arranged in a spatial pattern:
110+
111+ ``` python
112+ # Syntax: forms ~ arrangement[count]
113+ " trigonal[32]:{10-10}@1.0 + {10-11}@0.8 ~ cluster[12]" # Quartz cluster
114+ " trigonal[32]:{10-10}@1.0 + {10-11}@0.8 ~ druse[50]" # Amethyst geode
115+ " cubic[m3m]:{100} ~ cluster[5]" # Pyrite cluster
116+ " trigonal[-3m]:rhombohedron ~ parallel[3]" # Calcite parallel growth
117+ ```
118+
119+ ** Arrangements:** ` parallel ` , ` random ` , ` radial ` , ` epitaxial ` , ` druse ` , ` cluster `
120+
121+ ** Orientations** (optional): ` aligned ` , ` random ` , ` planar ` , ` spherical `
122+
123+ ### Group-Level Twins (v2.0)
124+
125+ Twin specifications can be applied to form groups, allowing twinning of composite morphologies:
126+
127+ ``` python
128+ # Twin a group of forms
129+ " cubic[m3m]:({111}@1.0 + {100}@0.3) | twin(spinel)"
130+ ```
57131
58132### Miller Indices
59133
@@ -133,20 +207,39 @@ Named twin laws for common crystal twins:
133207
134208# Fluorite cube
135209" cubic[m3m]:{100}"
210+
211+ # Opal — amorphous with play of color (v2.0)
212+ " amorphous[opalescent]:{botryoidal} | phenomenon[play_of_color:intense]"
213+
214+ # Turquoise — cryptocrystalline massive (v2.0)
215+ " amorphous[cryptocrystalline]:{massive, nodular}[colour:blue]"
216+
217+ # Scepter quartz — nested growth (v2.0)
218+ " trigonal[32]:({10-10}@1.0 + {10-11}@0.8) > ({10-10}@0.5 + {10-11}@0.4)"
219+
220+ # Quartz cluster aggregate (v2.0)
221+ " trigonal[32]:{10-10}@1.0 + {10-11}@0.8 ~ cluster[12]"
222+
223+ # Amethyst geode druse (v2.0)
224+ " trigonal[32]:{10-10}@1.0 + {10-11}@0.8 ~ druse[50]"
136225```
137226
138227## API Reference
139228
140229### Core Functions
141230
142- #### ` parse_cdl(text: str) -> CrystalDescription `
231+ #### ` parse_cdl(text: str) -> CrystalDescription | AmorphousDescription `
143232
144- Parse a CDL string into a structured description.
233+ Parse a CDL string into a structured description. Returns ` CrystalDescription ` for crystalline materials or ` AmorphousDescription ` for amorphous materials.
145234
146235``` python
147236from cdl_parser import parse_cdl
148237
238+ # Crystalline — returns CrystalDescription
149239desc = parse_cdl(" cubic[m3m]:{111} @1.0 + {100} @1.3" )
240+
241+ # Amorphous — returns AmorphousDescription (v2.0)
242+ desc = parse_cdl(" amorphous[opalescent]:{botryoidal} " )
150243```
151244
152245#### ` validate_cdl(text: str) -> tuple[bool, str | None] `
@@ -165,16 +258,66 @@ if not is_valid:
165258
166259#### ` CrystalDescription `
167260
168- Main output of CDL parsing.
261+ Main output of CDL parsing for crystalline materials .
169262
170263``` python
171264@dataclass
172265class CrystalDescription :
173266 system: str # Crystal system
174267 point_group: str # Point group symbol
175- forms: List[CrystalForm] # Crystal forms
176- modifications: List[Modification] # Morphological mods
177- twin: Optional[TwinSpec] # Twin specification
268+ forms: list[FormNode] # Form tree (CrystalForm | FormGroup | NestedGrowth | AggregateSpec)
269+ modifications: list[Modification] # Morphological mods
270+ twin: TwinSpec | None # Twin specification
271+ phenomenon: PhenomenonSpec | None # Optical phenomenon
272+ doc_comments: list[str ] | None # Doc comments (#!)
273+ definitions: list[Definition] | None # Named definitions (@name = ...)
274+
275+ def flat_forms (self ) -> list[CrystalForm]:
276+ """ Flatten form tree into a list of CrystalForm leaves."""
277+ ```
278+
279+ #### ` AmorphousDescription ` (v2.0)
280+
281+ Output of CDL parsing for amorphous (non-crystalline) materials.
282+
283+ ``` python
284+ @dataclass
285+ class AmorphousDescription :
286+ subtype: str # 'opalescent', 'glassy', 'waxy', etc.
287+ shapes: list[str ] # 'massive', 'botryoidal', etc.
288+ features: list[Feature] | None # Feature annotations
289+ phenomenon: PhenomenonSpec | None # Optical phenomenon
290+ doc_comments: list[str ] | None # Doc comments (#!)
291+ definitions: list[Definition] | None # Named definitions
292+
293+ @ property
294+ def system (self ) -> str : # Always returns 'amorphous'
295+ ```
296+
297+ #### ` NestedGrowth ` (v2.0)
298+
299+ Represents a base crystal with an overgrowth (the ` > ` operator).
300+
301+ ``` python
302+ @dataclass
303+ class NestedGrowth :
304+ base: FormNode # Base form node
305+ overgrowth: FormNode # Overgrowth form node
306+ ```
307+
308+ #### ` AggregateSpec ` (v2.0)
309+
310+ Represents a crystal aggregate (the ` ~ ` operator).
311+
312+ ``` python
313+ @dataclass
314+ class AggregateSpec :
315+ form: FormNode # Form to aggregate
316+ arrangement: str # 'parallel', 'random', 'radial', etc.
317+ count: int # Number of individuals
318+ spacing: str | None # Optional spacing value
319+ orientation: str | None # Optional orientation mode
320+ orientation_param: float | None # Optional orientation parameter
178321```
179322
180323#### ` MillerIndex `
@@ -209,11 +352,15 @@ class CrystalForm:
209352
210353``` python
211354from cdl_parser import (
212- CRYSTAL_SYSTEMS , # Set of system names
213- POINT_GROUPS , # Dict[system, Set[groups]]
214- DEFAULT_POINT_GROUPS , # Dict[system, default_group]
215- NAMED_FORMS , # Dict[name, (h, k, l)]
216- TWIN_LAWS , # Set of twin law names
355+ CRYSTAL_SYSTEMS , # Set of system names
356+ POINT_GROUPS , # Dict[system, Set[groups]]
357+ DEFAULT_POINT_GROUPS , # Dict[system, default_group]
358+ NAMED_FORMS , # Dict[name, (h, k, l)]
359+ TWIN_LAWS , # Set of twin law names
360+ AMORPHOUS_SUBTYPES , # Set: opalescent, glassy, waxy, resinous, cryptocrystalline
361+ AMORPHOUS_SHAPES , # Set: massive, botryoidal, reniform, stalactitic, ...
362+ AGGREGATE_ARRANGEMENTS , # Set: parallel, random, radial, epitaxial, druse, cluster
363+ AGGREGATE_ORIENTATIONS , # Set: aligned, random, planar, spherical
217364)
218365```
219366
0 commit comments