Skip to content

Commit

Permalink
Merge pull request #370 from cdk/patch/ctfile_dimension_field
Browse files Browse the repository at this point in the history
Looks good to me.
  • Loading branch information
egonw committed Oct 1, 2017
2 parents 4c252bf + 35dfb04 commit 8f14ed9
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 31 deletions.
Expand Up @@ -314,6 +314,7 @@ private IAtomContainer readAtomContainer(IAtomContainer molecule) throws CDKExce

int linecount = 0;
String title = null;
String program = null;
String remark = null;
String line = "";

Expand All @@ -333,6 +334,7 @@ private IAtomContainer readAtomContainer(IAtomContainer molecule) throws CDKExce
}
line = input.readLine();
linecount++;
program = line;
line = input.readLine();
linecount++;
if (line.length() > 0) {
Expand Down Expand Up @@ -406,8 +408,10 @@ private IAtomContainer readAtomContainer(IAtomContainer molecule) throws CDKExce
}
}
} else if (!hasZ) {

if (!forceReadAs3DCoords.isSet()) {
//' CDK 09251712073D'
// 0123456789012345678901
if (!(program.length() >= 22 && program.substring(20, 22).equals("3D"))
&& !forceReadAs3DCoords.isSet()) {
for (IAtom atomToUpdate : atoms) {
Point3d p3d = atomToUpdate.getPoint3d();
if (p3d != null) {
Expand Down
Expand Up @@ -330,6 +330,8 @@ private void writeChemFile(IChemFile file) throws Exception {
* @param container Molecule that is written to an OutputStream
*/
public void writeMolecule(IAtomContainer container) throws Exception {

final int dim = getNumberOfDimensions(container);
String line = "";
Map<Integer, Integer> rgroups = null;
Map<Integer, String> aliases = null;
Expand All @@ -352,6 +354,10 @@ public void writeMolecule(IAtomContainer container) throws Exception {
*/
writer.write(" CDK ");
writer.write(new SimpleDateFormat("MMddyyHHmm").format(System.currentTimeMillis()));
if (dim != 0) {
writer.write(Integer.toString(dim));
writer.write('D');
}
writer.write('\n');

String comment = (String) container.getProperty(CDKConstants.REMARK);
Expand Down Expand Up @@ -383,20 +389,30 @@ public void writeMolecule(IAtomContainer container) throws Exception {
for (int f = 0; f < container.getAtomCount(); f++) {
IAtom atom = container.getAtom(f);
line = "";
if (atom.getPoint3d() != null && !forceWriteAs2DCoords.isSet()) {
line += formatMDLFloat((float) atom.getPoint3d().x);
line += formatMDLFloat((float) atom.getPoint3d().y);
line += formatMDLFloat((float) atom.getPoint3d().z) + " ";
} else if (atom.getPoint2d() != null) {
line += formatMDLFloat((float) atom.getPoint2d().x);
line += formatMDLFloat((float) atom.getPoint2d().y);
line += " 0.0000 ";
} else {
// if no coordinates available, then output a number
// of zeros
line += formatMDLFloat((float) 0.0);
line += formatMDLFloat((float) 0.0);
line += formatMDLFloat((float) 0.0) + " ";
switch (dim) {
case 0:
// if no coordinates available, then output a number
// of zeros
line += " 0.0000 0.0000 0.0000 ";
break;
case 2:
if (atom.getPoint2d() != null) {
line += formatMDLFloat((float) atom.getPoint2d().x);
line += formatMDLFloat((float) atom.getPoint2d().y);
line += " 0.0000 ";
} else {
line += " 0.0000 0.0000 0.0000 ";
}
break;
case 3:
if (atom.getPoint3d() != null) {
line += formatMDLFloat((float) atom.getPoint3d().x);
line += formatMDLFloat((float) atom.getPoint3d().y);
line += formatMDLFloat((float) atom.getPoint3d().z) + " ";
} else {
line += " 0.0000 0.0000 0.0000 ";
}
break;
}
if (container.getAtom(f) instanceof IPseudoAtom) {
//according to http://www.google.co.uk/url?sa=t&ct=res&cd=2&url=http%3A%2F%2Fwww.mdl.com%2Fdownloads%2Fpublic%2Fctfile%2Fctfile.pdf&ei=MsJjSMbjAoyq1gbmj7zCDQ&usg=AFQjCNGaJSvH4wYy4FTXIaQ5f7hjoTdBAw&sig2=eSfruNOSsdMFdlrn7nhdAw an R group is written as R#
Expand Down Expand Up @@ -988,6 +1004,16 @@ private <T> List<List<T>> wrap(Collection<T> set, int lim) {
return wrapped;
}

private int getNumberOfDimensions(IAtomContainer mol) {
for (IAtom atom : mol.atoms()) {
if (atom.getPoint3d() != null && !forceWriteAs2DCoords.isSet())
return 3;
else if (atom.getPoint2d() != null)
return 2;
}
return 0;
}

private void writeRadicalPattern(Iterator<Map.Entry<Integer, SPIN_MULTIPLICITY>> iterator, int i)
throws IOException {

Expand Down
Expand Up @@ -86,7 +86,7 @@
public final class MDLV3000Writer extends DefaultChemObjectWriter {

public static final SimpleDateFormat HEADER_DATE_FORMAT = new SimpleDateFormat("MMddyyHHmm");
public static final NumberFormat DECIMAL_FORMAT = new DecimalFormat(".####");
public static final NumberFormat DECIMAL_FORMAT = new DecimalFormat("#.####");
private static final Pattern R_GRP_NUM = Pattern.compile("R(\\d+)");
private V30LineWriter writer;

Expand Down Expand Up @@ -163,6 +163,11 @@ private void writeHeader(IAtomContainer mol) throws IOException {
*/
writer.writeDirect(" CDK ");
writer.writeDirect(HEADER_DATE_FORMAT.format(System.currentTimeMillis()));
final int dim = getNumberOfDimensions(mol);
if (dim != 0) {
writer.writeDirect(Integer.toString(dim));
writer.writeDirect('D');
}
writer.writeDirect('\n');

String comment = mol.getProperty(CDKConstants.REMARK);
Expand Down Expand Up @@ -225,6 +230,7 @@ private void writeAtomBlock(IAtomContainer mol, IAtom[] atoms, Map<IChemObject,
Map<IAtom, ITetrahedralChirality> atomToStereo) throws IOException, CDKException {
if (mol.getAtomCount() == 0)
return;
final int dim = getNumberOfDimensions(mol);
writer.write("BEGIN ATOM\n");
int atomIdx = 0;
for (IAtom atom : atoms) {
Expand Down Expand Up @@ -267,18 +273,31 @@ private void writeAtomBlock(IAtomContainer mol, IAtom[] atoms, Map<IChemObject,
.write(' ')
.write(symbol)
.write(' ');

Point2d p2d = atom.getPoint2d();
Point3d p3d = atom.getPoint3d();
if (p2d != null) {
writer.write(p2d.x).write(' ')
.write(p2d.y).write(' ')
.write("0 ");
} else if (p3d != null) {
writer.write(p3d.x).write(' ')
.write(p3d.y).write(' ')
.write(p3d.z).write(' ');
} else {
writer.write("0 0 0 ");
switch (dim) {
case 0:
writer.write("0 0 0 ");
break;
case 2:
if (p2d != null) {
writer.write(p2d.x).writeDirect(' ')
.write(p2d.y).writeDirect(' ')
.write("0 ");
} else {
writer.write("0 0 0 ");
}
break;
case 3:
if (p3d != null) {
writer.write(p3d.x).writeDirect(' ')
.write(p3d.y).writeDirect(' ')
.write(p3d.z).writeDirect(' ');
} else {
writer.write("0 0 0 ");
}
break;
}
writer.write(nullAsZero(atom.getProperty(ATOM_ATOM_MAPPING, Integer.class)));

Expand Down Expand Up @@ -481,6 +500,16 @@ private List<Sgroup> getSgroups(IAtomContainer mol) {
return sgroups;
}

private int getNumberOfDimensions(IAtomContainer mol) {
for (IAtom atom : mol.atoms()) {
if (atom.getPoint3d() != null)
return 3;
else if (atom.getPoint2d() != null)
return 2;
}
return 0;
}

/**
* Write the Sgroup block to the output.
*
Expand Down
Expand Up @@ -561,6 +561,24 @@ public void testZeroZCoordinates() throws Exception {
assertTrue(has3d);
}

/**
* @cdk.bug 1732307
*/
@Test
public void testZeroZCoordinates3DMarked() throws Exception {
String filename = "data/mdl/nozcoord.sdf";
logger.info("Testing: " + filename);
InputStream ins = this.getClass().getClassLoader().getResourceAsStream(filename);
MDLV2000Reader reader = new MDLV2000Reader(ins);
IAtomContainer mol = reader.read(DefaultChemObjectBuilder.getInstance().newInstance(IAtomContainer.class));
reader.close();
Assert.assertNotNull(mol);
Assert.assertEquals(5, mol.getAtomCount());

boolean has3d = GeometryUtil.has3DCoordinates(mol);
assertTrue(has3d);
}

/**
* @cdk.bug 1826577
*/
Expand Down
Expand Up @@ -54,6 +54,7 @@
import org.openscience.cdk.interfaces.IChemModel;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.interfaces.IPseudoAtom;
import org.openscience.cdk.interfaces.ISingleElectron;
import org.openscience.cdk.interfaces.ITetrahedralChirality;
import org.openscience.cdk.io.listener.PropertiesListener;
import org.openscience.cdk.sgroup.Sgroup;
Expand Down Expand Up @@ -833,4 +834,51 @@ public void aromaticBondTypesEnabled() throws Exception {
}
assertThat(sw.toString(), containsString(" 1 2 4 0 0 0 0 \n"));
}

@Test
public void writeDimensionField() throws Exception {
IAtomContainer mol = builder.newAtomContainer();
IAtom atom = builder.newAtom();
atom.setSymbol("C");
atom.setImplicitHydrogenCount(4);
atom.setPoint2d(new Point2d(0.5, 0.5));
mol.addAtom(atom);
StringWriter sw = new StringWriter();
try (MDLV2000Writer mdlw = new MDLV2000Writer(sw)) {
mdlw.write(mol);
}
assertThat(sw.toString(), containsString("2D"));
}

@Test
public void writeDimensionField3D() throws Exception {
IAtomContainer mol = builder.newAtomContainer();
IAtom atom = builder.newAtom();
atom.setSymbol("C");
atom.setImplicitHydrogenCount(4);
atom.setPoint3d(new Point3d(0.5, 0.5, 0.1));
mol.addAtom(atom);
StringWriter sw = new StringWriter();
try (MDLV2000Writer mdlw = new MDLV2000Writer(sw)) {
mdlw.write(mol);
}
assertThat(sw.toString(), containsString("3D"));
}

@Test
public void writeMoreThan8Radicals() throws Exception {
IAtomContainer mol = builder.newAtomContainer();
for (int i = 0; i < 20; i++) {
IAtom atom = builder.newAtom();
atom.setSymbol("C");
mol.addAtom(atom);
mol.addSingleElectron(builder.newInstance(ISingleElectron.class, atom));
}
StringWriter sw = new StringWriter();
try (MDLV2000Writer mdlw = new MDLV2000Writer(sw)) {
mdlw.write(mol);
}
assertThat(sw.toString(),
containsString("M RAD 8 9 2 10 2 11 2 12 2 13 2 14 2 15 2 16 2"));
}
}
Expand Up @@ -30,22 +30,27 @@
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.interfaces.ITetrahedralChirality;
import org.openscience.cdk.sgroup.Sgroup;
import org.openscience.cdk.sgroup.SgroupKey;
import org.openscience.cdk.sgroup.SgroupType;
import org.openscience.cdk.silent.Atom;
import org.openscience.cdk.silent.AtomContainer;
import org.openscience.cdk.silent.Bond;
import org.openscience.cdk.silent.SilentChemObjectBuilder;
import org.openscience.cdk.stereo.TetrahedralChirality;

import javax.vecmath.Point2d;
import javax.vecmath.Point3d;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertThat;

public class MDLV3000WriterTest {

Expand Down Expand Up @@ -172,6 +177,15 @@ public void hashedWedgeInvBonds() throws IOException, CDKException {
assertThat(res, CoreMatchers.containsString("M V30 1 1 2 1 CFG=3\n"));
}

@Test
public void writeLeadingZero() throws IOException, CDKException {
IAtomContainer mol = new AtomContainer();
Atom atom = new Atom("C");
atom.setPoint2d(new Point2d(0.5, 1.2));
mol.addAtom(atom);
assertThat(writeToStr(mol), CoreMatchers.containsString("0.5 1.2"));
}

@Test
public void writeParity() throws IOException, CDKException {
IAtomContainer mol = new AtomContainer();
Expand Down Expand Up @@ -358,9 +372,9 @@ public void roundTripSRU() throws IOException, CDKException {
assertThat(res, CoreMatchers.containsString("M V30 1 SRU 0 ATOMS=(1 2) XBONDS=(2 1 2) LABEL=n CONNECT=HT BRKXYZ=(9 -2.5742-\n"
+ "M V30 4.207 0 -3.0692 3.3497 0 0 0 0) BRKXYZ=(9 -3.1626 3.3497 0 -3.6576 4.2-\n"
+ "M V30 07 0 0 0 0) BRKTYP=PAREN\n"
+ "M V30 2 SRU 0 ATOMS=(1 5) XBONDS=(2 3 4) LABEL=n CONNECT=HT BRKXYZ=(9 .9542 4-\n"
+ "M V30 .1874 0 .4592 3.33 0 0 0 0) BRKXYZ=(9 .3658 3.33 0 -.1292 4.1874 0 0 0 -\n"
+ "M V30 0) BRKTYP=PAREN\n"));
+ "M V30 2 SRU 0 ATOMS=(1 5) XBONDS=(2 3 4) LABEL=n CONNECT=HT BRKXYZ=(9 0.9542 -\n"
+ "M V30 4.1874 0 0.4592 3.33 0 0 0 0) BRKXYZ=(9 0.3658 3.33 0 -0.1292 4.1874 0 -\n"
+ "M V30 0 0 0) BRKTYP=PAREN"));
}
}

Expand Down Expand Up @@ -400,6 +414,38 @@ public void roundTripOrderMixtures() throws IOException, CDKException {
}
}

@Test
public void writeDimensionField() throws Exception {
IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
IAtomContainer mol = builder.newAtomContainer();
IAtom atom = builder.newAtom();
atom.setSymbol("C");
atom.setImplicitHydrogenCount(4);
atom.setPoint2d(new Point2d(0.5, 0.5));
mol.addAtom(atom);
StringWriter sw = new StringWriter();
try (MDLV3000Writer mdlw = new MDLV3000Writer(sw)) {
mdlw.write(mol);
}
assertThat(sw.toString(), containsString("2D"));
}

@Test
public void writeDimensionField3D() throws Exception {
IChemObjectBuilder builder = SilentChemObjectBuilder.getInstance();
IAtomContainer mol = builder.newAtomContainer();
IAtom atom = builder.newAtom();
atom.setSymbol("C");
atom.setImplicitHydrogenCount(4);
atom.setPoint3d(new Point3d(0.5, 0.5, 0.1));
mol.addAtom(atom);
StringWriter sw = new StringWriter();
try (MDLV3000Writer mdlw = new MDLV3000Writer(sw)) {
mdlw.write(mol);
}
assertThat(sw.toString(), containsString("3D"));
}

private String writeToStr(IAtomContainer mol) throws IOException, CDKException {
StringWriter sw = new StringWriter();
try (MDLV3000Writer mdlw = new MDLV3000Writer(sw)) {
Expand Down

0 comments on commit 8f14ed9

Please sign in to comment.