Skip to main content

Converting JSON crystal data to Graphics using AI Assistant

Β· 4 min read
Kirill Vasin

Working in condensed matter physics, I (JerryI) often need to represent crystal structures based on their CIF, JSON, or other formats. Sometimes, it is quite tricky to parse these data files since you also need to determine the given symmetry operation when constructing a unit cell. Here, we will do it using AI Copilot πŸ€–

Uranium​

When I was measuring the spectrum of UO2U O_2 at the Nijmegen High-Magnetic-Field Lab during the morning shift, I had to make a short summary report and needed a nice plot of a unit cell.

GPT models can actually work with JSON data or Associations quite well. The first step is to get a CIF or JSON file on the crystal structure. This can be done using the Materials Project database. In the summary section, one can export a single JSON file and then import it into our notebook.


Import["UO2.json", "RawJSON"]
<|"@module"->"pymatgen.core.structure","@class"->"Structure","charge"->0,"lattice"-><|"matrix"->{{5.45401004`,0.`,3.339617969001764`*^-16},{8.770717076887777`*^-16,5.45401004`,3.339617969001764`*^-16},{0.`,0.`,5.45401004`}},"pbc"->{True,True,True},"a"->5.45401004`,"b"->5.45401004`,"c"->5.45401004`,"alpha"->90.`,"beta"->90.`,"gamma"->90.`,"volume"->162.23621261866322`|>,"properties"-><||>,"sites"->{<|"species"->{<|"element"->"U","oxidation_state"->4,"spin"->Null,"occu"->1|>},"abc"->{0.5`,0.`,0.`},"xyz"->{2.72700502`,0.`,1.669808984500882`*^-16},"properties"-><||>,"label"->"U4+"|>,<|"species"->{<|"element"->"U","oxidation_state"->4,"spin"->Null,"occu"->1|>},"abc"->{0.5`,0.5`,0.5`},"xyz"->{2.7270050200000004`,2.72700502`,2.7270050200000004`},"properties"-><||>,"label"->"U4+"|>,<|"species"->{<|"element"->"U","oxidation_state"->4,"spin"->Null,"occu"->1|>},"abc"->{0.`,0.`,0.5`},"xyz"->{0.`,0.`,2.72700502`},"properties"-><||>,"label"->"U4+"|>,<|"species"->{<|"element"->"U","oxidation_state"->4,"spin"->Null,"occu"->1|>},"abc"->{0.`,0.5`,0.`},"xyz"->{4.3853585384438886`*^-16,2.72700502`,1.669808984500882`*^-16},"properties"-><||>,"label"->"U4+"|>,<|"species"->{<|"element"->"O","oxidation_state"->-2,"spin"->Null,"occu"->1|>},"abc"->{0.25`,0.75`,0.75`},"xyz"->{1.3635025100000007`,4.09050753`,4.09050753`},"properties"-><||>,"label"->"O2-"|>,<|"species"->{<|"element"->"O","oxidation_state"->-2,"spin"->Null,"occu"->1|>},"abc"->{0.25`,0.25`,0.75`},"xyz"->{1.3635025100000002`,1.36350251`,4.09050753`},"properties"-><||>,"label"->"O2-"|>,<|"species"->{<|"element"->"O","oxidation_state"->-2,"spin"->Null,"occu"->1|>},"abc"->{0.25`,0.25`,0.25`},"xyz"->{1.3635025100000002`,1.36350251`,1.3635025100000002`},"properties"-><||>,"label"->"O2-"|>,<|"species"->{<|"element"->"O","oxidation_state"->-2,"spin"->Null,"occu"->1|>},"abc"->{0.25`,0.75`,0.25`},"xyz"->{1.3635025100000007`,4.09050753`,1.3635025100000004`},"properties"-><||>,"label"->"O2-"|>,<|"species"->{<|"element"->"O","oxidation_state"->-2,"spin"->Null,"occu"->1|>},"abc"->{0.75`,0.75`,0.25`},"xyz"->{4.090507530000001`,4.09050753`,1.3635025100000004`},"properties"-><||>,"label"->"O2-"|>,<|"species"->{<|"element"->"O","oxidation_state"->-2,"spin"->Null,"occu"->1|>},"abc"->{0.75`,0.25`,0.25`},"xyz"->{4.09050753`,1.36350251`,1.3635025100000004`},"properties"-><||>,"label"->"O2-"|>,<|"species"->{<|"element"->"O","oxidation_state"->-2,"spin"->Null,"occu"->1|>},"abc"->{0.75`,0.25`,0.75`},"xyz"->{4.09050753`,1.36350251`,4.09050753`},"properties"-><||>,"label"->"O2-"|>,<|"species"->{<|"element"->"O","oxidation_state"->-2,"spin"->Null,"occu"->1|>},"abc"->{0.75`,0.75`,0.75`},"xyz"->{4.090507530000001`,4.09050753`,4.090507530000001`},"properties"-><||>,"label"->"O2-"|>}|>

It looks quite ugly. Let's ask our AI assistant to convert it to a 3D plot using following prompt

Ctrl/Cmd + P

and type

read crystal data in focused cell and draw a unit cell using 3D graphics and representing ions as spheres with different colors

The generated cell is following (using GPT-4o model Jun 2024)

Module[{a = 5.45401004, unitCell, filledUnitCell},
unitCell = {
{Yellow, Sphere[{2.72700502, 0., 0.}, 0.5]},
{Yellow, Sphere[{2.72700502, 2.72700502, 2.72700502}, 0.5]},
{Yellow, Sphere[{0., 0., 2.72700502}, 0.5]},
{Yellow, Sphere[{0., 2.72700502, 0.}, 0.5]},
{Red, Sphere[{1.36350251, 4.09050753, 4.09050753}, 0.3]},
{Red, Sphere[{1.36350251, 1.36350251, 4.09050753}, 0.3]},
{Red, Sphere[{1.36350251, 1.36350251, 1.36350251}, 0.3]},
{Red, Sphere[{4.09050753, 1.36350251, 4.09050753}, 0.3]},
{Red, Sphere[{4.09050753, 4.09050753, 4.09050753}, 0.3]}
};

filledUnitCell = Flatten[Table[
Translate[unitCell, {i, j, k} a],
{i, 0, 1}, {j, 0, 1}, {k, 0, 1}
], 3];

Graphics3D[{filledUnitCell}]
]

One can also ask it to add borders

edit your cell and add borders of the unit cell using black lines

Module[{a = 5.45401004, unitCell, filledUnitCell, borders},
unitCell = {
{Yellow, Sphere[{2.72700502, 0., 0.}, 0.5]},
{Yellow, Sphere[{2.72700502, 2.72700502, 2.72700502}, 0.5]},
{Yellow, Sphere[{0., 0., 2.72700502}, 0.5]},
{Yellow, Sphere[{0., 2.72700502, 0.}, 0.5]},
{Red, Sphere[{1.36350251, 4.09050753, 4.09050753}, 0.3]},
{Red, Sphere[{1.36350251, 1.36350251, 4.09050753}, 0.3]},
{Red, Sphere[{1.36350251, 1.36350251, 1.36350251}, 0.3]},
{Red, Sphere[{4.09050753, 1.36350251, 4.09050753}, 0.3]},
{Red, Sphere[{4.09050753, 4.09050753, 4.09050753}, 0.3]}
};

filledUnitCell = Flatten[Table[
Translate[unitCell, {i, j, k} a],
{i, 0, 1}, {j, 0, 1}, {k, 0, 1}
], 3];

borders = {
Line[{{0, 0, 0}, {a, 0, 0}}],
Line[{{0, 0, 0}, {0, a, 0}}],
Line[{{0, 0, 0}, {0, 0, a}}],
Line[{{a, a, 0}, {0, a, 0}}],
Line[{{a, a, 0}, {a, 0, 0}}],
Line[{{a, 0, a}, {a, 0, 0}}],
Line[{{a, 0, a}, {0, 0, a}}],
Line[{{0, a, a}, {0, 0, a}}],
Line[{{0, a, a}, {0, a, 0}}],
Line[{{a, a, a}, {0, a, a}}],
Line[{{a, a, a}, {a, 0, a}}],
Line[{{a, a, a}, {a, a, 0}}]
};

Graphics3D[{filledUnitCell, Black, borders}]
]

This is amazing how modern LLM can read and parse any kind of data and convert them to the desired formats πŸ¦„