Skip to content

Commit

Permalink
When atoms/bonds are aware of the container they are in - it is usefu…
Browse files Browse the repository at this point in the history
…l to be able to create them from the molecule directly. Not only this is more efficient but it avoids some awkwardness with the addAtom/Bond semantics. Default implementations have added.
  • Loading branch information
johnmay authored and egonw committed Sep 5, 2023
1 parent 3613660 commit 613b15a
Show file tree
Hide file tree
Showing 6 changed files with 266 additions and 0 deletions.
36 changes: 36 additions & 0 deletions base/data/src/main/java/org/openscience/cdk/Atom.java
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,42 @@ public Atom(IElement element) {
}
}

/**
* Constructs an isotope by copying the symbol, atomic number,
* flags, identifier, exact mass, natural abundance, mass
* number, maximum bond order, bond order sum, van der Waals
* and covalent radii, formal charge, hybridization, electron
* valency, formal neighbour count and atom type name from the
* given IAtomType. It does not copy the listeners and
* properties. If the element is an instance of
* IAtom, then the 2D, 3D and fractional coordinates, partial
* atomic charge, hydrogen count and stereo parity are copied
* too.
*
* @param org IAtomType to copy information from
*/
public Atom(IAtom org) {
super(org);
if (org.getPoint2d() != null) {
this.point2d = new Point2d(org.getPoint2d());
} else {
this.point2d = null;
}
if (org.getPoint3d() != null) {
this.point3d = new Point3d(org.getPoint3d());
} else {
this.point3d = null;
}
if (org.getFractionalPoint3d() != null) {
this.fractionalPoint3d = new Point3d(org.getFractionalPoint3d());
} else {
this.fractionalPoint3d = null;
}
this.hydrogenCount = org.getImplicitHydrogenCount();
this.charge = org.getCharge();
this.stereoParity = org.getStereoParity();
}

/**
* {@inheritDoc}
*/
Expand Down
32 changes: 32 additions & 0 deletions base/data/src/main/java/org/openscience/cdk/AtomContainer2.java
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,38 @@ public void add(IAtomContainer that) {
notifyChanged();
}

@Override
public IAtom newAtom(int element, int numImplH) {
BaseAtomRef ref = newAtomRef(new Atom(element, numImplH));
ensureAtomCapacity(numAtoms + 1);
ref.setIndex(numAtoms);
atoms[numAtoms++] = ref;
return ref;
}

@Override
public IAtom newAtom(IAtom atom) {
BaseAtomRef ref = newAtomRef(new Atom(atom));
ensureAtomCapacity(numAtoms + 1);
ref.setIndex(numAtoms);
atoms[numAtoms++] = ref;
return ref;
}

@Override
public IBond newBond(IAtom beg, IAtom end, Order order) {
if (!contains(beg))
throw new IllegalArgumentException("{beg} atom of bond does not belong to this container");
if (!contains(end))
throw new IllegalArgumentException("{end} atom of bond does not belong to this container");
final BaseBondRef bref = newBondRef(new Bond(beg, end, order));
ensureBondCapacity(numBonds + 1);
bref.setIndex(numBonds);
addToEndpoints(bref);
bonds[numBonds++] = bref;
return bref;
}

/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,83 @@ public interface IAtomContainer extends IChemObject, IChemObjectListener {
*/
void add(IAtomContainer atomContainer);

/**
* Create a new carbon atom in this container, it will have the implicit
* hydrogen count initialized to 0.
*
* @return thew new atom
*/
default IAtom newAtom() {
return newAtom(IAtom.C);
}

/**
* Create a new atom in this container of the specified element, it will
* have the implicit hydrogen count initialized to 0.
*
* @param element the atomic number
*
* @return thew new atom
*/
default IAtom newAtom(int element) {
return newAtom(element, 0);
}

/**
* Create a new atom in this container of the specified element and implicit
* hydrogen count.
*
* @param element the atomic number
* @param numImplH the number of implicit hydrogens
*
* @return thew new atom
*/
default IAtom newAtom(int element, int numImplH) {
IAtom atm = getBuilder().newAtom();
atm.setAtomicNumber(element);
atm.setImplicitHydrogenCount(numImplH);
addAtom(atm);
return getAtom(getAtomCount()-1);
}

/**
* Create a new atom in the container based on properties of the provided
* atom. The new atom will have the same properties as the original but is
* distinct.
*
* @param atom the original atom
* @return the new atom
*/
default IAtom newAtom(IAtom atom) {
IAtom cpy = getBuilder().newInstance(IAtom.class, atom);
addAtom(cpy);
return getAtom(getAtomCount()-1);
}

/**
* Create a new single bond between two atoms.
*
* @param beg the begin atom
* @param end the end atom
* @return the new bond
*/
default IBond newBond(IAtom beg, IAtom end) {
return newBond(beg, end, Order.SINGLE);
}

/**
* Create a new bond between two atoms.
*
* @param beg the begin atom
* @param end the end atom
* @param order the bond order
* @return the new bond
*/
default IBond newBond(IAtom beg, IAtom end, IBond.Order order) {
addBond(indexOf(beg), indexOf(end), order);
return getBond(getBondCount()-1);
}

/**
* Adds an atom to this container.
*
Expand Down
36 changes: 36 additions & 0 deletions base/silent/src/main/java/org/openscience/cdk/silent/Atom.java
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,42 @@ public Atom(IElement element) {
}
}

/**
* Constructs an isotope by copying the symbol, atomic number,
* flags, identifier, exact mass, natural abundance, mass
* number, maximum bond order, bond order sum, van der Waals
* and covalent radii, formal charge, hybridization, electron
* valency, formal neighbour count and atom type name from the
* given IAtomType. It does not copy the listeners and
* properties. If the element is an instance of
* IAtom, then the 2D, 3D and fractional coordinates, partial
* atomic charge, hydrogen count and stereo parity are copied
* too.
*
* @param org IAtomType to copy information from
*/
public Atom(IAtom org) {
super(org);
if (org.getPoint2d() != null) {
this.point2d = new Point2d(org.getPoint2d());
} else {
this.point2d = null;
}
if (org.getPoint3d() != null) {
this.point3d = new Point3d(org.getPoint3d());
} else {
this.point3d = null;
}
if (org.getFractionalPoint3d() != null) {
this.fractionalPoint3d = new Point3d(org.getFractionalPoint3d());
} else {
this.fractionalPoint3d = null;
}
this.hydrogenCount = org.getImplicitHydrogenCount();
this.charge = org.getCharge();
this.stereoParity = org.getStereoParity();
}

/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,38 @@ public void add(IAtomContainer that) {
}
}

@Override
public IAtom newAtom(int element, int numImplH) {
BaseAtomRef ref = newAtomRef(new Atom(element, numImplH));
ensureAtomCapacity(numAtoms + 1);
ref.setIndex(numAtoms);
atoms[numAtoms++] = ref;
return ref;
}

@Override
public IAtom newAtom(IAtom atom) {
BaseAtomRef ref = newAtomRef(new Atom(atom));
ensureAtomCapacity(numAtoms + 1);
ref.setIndex(numAtoms);
atoms[numAtoms++] = ref;
return ref;
}

@Override
public IBond newBond(IAtom beg, IAtom end, Order order) {
if (!contains(beg))
throw new IllegalArgumentException("beg atom of bond does not belong to this container");
if (!contains(end))
throw new IllegalArgumentException("end atom of bond does not belong to this container");
final BaseBondRef bref = newBondRef(new Bond(beg, end, order));
ensureBondCapacity(numBonds + 1);
bref.setIndex(numBonds);
addToEndpoints(bref);
bonds[numBonds++] = bref;
return bref;
}

/**
* {@inheritDoc}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3499,4 +3499,57 @@ public void removeSgroupWithAtom() throws CloneNotSupportedException {
List<Sgroup> sgroupsAfter = mol.getProperty(CDKConstants.CTAB_SGROUPS);
Assertions.assertEquals(0, sgroupsAfter.size());
}

@Test void shouldCreateNewAtomsDefault() {
IAtomContainer mol = (IAtomContainer) newChemObject();
IAtom atom = mol.newAtom();
assertThat(atom.getAtomicNumber(), is(IAtom.C));
assertThat(atom.getImplicitHydrogenCount(), is(0));
}

@Test void shouldCreateNewAtomsElement() {
IAtomContainer mol = (IAtomContainer) newChemObject();
IAtom atom = mol.newAtom(IAtom.Au);
assertThat(atom.getAtomicNumber(), is(IAtom.Au));
assertThat(atom.getImplicitHydrogenCount(), is(0));
}

@Test void shouldCreateNewAtomsElementHcnt() {
IAtomContainer mol = (IAtomContainer) newChemObject();
IAtom atom = mol.newAtom(IAtom.N, 3);
assertThat(atom.getAtomicNumber(), is(IAtom.N));
assertThat(atom.getImplicitHydrogenCount(), is(3));
}

@Test void shouldCreateNewAtomsCopy() {
IAtomContainer mol = (IAtomContainer) newChemObject();
IAtom fst = mol.newAtom(IAtom.N, 2);
fst.setIsAromatic(true);
IAtom snd = mol.newAtom(fst);
assertThat(snd.getAtomicNumber(), is(IAtom.N));
assertThat(snd.getImplicitHydrogenCount(), is(2));
assertThat(snd.isAromatic(), is(true));
}

@Test void shouldCreateNewBond() {
IAtomContainer mol = (IAtomContainer) newChemObject();
IAtom fst = mol.newAtom(IAtom.C, 3);
IAtom snd = mol.newAtom(IAtom.C, 3);
IBond bnd = mol.newBond(fst, snd);
assertThat(mol.getConnectedBondsCount(fst), is(1));
assertThat(mol.getConnectedBondsCount(snd), is(1));
assertThat(mol.getConnectedBondsList(fst).iterator().next(), is(bnd));
assertThat(mol.getConnectedBondsList(snd).iterator().next(), is(bnd));
}

@Test void shouldCreateNewBondOrder() {
IAtomContainer mol = (IAtomContainer) newChemObject();
IAtom fst = mol.newAtom(IAtom.C, 2);
IAtom snd = mol.newAtom(IAtom.C, 2);
IBond bnd = mol.newBond(fst, snd, IBond.Order.DOUBLE);
assertThat(mol.getConnectedBondsCount(fst), is(1));
assertThat(mol.getConnectedBondsCount(snd), is(1));
assertThat(mol.getConnectedBondsList(fst).iterator().next(), is(bnd));
assertThat(mol.getConnectedBondsList(snd).iterator().next(), is(bnd));
}
}

0 comments on commit 613b15a

Please sign in to comment.