/// <summary> /// The actual writing of the output. /// </summary> /// <param name="obj"></param> /// <exception cref="CDKException">could not write RGroup query</exception> public override void Write(IChemObject obj) { if (!(obj is IRGroupQuery)) { throw new CDKException("Only IRGroupQuery input is accepted."); } try { IRGroupQuery rGroupQuery = (IRGroupQuery)obj; string now = DateTime.UtcNow.ToString("MMddyyHHmm", DateTimeFormatInfo.InvariantInfo); IAtomContainer rootAtc = rGroupQuery.RootStructure; //Construct header var rootBlock = new StringBuilder(); string header = "$MDL REV 1 " + now + LSEP + "$MOL" + LSEP + "$HDR" + LSEP + " Rgroup query file (RGFile)" + LSEP + " CDK " + now + "2D" + LSEP + LSEP + "$END HDR" + LSEP + "$CTAB"; rootBlock.Append(header).Append(LSEP); //Construct the root structure, the scaffold string rootCTAB = GetCTAB(rootAtc); rootCTAB = rootCTAB.Replace(LSEP + "M END" + LSEP, ""); rootBlock.Append(rootCTAB).Append(LSEP); //Write the root's LOG lines foreach (var rgrpNum in rGroupQuery.RGroupDefinitions.Keys) { RGroupList rgList = rGroupQuery.RGroupDefinitions[rgrpNum]; int restH = rgList.IsRestH ? 1 : 0; string logLine = "M LOG" + MDLV2000Writer.FormatMDLInt(1, 3) + MDLV2000Writer.FormatMDLInt(rgrpNum, 4) + MDLV2000Writer.FormatMDLInt(rgList.RequiredRGroupNumber, 4) + MDLV2000Writer.FormatMDLInt(restH, 4) + " " + rgList.Occurrence; rootBlock.Append(logLine).Append(LSEP); } //AAL lines are optional, they are needed for R-atoms with multiple bonds to the root //for which the order of the attachment points can not be implicitly derived //from the order in the atom block. See CT spec for more on that. foreach (var rgroupAtom in rGroupQuery.RootAttachmentPoints.Keys) { var rApo = rGroupQuery.RootAttachmentPoints[rgroupAtom]; if (rApo.Count > 1) { int prevPos = -1; int apoIdx = 1; bool implicitlyOrdered = true; while (rApo.ContainsKey(apoIdx) && implicitlyOrdered) { IAtom partner = rApo[apoIdx].GetOther(rgroupAtom); for (int atIdx = 0; atIdx < rootAtc.Atoms.Count; atIdx++) { if (rootAtc.Atoms[atIdx].Equals(partner)) { if (atIdx < prevPos) { implicitlyOrdered = false; } prevPos = atIdx; break; } } apoIdx++; } if (!implicitlyOrdered) { StringBuilder aalLine = new StringBuilder("M AAL"); for (int atIdx = 0; atIdx < rootAtc.Atoms.Count; atIdx++) { if (rootAtc.Atoms[atIdx].Equals(rgroupAtom)) { aalLine.Append(MDLV2000Writer.FormatMDLInt((atIdx + 1), 4)); aalLine.Append(MDLV2000Writer.FormatMDLInt(rApo.Count, 3)); apoIdx = 1; while (rApo.ContainsKey(apoIdx)) { IAtom partner = rApo[apoIdx].GetOther(rgroupAtom); for (int a = 0; a < rootAtc.Atoms.Count; a++) { if (rootAtc.Atoms[a].Equals(partner)) { aalLine.Append(MDLV2000Writer.FormatMDLInt(a + 1, 4)); aalLine.Append(MDLV2000Writer.FormatMDLInt(apoIdx, 4)); } } apoIdx++; } } } rootBlock.Append(aalLine.ToString()).Append(LSEP); } } } rootBlock.Append("M END").Append(LSEP).Append("$END CTAB").Append(LSEP); //Construct each R-group block var rgpBlock = new StringBuilder(); foreach (var rgrpNum in rGroupQuery.RGroupDefinitions.Keys) { var rgrpList = rGroupQuery.RGroupDefinitions[rgrpNum].RGroups; if (rgrpList != null && rgrpList.Count != 0) { rgpBlock.Append("$RGP").Append(LSEP);; rgpBlock.Append(MDLV2000Writer.FormatMDLInt(rgrpNum, 4)).Append(LSEP); foreach (var rgroup in rgrpList) { //CTAB block rgpBlock.Append("$CTAB").Append(LSEP); string ctab = GetCTAB(rgroup.Group); ctab = ctab.Replace(LSEP + "M END" + LSEP, ""); rgpBlock.Append(ctab).Append(LSEP); //The APO line IAtom firstAttachmentPoint = rgroup.FirstAttachmentPoint; IAtom secondAttachmentPoint = rgroup.SecondAttachmentPoint; int apoCount = 0; if (firstAttachmentPoint != null) { var apoLine = new StringBuilder(); for (int atIdx = 0; atIdx < rgroup.Group.Atoms.Count; atIdx++) { if (rgroup.Group.Atoms[atIdx].Equals(firstAttachmentPoint)) { apoLine.Append(MDLV2000Writer.FormatMDLInt((atIdx + 1), 4)); apoCount++; if (secondAttachmentPoint != null && secondAttachmentPoint.Equals(firstAttachmentPoint)) { apoLine.Append(MDLV2000Writer.FormatMDLInt(3, 4)); } else { apoLine.Append(MDLV2000Writer.FormatMDLInt(1, 4)); } } } if (secondAttachmentPoint != null && !secondAttachmentPoint.Equals(firstAttachmentPoint)) { for (int atIdx = 0; atIdx < rgroup.Group.Atoms.Count; atIdx++) { if (rgroup.Group.Atoms[atIdx].Equals(secondAttachmentPoint)) { apoCount++; apoLine.Append(MDLV2000Writer.FormatMDLInt((atIdx + 1), 4)); apoLine.Append(MDLV2000Writer.FormatMDLInt(2, 4)); } } } if (apoCount > 0) { apoLine.Insert(0, "M APO" + MDLV2000Writer.FormatMDLInt(apoCount, 3)); rgpBlock.Append(apoLine).Append(LSEP); } } rgpBlock.Append("M END").Append(LSEP); rgpBlock.Append("$END CTAB").Append(LSEP); } rgpBlock.Append("$END RGP").Append(LSEP); } } rgpBlock.Append("$END MOL").Append(LSEP); writer.Write(rootBlock.ToString()); writer.Write(rgpBlock.ToString()); writer.Flush(); } catch (IOException e) { Console.Error.WriteLine(e.StackTrace); throw new CDKException("Unexpected exception when writing RGFile" + LSEP + e.Message); } }