/// <summary> /// checks that atomArray is in array format with unduplicated valid /// elements. must have elementType and count attributes of equal lengths. /// </summary> /// <param name="atomArray">to check (not modified)</param> /// <exception cref="ApplicationException">if invalid</exception> public static void CheckAtomArrayFormat(CMLAtomArray atomArray) { if (atomArray.HasElements) { throw new ApplicationException("No children allowed for formula/atomArray"); } var elements = atomArray.ElementType; var counts = atomArray.Count; if (elements == null || counts == null) { throw new ApplicationException("formula/atomArray must have elementType and count attributes"); } if (elements.Count != counts.Count) { throw new ApplicationException("formula/atomArray must have equal length elementType and count values"); } var elementSet = new HashSet <string>(); for (int i = 0; i < elements.Count; i++) { if (elements[i] != null && !(elements[i].Equals("null", StringComparison.Ordinal))) { if (elementSet.Contains(elements[i])) { throw new ApplicationException($"formula/atomArray@elementType has duplicate element: {elements[i]}"); } elementSet.Add(elements[i]); if (counts[i] <= 0 && !allowNegativeCounts) { throw new ApplicationException($"formula/atomArray@count has nonPositive value: {counts[i]} {elements[i]}"); } } } }
/// <summary> /// Adds element and count to formula. If element is already known, /// increments the count. /// </summary> /// <param name="elementType">the element atomicSymbol</param> /// <param name="count">the element multiplier</param> public void Add(string elementType, double count) { CMLAtomArray atomArray = AtomArrayElements.FirstOrDefault(); if (atomArray == null) { // if no atomArray , create from concise Normalize(); // if still none, create new one with empty attributes if (atomArray == null) { atomArray = new CMLAtomArray(); Add(atomArray); atomArray.ElementType = Array.Empty <string>(); atomArray.Count = Array.Empty <double>(); } } var elements = GetElementTypes(); if (elements == null) { elements = Array.Empty <string>(); } var counts = GetCounts()?.ToArray(); if (counts == null) { counts = Array.Empty <double>(); } var nelem = elements.Count; bool added = false; for (int i = 0; i < nelem; i++) { if (elements[i].Equals(elementType, StringComparison.Ordinal)) { counts[i] += count; added = true; break; } } if (!added) { var newElem = elements.ToList(); newElem.Add(elementType); var newCount = counts.ToList(); newCount.Add(count); atomArray.ElementType = newElem; atomArray.Count = newCount; } else { atomArray.ElementType = elements; atomArray.Count = counts; } int formalCharge = (this.Attribute(Attribute_formalCharge) == null) ? 0 : this.FormalCharge; string conciseS = atomArray.GenerateConcise(formalCharge); SetAttributeValue(Attribute_concise, conciseS); }
CMLAtomArray CreateAndAddAtomArrayAndFormalChargeFromConcise(string concise) { var atomArray = new CMLAtomArray(); if (concise != null) { var elements = new List <string>(); var counts = new List <double>(); var tokens = Regex.Split(concise, @"\s"); var nelement = tokens.Length / 2; for (int i = 0; i < nelement; i++) { var elem = tokens[2 * i]; var ce = NCDK.ChemicalElement.OfSymbol(elem).AtomicNumber; if (ce == AtomicNumbers.Unknown) { throw new ApplicationException($"Unknown chemical element: {elem}"); } if (elements.Contains(elem)) { throw new ApplicationException($"Duplicate element in concise: {elem}"); } elements.Add(elem); var countS = tokens[2 * i + 1]; try { counts.Add(double.Parse(countS, NumberFormatInfo.InvariantInfo)); } catch (FormatException) { throw new ApplicationException($"Bad element count in concise: {countS}"); } } if (tokens.Length > nelement * 2) { var chargeS = tokens[nelement * 2]; try { var formalCharge = int.Parse(chargeS, NumberFormatInfo.InvariantInfo); FormalCharge = formalCharge; } catch (FormatException) { throw new ApplicationException($"Bad formal charge in concise: {chargeS}"); } } var countD = new double[nelement]; for (int i = 0; i < nelement; i++) { countD[i] = counts[i]; } atomArray.ElementType = elements.ToArray(); atomArray.Count = countD; } Add(atomArray); return(atomArray); }
public void Add(CMLAtom atom) { var aa = this.Element(XName_CML_atomArray); if (aa == null) { aa = new CMLAtomArray(); this.Add(aa); } aa.Add(atom); }
// FIXME move to tools private string NormalizeConciseAndFormalCharge(string conciseS, int formalCharge) { if (conciseS != null) { CMLAtomArray atomArray = CreateAndAddAtomArrayAndFormalChargeFromConcise(conciseS); if (atomArray != null) { atomArray.Sort(SortType.CHFirst); conciseS = atomArray.GenerateConcise(formalCharge); } } return(conciseS); }
/// <summary> /// Count for corresponding element. /// No defaults. /// </summary> /// <returns>double[] array of element counts; or null for none.</returns> public IReadOnlyList <string> GetElementTypes() { CMLAtomArray atomArray = AtomArrayElements.FirstOrDefault(); return(atomArray?.ElementType); }
/// <summary> /// Count for corresponding element. /// No defaults. /// </summary> /// <returns>double[] array of element counts; or null for none.</returns> public IReadOnlyList <double> GetCounts() { CMLAtomArray atomArray = AtomArrayElements.FirstOrDefault(); return(atomArray?.Count); }
// element: formula // element: atomArray public void Normalize() { // create all possible renderings of formula // any or all may be present // concise var conciseAtt = this.Attribute(Attribute_concise); // formal charge int formalCharge = 0; if (this.Attribute(Attribute_formalCharge) != null) { formalCharge = int.Parse(this.Attribute(Attribute_formalCharge).Value, NumberFormatInfo.InvariantInfo); } string conciseS = conciseAtt?.Value; // convention string convention = this.Convention; // inline formula (might be SMILES) string inline = this.Inline; if (inline != null) { inline = inline.Trim(); } // atomArray CMLAtomArray atomArray = null; string atomArray2Concise = null; var atomArrays = this.Elements(XName_CML_atomArray).Cast <CMLAtomArray>().ToReadOnlyList(); if (atomArrays.Count > 1) { throw new ApplicationException($"Only one atomArray child allowed for formula; found: {atomArrays.Count}"); } else if (atomArrays.Count == 1) { atomArray = atomArrays.First(); atomArray.Sort(SortType.CHFirst); atomArray2Concise = atomArray.GenerateConcise(formalCharge); } // concise from inline if (inline != null) { if (SMILES.Equals(convention, StringComparison.Ordinal) || SMILES1.Equals(convention, StringComparison.Ordinal)) { } } if (conciseS == null) { if (atomArray2Concise != null) { conciseS = atomArray2Concise; } } if (conciseS != null) { conciseS = NormalizeConciseAndFormalCharge(conciseS, formalCharge); } // if no atomArray, create if (atomArray == null) { // causes problems with Jmol } else { CheckAtomArrayFormat(atomArray); } if (atomArray != null) { atomArray.Sort(SortType.CHFirst); } // check consistency if (atomArray2Concise != null && !atomArray2Concise.Equals(conciseS, StringComparison.Ordinal)) { throw new ApplicationException($"concise ({conciseS}) and atomArray ({atomArray2Concise}) differ"); } if (conciseS != null) { // by this time we may have generated a non-zero formal charge, so normalize it into concise conciseS = NormalizeConciseAndFormalCharge(conciseS, this.FormalCharge); ForceConcise(conciseS); } }
/// <summary> /// Customize Molecule. /// </summary> /// <param name="molecule"></param> /// <param name="nodeToAdd"></param> public void Customize(IAtomContainer molecule, object nodeToAdd) { if (!(nodeToAdd is CMLMolecule)) { throw new CDKException("NodeToAdd must be of type nu.xom.Element!"); } //The nodeToAdd CMLMolecule molToCustomize = (CMLMolecule)nodeToAdd; if ((molecule is MDMolecule)) { MDMolecule mdmol = (MDMolecule)molecule; molToCustomize.Convention = "md:mdMolecule"; molToCustomize.SetAttributeValue(XNamespace.Xmlns + "md", NS_MD.NamespaceName); //Residues if (mdmol.GetResidues().Count > 0) { foreach (var residue in mdmol.GetResidues()) { int number = residue.GetNumber(); CMLMolecule resMol = new CMLMolecule { DictRef = "md:residue", Title = residue.Name }; //Append resNo CMLScalar residueNumber = new CMLScalar(number); residueNumber.SetAttributeValue(Attribute_dictRef, "md:resNumber"); resMol.Add(residueNumber); // prefix for residue atom id string rprefix = "r" + number; //Append atoms CMLAtomArray ar = new CMLAtomArray(); for (int i = 0; i < residue.Atoms.Count; i++) { CMLAtom cmlAtom = new CMLAtom { // Console.Out.WriteLine("atom ID: "+ residue.Atoms[i].Id); // cmlAtom.AddAttribute(new Attribute("ref", residue.Atoms[i].Id)); // the next thing is better, but exception // // setRef to keep consistent usage // setId to satisfy Jumbo 54. need for all atoms to have id Ref = residue.Atoms[i].Id, Id = rprefix + "_" + residue.Atoms[i].Id }; ar.Add(cmlAtom); } resMol.Add(ar); molToCustomize.Add(resMol); } } //Chargegroups if (mdmol.GetChargeGroups().Count > 0) { foreach (var chargeGroup in mdmol.GetChargeGroups()) { int number = chargeGroup.GetNumber(); //FIXME: persist the ChargeGroup CMLMolecule cgMol = new CMLMolecule { DictRef = "md:chargeGroup" }; // etc: add name, refs to atoms etc //Append chgrpNo CMLScalar cgNo = new CMLScalar(number) { DictRef = "md:cgNumber" }; cgMol.Add(cgNo); // prefix for residue atom id string cprefix = "cg" + number; //Append atoms from chargeGroup as it is an AC CMLAtomArray ar = new CMLAtomArray(); for (int i = 0; i < chargeGroup.Atoms.Count; i++) { CMLAtom cmlAtom = new CMLAtom { // setRef to keep consistent usage // setId to satisfy Jumbo 5.4 need for all atoms to have id Ref = chargeGroup.Atoms[i].Id, Id = cprefix + "_" + chargeGroup.Atoms[i].Id }; //Append switching atom? if (chargeGroup.Atoms[i].Equals(chargeGroup.GetSwitchingAtom())) { CMLScalar scalar = new CMLScalar { DictRef = "md:switchingAtom" }; cmlAtom.Add(scalar); } ar.Add(cmlAtom); } cgMol.Add(ar); molToCustomize.Add(cgMol); } } } }