internal static ElementBase GetChemicalElement(XElement cmlElement, out string message) { message = ""; XAttribute xa = cmlElement.Attribute(CMLConstants.AttributeElementType); if (xa != null) { string symbol = xa.Value; ElementBase eb; AtomHelpers.TryParse(symbol, out eb); if (eb is Element element) { return(element); } if (eb is FunctionalGroup functionalGroup) { return(functionalGroup); } //if we got here then it went very wrong message = $"Unrecognised element '{symbol}' in {cmlElement}"; } else { message = $"cml attribute 'elementType' missing from {cmlElement}"; } return(null); }
internal static ElementBase GetElementOrFunctionalGroup(XElement cmlElement, out string message) { message = ""; XAttribute xa = cmlElement.Attribute(CMLConstants.AttributeElementType); if (xa != null) { string symbol = xa.Value; ElementBase eb; AtomHelpers.TryParse(symbol, out eb); if (eb is Element element) { return(element); } if (eb is FunctionalGroup functionalGroup) { // Fix Invalid data; Force internal FG to prime Element if (functionalGroup.Internal) { AtomHelpers.TryParse(functionalGroup.Components[0].Component, out eb); if (eb is Element chemicalElement) { return(chemicalElement); } } return(functionalGroup); } //if we got here then it went very wrong message = $"Unrecognised element '{symbol}' in {cmlElement}"; } else { message = $"cml attribute 'elementType' missing from {cmlElement}"; } return(null); }
private void ReadAtoms(StreamReader reader, int atoms) { int idx = 0; while (!reader.EndOfStream && idx < atoms) { string line = SdFileConverter.GetNextLine(reader); if (!string.IsNullOrEmpty(line)) { // create atom Atom thisAtom = new Atom(); double x = Double.Parse(GetSubString(line, 0, 9), CultureInfo.InvariantCulture); double y = Double.Parse(GetSubString(line, 10, 9), CultureInfo.InvariantCulture); double z = Double.Parse(GetSubString(line, 20, 9), CultureInfo.InvariantCulture); // Inverting Y co-ordinate to make it the right way up. thisAtom.Position = new Point(x, 0 - y); // element type string elType = GetSubString(line, 31, 3); ElementBase eb; var ok = AtomHelpers.TryParse(elType, out eb); if (ok) { if (eb is Element element) { thisAtom.Element = element; } if (eb is FunctionalGroup functionalGroup) { thisAtom.Element = functionalGroup; // Fix Invalid data; Force internal FG to prime Element if (functionalGroup.Internal) { AtomHelpers.TryParse(functionalGroup.Components[0].Component, out eb); if (eb is Element chemicalElement) { thisAtom.Element = chemicalElement; } } } } else { _molecule.Errors.Add($"{elType} at Line {SdFileConverter.LineNumber} is not a valid Element"); _molecule.Errors.Add($"{line}"); } // isotope int delta = ParseInteger(line, 34, 2); if (delta != 0) { thisAtom.IsotopeNumber = delta; } // charge int ch = ParseInteger(line, 36, 3); thisAtom.FormalCharge = FormalChargeFromMolfile(ch); thisAtom.DoubletRadical = DoubletRadicalFromMolfile(ch); // field 3 is atom parity (a *write-only* field, so not used) // int parity = ParseInteger(line, 39, 3) // field 4 hydrogen count // int hCount = ParseInteger(line, 42, 3) // field 5 stereoCareBox // int field5 = ParseInteger(line, 45, 3) // field 6 valency/oxidation state // int oxState = ParseInteger(line, 48, 3) // field 7 H0 designator // int hZero = ParseInteger(line, 51, 3) // atom-atom mapping int atomMap = ParseInteger(line, 60, 3); if (atomMap != 0) { // ToDo: What to do here ??? } // inversion/retention flag // int hZero = ParseInteger(line, 63, 3) // exact change flag // int hZero = ParseInteger(line, 66, 3) idx++; // Add atom to molecule thisAtom.Id = $"a{idx}"; _molecule.AddAtom(thisAtom); thisAtom.Parent = _molecule; atomByNumber.Add(idx, thisAtom); } } }
private static void AddMolecule(dynamic data, Model newModel) { Dictionary <int, string> atoms = new Dictionary <int, string>(); var newMol = new Molecule(); ElementBase ce = Globals.PeriodicTable.C; int atomCount = 0; // GitHub: Issue #13 https://github.com/Chem4Word/Version3/issues/13 if (data.a != null) { foreach (AtomJSON a in data.a) { if (!string.IsNullOrEmpty(a.l)) { ElementBase eb; var ok = AtomHelpers.TryParse(a.l, out eb); if (ok) { if (eb is Element element) { ce = element; } if (eb is FunctionalGroup functionalGroup) { ce = functionalGroup; } } } else { ce = Globals.PeriodicTable.C; } Atom atom = new Atom() { Element = ce, Position = new Point(a.x, a.y) }; if (a.c != null) { atom.FormalCharge = a.c.Value; } atoms.Add(atomCount++, atom.InternalId); newMol.AddAtom(atom); atom.Parent = newMol; } } if (data.b != null) { foreach (BondJSON b in data.b) { string o; if (b.o != null) { o = Globals.OrderValueToOrder(double.Parse(b.o.ToString())); } else { o = Globals.OrderSingle; } Globals.BondStereo s; if (!string.IsNullOrEmpty(b.s)) { if (o == Globals.OrderDouble) { if (b.s.Equals(Ambiguous)) { s = Globals.BondStereo.Indeterminate; } else { s = Globals.BondStereo.None; } } else { if (b.s.Equals(Recessed)) { s = Globals.BondStereo.Hatch; } else if (b.s.Equals(Protruding)) { s = Globals.BondStereo.Wedge; } else if (b.s.Equals(Ambiguous)) { s = Globals.BondStereo.Indeterminate; } else { s = Globals.BondStereo.None; } } } else { s = Globals.BondStereo.None; } // Azure DevOps #715 if (b.b.HasValue && b.b.Value < atoms.Count && b.e.HasValue && b.e.Value < atoms.Count) { var sa = atoms[b.b.Value]; var ea = atoms[b.e.Value]; Bond newBond = new Bond() { StartAtomInternalId = sa, EndAtomInternalId = ea, Stereo = s, Order = o }; newMol.AddBond(newBond); newBond.Parent = newMol; } } } newModel.AddMolecule(newMol); newMol.Parent = newModel; }
/// <summary> /// Expand the Functional Group into a flattened list of terms /// </summary> /// <param name="reverse"></param> /// <param name="consolidate"></param> /// <returns></returns> public List <FunctionalGroupTerm> ExpandIntoTerms(bool reverse = false, bool consolidate = true) { List <FunctionalGroupTerm> result = new List <FunctionalGroupTerm>(); if (ShowAsSymbol) { var term = new FunctionalGroupTerm { IsAnchor = true }; term.Parts = ExpandSymbol(Symbol); result.Add(term); } else { for (int i = 0; i < Components.Count; i++) { var term = new FunctionalGroupTerm { IsAnchor = i == 0, Parts = ExpandGroupV2(Components[i]) }; result.Add(term); } } // Consolidate parts of each term if (consolidate) { foreach (var term in result) { if (term.Parts.Count > 1) { var newParts = new List <FunctionalGroupPart>(); var newPart = term.Parts[0]; newParts.Add(newPart); for (int i = 1; i < term.Parts.Count; i++) { if (term.Parts[i].Type == term.Parts[i - 1].Type) { newPart.Text += term.Parts[i].Text; } else { newPart = term.Parts[i]; newParts.Add(newPart); } } term.Parts = newParts; } } } if (Flippable && reverse) { result.Reverse(); } return(result); // Local Functions // Ensure that Symbols such as "R{1}" and "{i}Pr" are expanded into parts List <FunctionalGroupPart> ExpandSymbol(string symbol) { List <FunctionalGroupPart> expanded = new List <FunctionalGroupPart>(); if (symbol.Contains("{") || symbol.Contains("}")) { var part = new FunctionalGroupPart(); foreach (char c in symbol) { switch (c) { case '{': if (!string.IsNullOrEmpty(part.Text)) { expanded.Add(part); } part = new FunctionalGroupPart { Type = FunctionalGroupPartType.Superscript }; break; case '}': expanded.Add(part); part = new FunctionalGroupPart(); break; default: part.Text += c; break; } } // Ensure that trailing characters are not lost if (!string.IsNullOrEmpty(part.Text)) { expanded.Add(part); } } else { expanded.Add(new FunctionalGroupPart { Text = symbol }); } return(expanded); } List <FunctionalGroupPart> ExpandGroupV2(Group componentGroup, bool flipped = false) { List <FunctionalGroupPart> expanded = new List <FunctionalGroupPart>(); ElementBase elementBase; if (AtomHelpers.TryParse(componentGroup.Component, out elementBase)) { if (elementBase is Element element) { expanded.Add(new FunctionalGroupPart { Text = element.Symbol }); if (componentGroup.Count != 1) { var part = new FunctionalGroupPart { Type = FunctionalGroupPartType.Subscript, Text = $"{componentGroup.Count}" }; expanded.Add(part); } } if (elementBase is FunctionalGroup functionalGroup) { var part = new FunctionalGroupPart(); if (componentGroup.Count != 1) { part.Text += "("; expanded.Add(part); part = new FunctionalGroupPart(); } if (functionalGroup.ShowAsSymbol) { if (!string.IsNullOrEmpty(part.Text)) { expanded.Add(part); } expanded.AddRange(ExpandSymbol(functionalGroup.Symbol)); part = new FunctionalGroupPart(); } else { if (functionalGroup.Flippable && flipped) { for (int ii = functionalGroup.Components.Count - 1; ii >= 0; ii--) { expanded.AddRange(ExpandGroupV2(functionalGroup.Components[ii])); } } else { foreach (var fgc in functionalGroup.Components) { expanded.AddRange(ExpandGroupV2(fgc)); } } } if (componentGroup.Count != 1) { part.Text += ")"; expanded.Add(part); part = new FunctionalGroupPart { Type = FunctionalGroupPartType.Subscript, Text = $"{componentGroup.Count}" }; expanded.Add(part); part = new FunctionalGroupPart(); } // Ensure that trailing characters are not lost if (!string.IsNullOrEmpty(part.Text)) { expanded.Add(part); } } } return(expanded); } }