diff --git a/environment-minimal.yml b/environment-minimal.yml index 496b1712..b8f1f30f 100644 --- a/environment-minimal.yml +++ b/environment-minimal.yml @@ -13,4 +13,4 @@ dependencies: - pip: - pyscf==2.11.0 - metatensor-core==0.1.17 - - git+https://github.com/lcmd-epfl/cell2mol.git@40b3237 + - git+https://github.com/lcmd-epfl/cell2mol.git@283c965 diff --git a/environment.yml b/environment.yml index edf4f37f..73016d8c 100644 --- a/environment.yml +++ b/environment.yml @@ -92,4 +92,4 @@ dependencies: - typing-extensions==4.15.0 - typing-inspection==0.4.2 - tzdata==2025.2 - - git+https://github.com/lcmd-epfl/cell2mol.git@40b3237 + - git+https://github.com/lcmd-epfl/cell2mol.git@283c965 diff --git a/pyproject.toml b/pyproject.toml index 9dd486ae..ee1cf2d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,7 +47,7 @@ pyscf = ['pyscf >= 2.1.0, < 2.12'] qml = ['ase >= 3.22, < 3.27'] regression = ["scikit-learn >= 0.24.2, < 1.8"] wigner = ["sympy >= 1.5, < 1.15"] -cell2mol-itself = ["cell2mol @ git+https://github.com/lcmd-epfl/cell2mol.git@40b3237"] +cell2mol-itself = ["cell2mol @ git+https://github.com/lcmd-epfl/cell2mol.git@283c965"] cell2mol = ["qstack[pyscf,cell2mol-itself]"] equio-itself = ["metatensor-core >= 0.1.8, == 0.1.*"] equio = ["qstack[pyscf,equio-itself]"] diff --git a/qstack/io/cell2mol.py b/qstack/io/cell2mol.py index 1c0dbc5b..1f72a681 100644 --- a/qstack/io/cell2mol.py +++ b/qstack/io/cell2mol.py @@ -1,10 +1,10 @@ """Converter from cell2mol Cell objects to PySCF Mole.""" -import sys import os import io -from cell2mol.read_write import load_binary -from cell2mol.unitcell import process_unitcell +from contextlib import redirect_stdout +import numpy as np +from cell2mol.process_unitcell import interpret_unitcell from qstack.compound import xyz_to_mol @@ -21,10 +21,9 @@ def get_cell2mol_xyz(mol): - spin (int): Number of unpaired electrons of the molecule (multiplicity - 1) for molecules and None for ligands. """ - f = io.StringIO() - sys.stdout, stdout = f, sys.stdout - mol.print_xyz() - xyz, sys.stdout = f.getvalue(), stdout + with redirect_stdout(io.StringIO()) as f: + mol.print_xyz() + xyz = f.getvalue() f.close() return xyz, mol.totcharge, (mol.get_spin()-1 if hasattr(mol, 'get_spin') else None) @@ -49,14 +48,14 @@ def get_cell(fpath, workdir='.'): """ ext = os.path.splitext(fpath)[-1] if ext=='.cell': - cell = load_binary(fpath) + cell = np.load(fpath, allow_pickle=True) elif ext=='.cif': name = os.path.basename(os.path.splitext(fpath)[0]) cell_path = f'{workdir}/Cell_{name}.cell' if os.path.isfile(cell_path): - cell = load_binary(cell_path) + cell = np.load(cell_path, allow_pickle=True) else: - cell = process_unitcell(fpath, name, workdir, cif_bond_info=True, debug=0) + cell = interpret_unitcell(input_path=fpath, name=name, current_dir=workdir) else: raise NotImplementedError(f'{ext} input is not supported') return cell diff --git a/requirements.py3.11.txt b/requirements.py3.11.txt index b91ce11d..c952039f 100644 --- a/requirements.py3.11.txt +++ b/requirements.py3.11.txt @@ -14,4 +14,4 @@ scikit-learn==1.7.2 ase==3.26 tqdm==4.67 metatensor-core==0.1.17 -cell2mol @ git+https://github.com/lcmd-epfl/cell2mol.git@40b3237 +cell2mol @ git+https://github.com/lcmd-epfl/cell2mol.git@283c965 diff --git a/requirements.py3.13.txt b/requirements.py3.13.txt index 2e89926e..32af2117 100644 --- a/requirements.py3.13.txt +++ b/requirements.py3.13.txt @@ -11,4 +11,4 @@ scikit-learn==1.7.2 ase==3.26 tqdm==4.67 metatensor-core==0.1.17 -cell2mol @ git+https://github.com/lcmd-epfl/cell2mol.git@40b3237 +cell2mol @ git+https://github.com/lcmd-epfl/cell2mol.git@283c965 diff --git a/tests/data/cell2mol/Cell_YOXKUS.cell b/tests/data/cell2mol/Cell_YOXKUS.cell index ffa569c7..72051f02 100644 Binary files a/tests/data/cell2mol/Cell_YOXKUS.cell and b/tests/data/cell2mol/Cell_YOXKUS.cell differ diff --git a/tests/data/cell2mol/Ref_Cell_YOXKUS.cell b/tests/data/cell2mol/Ref_Cell_YOXKUS.cell index cc87f224..0ce1d5c9 100644 Binary files a/tests/data/cell2mol/Ref_Cell_YOXKUS.cell and b/tests/data/cell2mol/Ref_Cell_YOXKUS.cell differ diff --git a/tests/data/cell2mol/reference_summary.txt b/tests/data/cell2mol/reference_summary.txt new file mode 100644 index 00000000..5926a7e7 --- /dev/null +++ b/tests/data/cell2mol/reference_summary.txt @@ -0,0 +1,89 @@ +YOXKUS +Total charge comparison result: True +Metal oxidation state comparison result: True + - Reported: [('carbonyl-diiodo-rhenium', 3)] + - Matched: ['Re_3'] + - Confidence: 1.00 + +Molecules in reference: +Molecule 0: H24-C23-O-P-I2-Re (TM Complex) totcharge=0 totcharge_cif=0 totcharge_agree=True spin_multiplicity=1 smiles=C[c]12->[Re+3]3456(<-[I-])(<-[I-])(<-[C-]#[O+])<-[c]1(C)[c]->3(C)[c-]->4(C[P]->5(c1ccccc1)c1ccccc1)[c]->62C + Re (metal) atom_site_label=Re1 metal_OS=3 metal_spin=1 + |--coord_sphere_formula=C6-P-I2 + |--coord_nr=5 coord_geometry=Trigonal bipyramidal geom_deviation=3.348 + |--(group) ['C'] atom_site_labels=['C23'] denticity=1 + |--(group) ['C', 'C', 'C', 'C', 'C'] atom_site_labels=['C1', 'C2', 'C3', 'C4', 'C5'] denticity=5 haptic_type=eta5(Cp) + |--(group) ['P'] atom_site_labels=['P1'] denticity=1 + |--(group) ['I'] atom_site_labels=['I2'] denticity=1 + |--(group) ['I'] atom_site_labels=['I1'] denticity=1 + C-O (ligand) smiles=[C-]#[O+] denticity=1 totcharge=0 + |--(group) ['C'] atom_site_labels=['C23'] denticity=1 connected_metals=['Re1'] + H24-C22-P (ligand) smiles=[H]c1c([H])c([H])c(P(c2c([H])c([H])c([H])c([H])c2[H])C([H])([H])[c-]2c(C([H])([H])[H])c(C([H])([H])[H])c(C([H])([H])[H])c2C([H])([H])[H])c([H])c1[H] denticity=6 totcharge=-1 + |--(group) ['C', 'C', 'C', 'C', 'C'] atom_site_labels=['C1', 'C2', 'C3', 'C4', 'C5'] denticity=5 haptic_type=eta5(Cp) connected_metals=['Re1'] + |--(group) ['P'] atom_site_labels=['P1'] denticity=1 connected_metals=['Re1'] + I (ligand) smiles=[I-] denticity=1 totcharge=-1 + |--(group) ['I'] atom_site_labels=['I2'] denticity=1 connected_metals=['Re1'] + I (ligand) smiles=[I-] denticity=1 totcharge=-1 + |--(group) ['I'] atom_site_labels=['I1'] denticity=1 connected_metals=['Re1'] + +Unique Species in reference: + unique_index=0 C-O (ligand) denticity=1 smiles=[C-]#[O+] totcharge=0 groups=['C'] + unique_index=1 H24-C22-P (ligand) denticity=6 haptic_type=['eta5(Cp)'] smiles=[H]c1c([H])c([H])c(P(c2c([H])c([H])c([H])c([H])c2[H])C([H])([H])[c-]2c(C([H])([H])[H])c(C([H])([H])[H])c(C([H])([H])[H])c2C([H])([H])[H])c([H])c1[H] totcharge=-1 groups=['C5', 'P'] + unique_index=2 I (ligand) denticity=1 smiles=[I-] totcharge=-1 groups=['I'] + unique_index=3 Re (metal) coord_sphere_formula=C6-P-I2 charge=3 + +Possible charges of species in reference: + unique_index=0 C-O (ligand) + possible_cs=[------------- Cell2mol Charge State --------------- + Status = True + Smiles = [C-]#[O+] + Number of Protons Added = 0 + Charge Tried = 0 + Uncorrected Total Charge = 0 + Corrected Total Charge = 0 + Corrected Absolute Total Charge = 2 + Corrected Is Zwitterion? = True +--------------------------------------------------- +] + unique_index=1 H24-C22-P (ligand) + possible_cs=[------------- Cell2mol Charge State --------------- + Status = True + Smiles = [H]c1c([H])c([H])c(P(c2c([H])c([H])c([H])c([H])c2[H])C([H])([H])C2([H])C(C([H])([H])[H])=C(C([H])([H])[H])C(C([H])([H])[H])=C2C([H])([H])[H])c([H])c1[H] + Number of Protons Added = 1 + Charge Tried = 0 + Uncorrected Total Charge = 0 + Corrected Total Charge = -1 + Corrected Absolute Total Charge = 1 + Corrected Is Zwitterion? = False +--------------------------------------------------- +] + unique_index=2 I (ligand) + possible_cs=[------------- Cell2mol Charge State --------------- + Status = True + Smiles = [I-] + Number of Protons Added = 0 + Charge Tried = -1 + Uncorrected Total Charge = -1 + Corrected Total Charge = -1 + Corrected Absolute Total Charge = 1 + Corrected Is Zwitterion? = False +--------------------------------------------------- +] + unique_index=2 I (ligand) + possible_cs=[------------- Cell2mol Charge State --------------- + Status = True + Smiles = [I-] + Number of Protons Added = 0 + Charge Tried = -1 + Uncorrected Total Charge = -1 + Corrected Total Charge = -1 + Corrected Absolute Total Charge = 1 + Corrected Is Zwitterion? = False +--------------------------------------------------- +] + unique_index=3 Re (metal) coord_sphere_formula=C6-P-I2 possible_cs=[1, 2, 3, 4, 5, 7] + +Reference Error (mode=ref_molecules): No errors found +Reference Error (mode=hydrogens): No errors found +Reference Error (mode=possible_charges): No errors found +Reference Error (mode=charge_assignment): No errors found +Reference Error (mode=spin_assignment): No errors found diff --git a/tests/data/cell2mol/unitcell_summary.txt b/tests/data/cell2mol/unitcell_summary.txt new file mode 100644 index 00000000..9a2cd643 --- /dev/null +++ b/tests/data/cell2mol/unitcell_summary.txt @@ -0,0 +1,81 @@ +YOXKUS +Total charge comparison result: True +Metal oxidation state comparison result: True + +Molecules in unitcell: +Molecule 0: H24-C23-O-P-I2-Re (TM Complex) totcharge=0 spin_multiplicity=1 smiles=C[c]12->[Re+3]3456(<-[I-])(<-[I-])(<-[C-]#[O+])<-[c]1(C)[c]->3(C)[c-]->4(C[P]->5(c1ccccc1)c1ccccc1)[c]->62C + Re (metal) atom_site_label=Re1 metal_OS=3 metal_spin=1 + |--coord_sphere_formula=C6-P-I2 + |--coord_nr=5 coord_geometry=Trigonal bipyramidal geom_deviation=3.348 + |--(group) ['C'] atom_site_labels=['C23'] denticity=1 + |--(group) ['C', 'C', 'C', 'C', 'C'] atom_site_labels=['C1', 'C5', 'C2', 'C3', 'C4'] denticity=5 haptic_type=eta5(Cp) + |--(group) ['P'] atom_site_labels=['P1'] denticity=1 + |--(group) ['I'] atom_site_labels=['I2'] denticity=1 + |--(group) ['I'] atom_site_labels=['I1'] denticity=1 + C-O (ligand) smiles=[C-]#[O+] denticity=1 totcharge=0 + |--(group) ['C'] atom_site_labels=['C23'] denticity=1 connected_metals=['Re1'] + H24-C22-P (ligand) smiles=[H]c1c([H])c([H])c(P(c2c([H])c([H])c([H])c([H])c2[H])C([H])([H])[c-]2c(C([H])([H])[H])c(C([H])([H])[H])c(C([H])([H])[H])c2C([H])([H])[H])c([H])c1[H] denticity=6 totcharge=-1 + |--(group) ['C', 'C', 'C', 'C', 'C'] atom_site_labels=['C1', 'C5', 'C2', 'C3', 'C4'] denticity=5 haptic_type=eta5(Cp) connected_metals=['Re1'] + |--(group) ['P'] atom_site_labels=['P1'] denticity=1 connected_metals=['Re1'] + I (ligand) smiles=[I-] denticity=1 totcharge=-1 + |--(group) ['I'] atom_site_labels=['I2'] denticity=1 connected_metals=['Re1'] + I (ligand) smiles=[I-] denticity=1 totcharge=-1 + |--(group) ['I'] atom_site_labels=['I1'] denticity=1 connected_metals=['Re1'] +Molecule 1: H24-C23-O-P-I2-Re (TM Complex) totcharge=0 spin_multiplicity=1 smiles=C[c]12->[Re+3]3456(<-[I-])(<-[I-])(<-[C-]#[O+])<-[c]1(C)[c]->3(C)[c-]->4(C[P]->5(c1ccccc1)c1ccccc1)[c]->62C + Re (metal) atom_site_label=Re1 metal_OS=3 metal_spin=1 + |--coord_sphere_formula=C6-P-I2 + |--coord_nr=5 coord_geometry=Trigonal bipyramidal geom_deviation=3.348 + |--(group) ['C'] atom_site_labels=['C23'] denticity=1 + |--(group) ['C', 'C', 'C', 'C', 'C'] atom_site_labels=['C1', 'C2', 'C3', 'C4', 'C5'] denticity=5 haptic_type=eta5(Cp) + |--(group) ['P'] atom_site_labels=['P1'] denticity=1 + |--(group) ['I'] atom_site_labels=['I2'] denticity=1 + |--(group) ['I'] atom_site_labels=['I1'] denticity=1 + C-O (ligand) smiles=[C-]#[O+] denticity=1 totcharge=0 + |--(group) ['C'] atom_site_labels=['C23'] denticity=1 connected_metals=['Re1'] + H24-C22-P (ligand) smiles=[H]c1c([H])c([H])c(P(c2c([H])c([H])c([H])c([H])c2[H])C([H])([H])[c-]2c(C([H])([H])[H])c(C([H])([H])[H])c(C([H])([H])[H])c2C([H])([H])[H])c([H])c1[H] denticity=6 totcharge=-1 + |--(group) ['C', 'C', 'C', 'C', 'C'] atom_site_labels=['C1', 'C2', 'C3', 'C4', 'C5'] denticity=5 haptic_type=eta5(Cp) connected_metals=['Re1'] + |--(group) ['P'] atom_site_labels=['P1'] denticity=1 connected_metals=['Re1'] + I (ligand) smiles=[I-] denticity=1 totcharge=-1 + |--(group) ['I'] atom_site_labels=['I2'] denticity=1 connected_metals=['Re1'] + I (ligand) smiles=[I-] denticity=1 totcharge=-1 + |--(group) ['I'] atom_site_labels=['I1'] denticity=1 connected_metals=['Re1'] +Molecule 2: H24-C23-O-P-I2-Re (TM Complex) totcharge=0 spin_multiplicity=1 smiles=C[c]12->[Re+3]3456(<-[I-])(<-[I-])(<-[C-]#[O+])<-[c]1(C)[c]->3(C)[c-]->4(C[P]->5(c1ccccc1)c1ccccc1)[c]->62C + Re (metal) atom_site_label=Re1 metal_OS=3 metal_spin=1 + |--coord_sphere_formula=C6-P-I2 + |--coord_nr=5 coord_geometry=Trigonal bipyramidal geom_deviation=3.348 + |--(group) ['C'] atom_site_labels=['C23'] denticity=1 + |--(group) ['C', 'C', 'C', 'C', 'C'] atom_site_labels=['C1', 'C5', 'C2', 'C3', 'C4'] denticity=5 haptic_type=eta5(Cp) + |--(group) ['P'] atom_site_labels=['P1'] denticity=1 + |--(group) ['I'] atom_site_labels=['I2'] denticity=1 + |--(group) ['I'] atom_site_labels=['I1'] denticity=1 + C-O (ligand) smiles=[C-]#[O+] denticity=1 totcharge=0 + |--(group) ['C'] atom_site_labels=['C23'] denticity=1 connected_metals=['Re1'] + H24-C22-P (ligand) smiles=[H]c1c([H])c([H])c(P(c2c([H])c([H])c([H])c([H])c2[H])C([H])([H])[c-]2c(C([H])([H])[H])c(C([H])([H])[H])c(C([H])([H])[H])c2C([H])([H])[H])c([H])c1[H] denticity=6 totcharge=-1 + |--(group) ['C', 'C', 'C', 'C', 'C'] atom_site_labels=['C1', 'C5', 'C2', 'C3', 'C4'] denticity=5 haptic_type=eta5(Cp) connected_metals=['Re1'] + |--(group) ['P'] atom_site_labels=['P1'] denticity=1 connected_metals=['Re1'] + I (ligand) smiles=[I-] denticity=1 totcharge=-1 + |--(group) ['I'] atom_site_labels=['I2'] denticity=1 connected_metals=['Re1'] + I (ligand) smiles=[I-] denticity=1 totcharge=-1 + |--(group) ['I'] atom_site_labels=['I1'] denticity=1 connected_metals=['Re1'] +Molecule 3: H24-C23-O-P-I2-Re (TM Complex) totcharge=0 spin_multiplicity=1 smiles=C[c]12->[Re+3]3456(<-[I-])(<-[I-])(<-[C-]#[O+])<-[c]1(C)[c]->3(C)[c-]->4(C[P]->5(c1ccccc1)c1ccccc1)[c]->62C + Re (metal) atom_site_label=Re1 metal_OS=3 metal_spin=1 + |--coord_sphere_formula=C6-P-I2 + |--coord_nr=5 coord_geometry=Trigonal bipyramidal geom_deviation=3.348 + |--(group) ['C'] atom_site_labels=['C23'] denticity=1 + |--(group) ['C', 'C', 'C', 'C', 'C'] atom_site_labels=['C1', 'C2', 'C3', 'C4', 'C5'] denticity=5 haptic_type=eta5(Cp) + |--(group) ['P'] atom_site_labels=['P1'] denticity=1 + |--(group) ['I'] atom_site_labels=['I2'] denticity=1 + |--(group) ['I'] atom_site_labels=['I1'] denticity=1 + C-O (ligand) smiles=[C-]#[O+] denticity=1 totcharge=0 + |--(group) ['C'] atom_site_labels=['C23'] denticity=1 connected_metals=['Re1'] + H24-C22-P (ligand) smiles=[H]c1c([H])c([H])c(P(c2c([H])c([H])c([H])c([H])c2[H])C([H])([H])[c-]2c(C([H])([H])[H])c(C([H])([H])[H])c(C([H])([H])[H])c2C([H])([H])[H])c([H])c1[H] denticity=6 totcharge=-1 + |--(group) ['C', 'C', 'C', 'C', 'C'] atom_site_labels=['C1', 'C2', 'C3', 'C4', 'C5'] denticity=5 haptic_type=eta5(Cp) connected_metals=['Re1'] + |--(group) ['P'] atom_site_labels=['P1'] denticity=1 connected_metals=['Re1'] + I (ligand) smiles=[I-] denticity=1 totcharge=-1 + |--(group) ['I'] atom_site_labels=['I2'] denticity=1 connected_metals=['Re1'] + I (ligand) smiles=[I-] denticity=1 totcharge=-1 + |--(group) ['I'] atom_site_labels=['I1'] denticity=1 connected_metals=['Re1'] +UnitCell Error (mode=reconstruction): No errors found +UnitCell Error (mode=balance_charges): No errors found +UnitCell Error (mode=charge_assignment): No errors found +UnitCell Error (mode=spin_assignment): No errors found