from mp_api.client import MPRester
from pymatgen.core.tensors import Tensor
import numpy as np
import os
import argparse
API_KEY = os.environ.get("MAT_PROJ_API_KEY")
if not API_KEY:
raise ValueError("MAT_PROJ_API_KEY environment variable is not set!")
parser = argparse.ArgumentParser(description="Fetch and compute tensor properties for Materials Project materials.")
parser.add_argument("materials", nargs="*", default=["661", "2133", "3731", "3666", "5020", "6945", "20459", "774922"],
help="Material IDs (numbers only, without 'mp-'). E.g., 3731 6945.")
args = parser.parse_args()
with MPRester(API_KEY) as mpr:
material_ids = [f"mp-{m}" for m in args.materials]
piezo_docs = mpr.materials.piezoelectric.search(material_ids=material_ids)
elastic_docs = mpr.materials.elasticity.search(material_ids=material_ids)
dielectric_docs = mpr.materials.dielectric.search(material_ids=material_ids)
elastic_map = {d.material_id: d for d in elastic_docs}
dielectric_map = {d.material_id: d for d in dielectric_docs}
for doc in piezo_docs:
print("-" * 60)
print(f"Material: {doc.material_id} ({doc.formula_pretty})")
print(f"Symmetry: {doc.symmetry.symbol} (Space Group {doc.symmetry.number})")
print("\n--- Piezoelectric Stress Tensor (e) [C/m²] ---")
print("Voigt Notation (3x6):")
e_matrix = np.array(doc.total)
print(e_matrix)
e_doc = elastic_map.get(doc.material_id)
if e_doc:
print("\n--- Elastic Tensors [GPa] ---")
print("Stiffness Tensor (C):")
print(np.array(e_doc.elastic_tensor.ieee_format))
else:
print("\n--- Elastic Tensors ---")
print("Elastic data not available for this material.")
d_doc = dielectric_map.get(doc.material_id)
if d_doc:
print("\n--- Relative Permittivity Tensor (ε_r) ---")
print(np.array(d_doc.total))
else:
print("\n--- Relative Permittivity Tensor ---")
print("Not available for this material.")
print("\n")
def export_tensors_to_json(piezo_docs, elastic_map, dielectric_map, filename="piezo_data.json"):
import json
from pymatgen.core.elasticity import ElasticTensor, ComplianceTensor
data = {
"_metadata": {
"voigt_mapping": "11, 22, 33, 23, 13, 12",
"voigt_mapping_notes": "Standard IEEE mapping: 1->11, 2->22, 3->33, 4->23 (or 32), 5->13 (or 31), 6->12 (or 21).",
"units": {
"e_tensor": "C/m^2",
"e_voigt": "C/m^2",
"cc_tensor": "GPa",
"cc_voigt": "GPa",
"relative_permittivity_tensor": "dimensionless"
}
}
}
for doc in piezo_docs:
mat_id = doc.material_id
e_voigt = np.array(doc.total)
e_full = Tensor.from_voigt(e_voigt).tolist()
e_doc = elastic_map.get(mat_id)
c_full = None
c_voigt_list = None
if e_doc:
c_voigt = np.array(e_doc.elastic_tensor.ieee_format)
c_full = ElasticTensor.from_voigt(c_voigt).tolist()
c_voigt_list = c_voigt.tolist()
d_doc = dielectric_map.get(mat_id)
eps_full = np.array(d_doc.total).tolist() if d_doc else None
if any(v is None for v in [e_full, c_full, eps_full]):
print(f"Material {mat_id} ({doc.formula_pretty}) skipped: Not all data available.")
continue
data[mat_id] = {
"material_id": mat_id,
"formula": doc.formula_pretty,
"crystal_system": str(doc.symmetry.crystal_system),
"point_group": str(doc.symmetry.point_group),
"space_group_symbol": str(doc.symmetry.symbol),
"space_group_number": doc.symmetry.number,
"e_tensor": e_full,
"e_voigt": e_voigt.tolist(),
"cc_tensor": c_full,
"cc_voigt": c_voigt_list,
"relative_permittivity_tensor": eps_full
}
with open(filename, "w") as f:
json.dump(data, f, indent=4)
print(f"Successfully exported data with full Cartesian components to {filename}")
export_tensors_to_json(piezo_docs, elastic_map, dielectric_map)