From 7397a049481683f7cb2c89db68470516512671ae Mon Sep 17 00:00:00 2001 From: my-name Date: Sun, 10 Nov 2024 18:49:18 +0100 Subject: [PATCH] Debugging evaluate_as_nitrosyl and assign_charges --- cell2mol/charge_assignment.py | 6 +- cell2mol/classes.py | 51 ++++++--- cell2mol/missingH.py | 4 +- cell2mol/new_cell_reconstruction.py | 2 +- cell2mol/new_charge_assignment.py | 9 +- cell2mol/refcell.py | 2 +- cell2mol/spin.py | 5 +- cell2mol/test/check_Cell_object.ipynb | 145 ++++++++++++++++++++++++++ cell2mol/unitcell.py | 62 ++++++----- cell2mol/xyz2mol.py | 12 ++- 10 files changed, 240 insertions(+), 58 deletions(-) diff --git a/cell2mol/charge_assignment.py b/cell2mol/charge_assignment.py index 7fb65f5f..108a9eaa 100644 --- a/cell2mol/charge_assignment.py +++ b/cell2mol/charge_assignment.py @@ -59,8 +59,8 @@ def get_possible_charge_state(spec: object, debug: int=0): ### After collecting charge states, then best ones are selected if spec.subtype == "ligand": if spec.is_nitrosyl: - if spec.NO_type == "Linear": possible_cs = charge_states[2] ## When Nitrosyl, we sistematically get the correct charge_distribution in [2] (charge = 1)and [0] (charge = 0)for Linear and Bent respectively - elif spec.NO_type == "Bent": possible_cs = charge_states[0] + if spec.NO_type == "Linear": possible_cs = [charge_states[2]] ## When Nitrosyl, we sistematically get the correct charge_distribution in [2] (charge = 1)and [0] (charge = 0)for Linear and Bent respectively + elif spec.NO_type == "Bent": possible_cs = [charge_states[0]] else: # spec.get_connected_atoms() # if [a.label for a in spec.connected_atoms] == ['S', 'S'] : @@ -68,7 +68,7 @@ def get_possible_charge_state(spec: object, debug: int=0): # else : possible_cs = select_charge_distr(charge_states, debug=debug) ## For ligands other than nitrosyl else: possible_cs = select_charge_distr(charge_states, debug=debug) ## For organic molecules - + print(f"GET_POSSIBLE_CHARGE_STATE: {spec.formula} ({spec.subtype}) {spec.cov_factor=} {possible_cs=}") ### Return possible charge states if len(possible_cs) == 0: return None else: return possible_cs diff --git a/cell2mol/classes.py b/cell2mol/classes.py index 0193f048..9d48ab31 100644 --- a/cell2mol/classes.py +++ b/cell2mol/classes.py @@ -298,6 +298,7 @@ def get_protonation_states(self, debug: int=0): # if not hasattr(self,"groups"): self.split_ligand() if not hasattr(self, "is_haptic"): self.get_hapticity() if not hasattr(self, "denticity"): self.get_denticity() + if not hasattr(self, "is_nitrosyl"): self.evaluate_as_nitrosyl() self.protonation_states = get_protonation_states_specie(self, debug=debug) else: if not hasattr(self,"is_haptic"): self.get_hapticity() @@ -436,7 +437,7 @@ def split_complex(self, debug: int=0): newligand.origin = "split_complex" # Define the molecule as parent of the ligand. Bottom-Up hierarchy newligand.add_parent(self, indices=lig_indices) - + if self.check_parent("unitcell"): cell_indices = [a.get_parent_index("unitcell") for a in lig_atoms] newligand.add_parent(self.get_parent("unitcell"), indices=cell_indices) @@ -452,6 +453,7 @@ def split_complex(self, debug: int=0): # Inherit the adjacencies from molecule newligand.inherit_adjmatrix("molecule") # Add ligand to the list. Top-Down hierarchy + # newligand.evaluate_as_nitrosyl() self.ligands.append(newligand) ## Arranges Metals @@ -488,7 +490,7 @@ def __init__(self, labels: list, coord: list, frac_coord: list=None, radii: list self.subtype = "ligand" if frac_coord is not None: self.frac_coord = frac_coord specie.__init__(self, labels, coord, frac_coord, radii) - self.evaluate_as_nitrosyl() + #self.evaluate_as_nitrosyl() ### move to the split_complexes function ####################################################### def __repr__(self): @@ -1332,13 +1334,14 @@ def get_reference_molecules(self, ref_labels: list, ref_fracs: list, cov_factor: refcell.get_subtype("reference") # Get reference molecules blocklist = split_species(ref_labels, ref_pos, cov_factor=cov_factor) - + print(blocklist) self.refmoleclist = [] for b in blocklist: mol_labels = extract_from_list(b, ref_labels, dimension=1) mol_coord = extract_from_list(b, ref_pos, dimension=1) mol_frac_coord = extract_from_list(b, ref_fracs, dimension=1) newmolec = molecule(mol_labels, mol_coord, mol_frac_coord) + print(newmolec) newmolec.add_parent(self, indices=b) newmolec.add_parent(refcell, indices=b) newmolec.set_adjacency_parameters(cov_factor, metal_factor) @@ -1550,6 +1553,7 @@ def get_selected_cs(self, debug: int=0): self.selected_cs = [] for specie in self.unique_species: + print("Get possible charge states for unique specie", specie.formula) tmp = specie.get_possible_cs(debug=debug) if tmp is None: self.selected_cs.append(None) @@ -1614,26 +1618,33 @@ def assign_charges (self, debug: int=0): cs = specie.possible_cs[idx] specie.set_charge(cs) for specie in self.unique_species: + print("Unique Species final charges") if (specie.subtype == "molecule" and specie.iscomplex == False) or (specie.subtype == "ligand"): - print(specie.formula, specie.charge_state, specie.totcharge, specie.smiles) + print(specie.formula, specie.totcharge) + elif specie.subtype == "metal" : + print(specie.formula, specie.charge) for idx, ref in enumerate(self.refmoleclist): print(f"Refenrence Molecule {idx}: {ref.formula}") if ref.iscomplex: for jdx, lig in enumerate(ref.ligands): - for specie in self.unique_species: + for kdx, specie in enumerate(self.unique_species): if specie.subtype == "ligand": issame = compare_species(lig, specie) if issame: set_charge_state (specie, lig, mode=1, debug=debug) - print(lig.formula, specie.formula, issame) + print(lig.formula, specie.formula, lig.totcharge, specie.totcharge, issame) + print("Check Error", f"{idx=}, {jdx=}, {kdx=}", lig.formula, specie.formula, issame) + # print(f"{lig.smiles=}") + # print(f"{specie.smiles=}") + for met in ref.metals: for specie in self.unique_species: if specie.subtype == "metal": issame = compare_metals(met, specie) if issame: met.set_charge(specie.charge) - print(met.formula, specie.formula, issame) + print(met.formula, specie.formula, met.charge, specie.charge, issame) prepare_mol(ref) else: for specie in self.unique_species: @@ -1641,7 +1652,7 @@ def assign_charges (self, debug: int=0): issame = compare_species(ref, specie) if issame: set_charge_state (specie, ref, mode=1, debug=debug) - print(ref.formula, specie.formula, issame) + print(ref.formula, specie.formula, ref.totcharge, specie.totcharge, issame) for idx, mol in enumerate(self.moleclist): print(f"Unit cell Molecule {idx}: {mol.formula}") @@ -1651,20 +1662,30 @@ def assign_charges (self, debug: int=0): issame = compare_reference_indices(ref, mol, debug=debug) if issame: set_charge_state (ref, mol, mode=2, debug=debug) - print(mol.formula, ref.formula, issame) + print(mol.formula, ref.formula, mol.totcharge, ref.totcharge, issame) else: for ref in self.refmoleclist: if ref.iscomplex: - for lig in mol.ligands: - for ref_lig in ref.ligands: + for jdx, lig in enumerate(mol.ligands): + for kdx, ref_lig in enumerate(ref.ligands): issame = compare_reference_indices(ref_lig, lig, debug=debug) if issame: set_charge_state (ref_lig, lig, mode=2, debug=debug) - print(lig.formula, ref_lig.formula, issame) + print(lig.formula, ref_lig.formula, lig.totcharge, ref_lig.totcharge, lig.smiles, ref_lig.smiles, issame) + else : + issame_2 = compare_species(lig, ref_lig) + if issame_2: + set_charge_state (ref_lig, lig, mode=1, debug=debug) + print("Check Error", f"{idx=} {jdx=} {kdx}", lig.formula, ref_lig.formula, issame) for met in mol.metals: for ref_met in ref.metals: if ref_met.get_parent_index("reference") == met.get_parent_index("reference"): met.set_charge(ref_met.charge) + print(met.formula, ref_met.formula, met.charge, ref_met.charge, issame) + else : + issame_2 = compare_metals(met, ref_met) + if issame_2: + met.set_charge(ref_met.charge) prepare_mol(mol) ####################################################### @@ -1770,11 +1791,7 @@ def assign_charges_old (self, debug: int=0) -> object: else: # Only one possible charge distribution -> getcharge for the repeated species self.error_multiple_distrib = False self.error_empty_distrib = False - if debug >= 1: - print(f"\nFINAL Charge Distribution: {final_charge_distribution}\n") - print("#########################################") - print("Assigning Charges and Preparing Molecules") - print("#########################################") + self.moleclist, self.error_prepare_mols = prepare_mols (self.moleclist, self.unique_indices, self.unique_species, final_charge_distribution[0], debug=debug) if self.error_prepare_mols: diff --git a/cell2mol/missingH.py b/cell2mol/missingH.py index f14754cd..bc17098b 100755 --- a/cell2mol/missingH.py +++ b/cell2mol/missingH.py @@ -106,7 +106,7 @@ def check_missingH(refmoleclist: list, debug: int=0): Warning = False # List of Metal Atoms for which O atoms might appear connected directly. - Exceptions_for_CoordWater = ["Re", "V", "Mo", "W"] + Exceptions_for_CoordWater = ["Re", "V", "Mo", "W", "Fe"] if debug >= 2: print("") if debug >= 2: print("##################") @@ -141,7 +141,7 @@ def check_missingH(refmoleclist: list, debug: int=0): else: for jdx, lig in enumerate(ref.ligands): if lig.natoms == 1 and "O" in lig.labels and lig.denticity <= 1: - if any(m.label in Exceptions_for_CoordWater for m in lig.metalatoms): pass + if any(m.label in Exceptions_for_CoordWater for m in lig.metals): pass else: Missing_H_in_CoordWater = True if debug >= 2: print("") diff --git a/cell2mol/new_cell_reconstruction.py b/cell2mol/new_cell_reconstruction.py index 5755d08f..8a6cb5a6 100644 --- a/cell2mol/new_cell_reconstruction.py +++ b/cell2mol/new_cell_reconstruction.py @@ -47,7 +47,7 @@ def modify_cov_factor_due_to_possible_charges (refcell, debug: int=0): else : temp_selection.append(specie.possible_cs) - if debug >= 1: print(f"Covalent factor decreases: {cov_factor=}") + if debug >= 1: print(f"Covalent factor : {cov_factor=}") refcell.assess_errors(mode="hydrogens") if refcell.error_case == 0: if debug >= 1: print(f"OK with decreasing cov_factor {cov_factor=}") diff --git a/cell2mol/new_charge_assignment.py b/cell2mol/new_charge_assignment.py index f07e75f8..093d4a71 100644 --- a/cell2mol/new_charge_assignment.py +++ b/cell2mol/new_charge_assignment.py @@ -73,7 +73,7 @@ def assign_charge_state_for_unique_species(unique_species, final_charges_tuple, specie.set_charges(cs.corr_total_charge, cs.corr_atom_charges, cs.smiles, cs.rdkit_obj) elif specie.subtype == "metal" : charge_list = specie.possible_cs - # idx = charge_list.index(final_charge) + idx = charge_list.index(final_charge) cs = specie.possible_cs[idx] specie.set_charge(cs) for specie in unique_species: @@ -112,8 +112,10 @@ def set_charge_state(reference, target, mode, debug: int=0): if target.formula in ["O4-Cl", "N3", "I3"]: cs = get_charge_manual(target, debug=debug) else : + #if not hasattr(target, "possible_cs"): target.get_possible_cs(debug=debug) target.get_possible_cs(debug=debug) charge_list = [cs.corr_total_charge for cs in target.possible_cs] + print(charge_list, final_charge, target.possible_cs) idx = charge_list.index(final_charge) cs = target.possible_cs[idx] @@ -148,12 +150,13 @@ def set_charge_state(reference, target, mode, debug: int=0): target.charge_state = cs if final_charge != cs.corr_total_charge: print(f"SET_CHARGE_STATE: WARNING!!! {target.formula=} {final_charge=} {cs.corr_total_charge=} final_charge != cs.corr_total_charge") + print("SET_CHARGE_STATE!!!!", f"{mode=}", cs, cs.smiles) target.set_charges(cs.corr_total_charge, cs.corr_atom_charges, cs.smiles, cs.rdkit_obj) print(f"SET_CHARGE_STATE:{target.formula=} {target.totcharge=} {target.smiles=}") ###################################################### def prepare_mol (mol): - tmp_atcharge = np.zeros((mol.natoms)) + tmp_atcharge = np.zeros((mol.natoms), dtype=int) tmp_smiles = [] for lig in mol.ligands: @@ -164,7 +167,7 @@ def prepare_mol (mol): for met in mol.metals: parent_index = met.get_parent_index("molecule") - tmp_atcharge[parent_index] = met.charge + tmp_atcharge[parent_index] = met.charge mol.set_charges(int(sum(tmp_atcharge)), atomic_charges=tmp_atcharge, smiles=tmp_smiles) diff --git a/cell2mol/refcell.py b/cell2mol/refcell.py index 8c165cfd..7ed78ac7 100644 --- a/cell2mol/refcell.py +++ b/cell2mol/refcell.py @@ -69,7 +69,7 @@ def get_unique_species_in_reference (refcell, debug): if debug >= 1: print(f"Unique species: {[specie.formula for specie in refcell.unique_species]}") print(f"Species list: {[specie.formula for specie in refcell.species_list]}\n") - + refcell = modify_cov_factor_due_to_possible_charges(refcell, debug=debug) refcell.get_selected_cs(debug=debug) refcell.assess_errors(mode="possible_charges") diff --git a/cell2mol/spin.py b/cell2mol/spin.py index 385b57d5..b6b38b4f 100644 --- a/cell2mol/spin.py +++ b/cell2mol/spin.py @@ -50,10 +50,13 @@ def assign_spin_complexes (mol:object, debug: int=0) -> None: """ for metal in mol.metals: if not hasattr(metal,"spin"): metal.get_spin(debug=debug) + for ligand in mol.ligands: + if not hasattr(ligand, "is_nitrosyl"): ligand.evaluate_as_nitrosyl() + metals_spin = [metal.spin for metal in mol.metals] if debug >=2: print(f"ASSIGN_SPIN_COMPLEXES: {metals_spin=}") - if any(ligand.is_nitrosyl for ligand in mol.ligands): return None + if any([ligand.is_nitrosyl for ligand in mol.ligands]): return None else : if None in metals_spin : return None elif len(metals_spin) == 1: return metals_spin[0] # Mononuclear complex diff --git a/cell2mol/test/check_Cell_object.ipynb b/cell2mol/test/check_Cell_object.ipynb index b8427a43..8b41e137 100644 --- a/cell2mol/test/check_Cell_object.ipynb +++ b/cell2mol/test/check_Cell_object.ipynb @@ -29,6 +29,151 @@ "rdkit.__version__" ] }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "refcell = np.load(\"ABIJEB/Ref_Cell_ABIJEB.cell\", allow_pickle=True)\n", + "unitcell = np.load(\"ABIJEB/Cell_ABIJEB.cell\", allow_pickle=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "ref = refcell.refmoleclist[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "N-O -1 [N-]=O\n", + "H20-C10-N2-S2 -2 [H]C([H])([S-])C([H])([H])N1C([H])([H])C([H])([H])C([H])([H])N(C([H])([H])C([H])([H])[S-])C([H])([H])C([H])([H])C1([H])[H]\n", + "Fe 2.0\n" + ] + } + ], + "source": [ + "met = ref.metals[0]\n", + "for lig in ref.ligands:\n", + " print(lig.formula, lig.totcharge, lig.smiles)\n", + "for met in ref.metals:\n", + " print(met.label, met.charge)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "H20-C10-N3-O-S2-Fe 0\n", + "Fe 3.0\n", + "H20-C10-N3-O-S2-Fe 0\n", + "Fe 3.0\n", + "H20-C10-N3-O-S2-Fe 0\n", + "Fe 3.0\n", + "H20-C10-N3-O-S2-Fe 0\n", + "Fe 3.0\n" + ] + } + ], + "source": [ + "for mol in unitcell.moleclist:\n", + " print(mol.formula, mol.totcharge)\n", + " for met in mol.metals:\n", + " print(met.label, met.charge)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "N-O\n", + "-1\n", + "H20-C10-N2-S2\n", + "-2\n", + "Fe\n", + "3\n" + ] + } + ], + "source": [ + "for specie in unitcell.unique_species:\n", + " if specie.subtype == \"metal\":\n", + " print(specie.formula, specie.charge)\n", + " else:\n", + " print(specie.formula, specie.totcharge)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "H20-C10-N3-O-S2-Fe -1\n", + "Fe 2.0\n", + "N-O -1\n", + "H20-C10-N2-S2 -2\n" + ] + } + ], + "source": [ + "for mol in unitcell.refmoleclist:\n", + " print(mol.formula, ref.totcharge)\n", + " for met in ref.metals:\n", + " print(met.label, met.charge)\n", + " for lig in ref.ligands:\n", + " print(lig.formula, lig.totcharge)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "met = mol.metals[0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "met." + ] + }, { "cell_type": "code", "execution_count": 6, diff --git a/cell2mol/unitcell.py b/cell2mol/unitcell.py index 217eb75f..cb90ee2c 100644 --- a/cell2mol/unitcell.py +++ b/cell2mol/unitcell.py @@ -8,7 +8,7 @@ from cell2mol.new_c2m_module import cell2mol from cell2mol.new_charge_assignment import assign_charge_state_for_unique_species, balance_charge from cell2mol.other import handle_error - +import copy # Constants VERSION = "2.0" COV_FACTOR = 1.3 @@ -23,26 +23,27 @@ def process_unitcell(input_path, name, current_dir, debug=0): ref_cell_fname = os.path.join(current_dir, f"Ref_Cell_{name}.cell") output_fname = os.path.join(current_dir, "cell2mol.out") - # Redirect stdout to file for logging - with open(output_fname, "w") as output, redirect_stdout(output): - logging.info(f"cell2mol version {VERSION}") - logging.info(f"Initializing cell object from input path: {input_path}") - logging.info(f"Debug level: {debug}") - - # Read CIF file and initialize unit cell parameters - structure = read(input_path) - cell_labels, cell_pos, cell_fracs, cell_vector, cell_param, sym_ops = get_cell_parameters(structure) - - # Create and process unit cell - newcell = create_unitcell_object(name, cell_labels, cell_pos, cell_fracs, cell_vector, cell_param, "unitcell") - - # Process reference cell and update new cell with molecules and properties - refcell = process_refcell(input_path, name, current_dir, debug=debug) - if refcell.error_case == 0: - perform_cell2mol(newcell, refcell, sym_ops, cell_fname, ref_cell_fname, debug) - else: - logging.error("Error encountered while processing the reference cell") + # Process reference cell and update new cell with molecules and properties + refcell = process_refcell(input_path, name, current_dir, debug=debug) + if refcell.error_case == 0: + # Redirect stdout to file for logging + with open(output_fname, "a") as output, redirect_stdout(output): + logging.info(f"cell2mol version {VERSION}") + logging.info(f"Initializing cell object from input path: {input_path}") + logging.info(f"Debug level: {debug}") + # Read CIF file and initialize unit cell parameters + structure = read(input_path) + cell_labels, cell_pos, cell_fracs, cell_vector, cell_param, sym_ops = get_cell_parameters(structure) + + # Create and process unit cell + newcell = create_unitcell_object(name, cell_labels, cell_pos, cell_fracs, cell_vector, cell_param, "unitcell") + + perform_cell2mol(newcell, refcell, sym_ops, cell_fname, ref_cell_fname, debug) + else: + logging.error("Error encountered while processing the reference cell") + + # Handle error cases for the unit cell if hasattr(newcell, 'error_case'): error_fname = os.path.join(current_dir, f"unitcell_error_{newcell.error_case}.out") with open(error_fname, "w") as error_output: @@ -76,10 +77,14 @@ def perform_cell2mol(newcell, refcell, sym_ops, cell_fname, ref_cell_fname, debu cov_factor = refcell.refmoleclist[0].cov_factor if refcell.refmoleclist else COV_FACTOR # Get reference molecules for the new cell - newcell.get_reference_molecules(refcell.labels, refcell.frac_coord, cov_factor=cov_factor, debug=-1) - if not newcell.has_isolated_H: - newcell.check_missing_H(debug=-1) - + # newcell.get_reference_molecules(refcell.labels, refcell.frac_coord, cov_factor=cov_factor, debug=-1) + # if not newcell.has_isolated_H: + # newcell.check_missing_H(debug=-1) + newcell.refmoleclist = copy.deepcopy(refcell.refmoleclist) + + newcell.has_isolated_H = refcell.has_isolated_H + newcell.has_missing_H = refcell.has_missing_H + newcell.error_get_poscharges = refcell.error_get_poscharges logging.info("Starting molecule reconstruction with cell2mol") # Step-by-step molecule reconstruction and error assessment @@ -98,8 +103,13 @@ def perform_cell2mol(newcell, refcell, sym_ops, cell_fname, ref_cell_fname, debu # Assign and balance charges final_charge_distribution, final_charges = balance_charge(newcell.unique_indices, refcell.unique_species, debug=debug) - refcell.unique_species = assign_charge_state_for_unique_species(refcell.unique_species, final_charges[0], debug=debug) - + print(f"{final_charges=}") + refcell.unique_species = assign_charge_state_for_unique_species(newcell.unique_species, final_charges[0], debug=2) + for specie in refcell.unique_species: + if specie.subtype == "metal": + print("refcell.unique_species", specie.formula, specie.charge) + else: + print("refcell.unique_species", specie.formula, specie.totcharge) # Finalize refcell properties and save both cell objects refcell.assign_charges_for_refcell(debug=debug) refcell.assign_spin(debug=debug) diff --git a/cell2mol/xyz2mol.py b/cell2mol/xyz2mol.py index 46137ea3..0e45897b 100644 --- a/cell2mol/xyz2mol.py +++ b/cell2mol/xyz2mol.py @@ -509,10 +509,14 @@ def AC2BO(AC, atoms, charge, allow_charged_fragments=True, use_graph=True): # if atomicNum == 15: # print("Possible valences for:", atomicNum,"are",possible_valence, valence) if len(possible_valence) == 0: - print('WARNING!! Valence of atom', elemdatabase.elementsym[atomicNum], i,\ - 'is',valence,'which bigger than allowed max',max(atomic_valence[atomicNum]),'. Stopping') - possible_valence.append(valence) - wrong += 1 + element = elemdatabase.elementsym[atomicNum] + if elemdatabase.elementperiod[element] < 3 : + print('WARNING!! Valence of atom', element, i,\ + 'is',valence,'which bigger than allowed max',max(atomic_valence[atomicNum]),'. Stopping') + possible_valence.append(valence) + wrong += 1 + else: + possible_valence.append(valence) # sys.exit() valences_list_of_lists.append(possible_valence) #print(f"{wrong=}")