Skip to content

Commit 1fbb515

Browse files
committed
New getMass function that unifies and replaces the existing functions.
1 parent baae4da commit 1fbb515

File tree

2 files changed

+175
-63
lines changed

2 files changed

+175
-63
lines changed

tool/formula/src/main/java/org/openscience/cdk/tools/manipulator/MolecularFormulaManipulator.java

Lines changed: 130 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -771,37 +771,14 @@ private static int extractCharge(String formula) {
771771
}
772772

773773
/**
774-
* Get the summed exact mass of all isotopes from an MolecularFormula. It
775-
* assumes isotope masses to be preset, and returns 0.0 if not.
776-
*
777-
* @param formula The IMolecularFormula to calculate
778-
* @return The summed exact mass of all atoms in this MolecularFormula
774+
* @deprecated calls {@link #getMass(IMolecularFormula, int)} with option
775+
* {@link #MonoIsotopic} and adjusts for charge with
776+
* {@link #correctMass(double, Integer)}. These functions should be used
777+
* directly.
779778
*/
779+
@Deprecated
780780
public static double getTotalExactMass(IMolecularFormula formula) {
781-
double mass = 0.0;
782-
for (IIsotope isotope : formula.isotopes()) {
783-
try {
784-
Integer massNum = isotope.getMassNumber();
785-
Double exactMass = isotope.getExactMass();
786-
if (massNum == null || massNum == 0) {
787-
IIsotope majorIsotope = Isotopes.getInstance().getMajorIsotope(isotope.getSymbol());
788-
if (majorIsotope != null)
789-
exactMass = majorIsotope.getExactMass();
790-
} else {
791-
if (exactMass == null) {
792-
IIsotope temp = Isotopes.getInstance().getIsotope(isotope.getSymbol(), massNum);
793-
if (temp != null)
794-
exactMass = temp.getExactMass();
795-
}
796-
}
797-
if (exactMass != null)
798-
mass += exactMass * formula.getIsotopeCount(isotope);
799-
} catch (IOException e) {
800-
throw new RuntimeException("Could not instantiate the IsotopeFactory.");
801-
}
802-
}
803-
if (formula.getCharge() != null) mass = correctMass(mass, formula.getCharge());
804-
return mass;
781+
return correctMass(getMass(formula, MonoIsotopic), formula.getCharge());
805782
}
806783

807784
/**
@@ -844,48 +821,135 @@ public static double getTotalMassNumber(IMolecularFormula formula) {
844821
return mass;
845822
}
846823

824+
private static final int MolWeight = 0x1;
825+
private static final int AverageWeight = 0x2;
826+
private static final int MonoIsotopic = 0x3;
827+
private static final int MostAbundant = 0x4;
828+
829+
private static double getExactMass(IsotopeFactory isofact, IIsotope atom) {
830+
if (atom.getExactMass() != null)
831+
return atom.getExactMass();
832+
else if (atom.getMassNumber() != null)
833+
return isofact.getExactMass(atom.getAtomicNumber(),
834+
atom.getMassNumber());
835+
else
836+
return isofact.getMajorIsotopeMass(atom.getAtomicNumber());
837+
}
838+
839+
private static double getMassOrAvg(IsotopeFactory isofact, IIsotope atom) {
840+
if (atom.getMassNumber() == null ||
841+
atom.getMassNumber() == 0)
842+
return isofact.getNaturalMass(atom);
843+
else
844+
return getExactMass(isofact, atom);
845+
}
846+
847847
/**
848-
* Get the summed natural mass of all elements from an MolecularFormula.
849-
*
850-
* @param formula The IMolecularFormula to calculate
851-
* @return The summed exact mass of all atoms in this MolecularFormula
848+
* Calculate the mass of a molecule, this function takes an optional
849+
* 'mass flavour' that switches the computation type, the flavours are:
850+
* <br>
851+
* <ul>
852+
* <li>{@link #MolWeight} (default) - use and isotopes the natural mass
853+
* unless a specific isotope is specified</li>
854+
* <li>{@link #AverageWeight} - use and isotopes the natural mass even
855+
* if a specific isotope is specified</li>
856+
* <li>{@link #MonoIsotopic} - use and isotopes the major isotope mass
857+
* even if a specific isotope is specified</li>
858+
* <li>{@link #MostAbundant} - use the distribution of isotopes
859+
* based on their abundance and select the most abundant. For example
860+
* C<sub>6</sub>Br<sub>6</sub> would have three <sup>79</sup>Br and
861+
* <sup>81</sup>Br because their abundance is 51 and 49%.
862+
* </ul>
863+
*
864+
* @param mf molecular formula
865+
* @param flav the mass flavour
866+
* @return the mass of the molecule
867+
* @see #MolWeight
868+
* @see #AverageWeight
869+
* @see #MonoIsotopic
870+
* @see #MostAbundant
852871
*/
853-
public static double getNaturalExactMass(IMolecularFormula formula) {
854-
double mass = 0.0;
855-
IsotopeFactory factory;
872+
public static double getMass(IMolecularFormula mf, int flav) {
873+
final Isotopes isofact;
856874
try {
857-
factory = Isotopes.getInstance();
875+
isofact = Isotopes.getInstance();
858876
} catch (IOException e) {
859-
throw new RuntimeException("Could not instantiate the IsotopeFactory.");
877+
throw new IllegalStateException("Could not load Isotopes!");
860878
}
861-
for (IIsotope isotope : formula.isotopes()) {
862-
IElement isotopesElement = formula.getBuilder().newInstance(IElement.class, isotope);
863-
mass += factory.getNaturalMass(isotopesElement) * formula.getIsotopeCount(isotope);
879+
880+
double mass = 0;
881+
switch (flav & 0xf) {
882+
case MolWeight:
883+
for (IIsotope iso : mf.isotopes()) {
884+
mass += mf.getIsotopeCount(iso) *
885+
getMassOrAvg(isofact, iso);
886+
}
887+
break;
888+
case AverageWeight:
889+
for (IIsotope iso : mf.isotopes()) {
890+
mass += mf.getIsotopeCount(iso) *
891+
isofact.getNaturalMass(iso.getAtomicNumber());
892+
}
893+
break;
894+
case MonoIsotopic:
895+
for (IIsotope iso : mf.isotopes()) {
896+
mass += mf.getIsotopeCount(iso) *
897+
getExactMass(isofact, iso);
898+
}
899+
break;
900+
case MostAbundant:
901+
IMolecularFormula mamf = getMostAbundant(mf);
902+
if (mamf != null)
903+
mass = getMass(mamf, MonoIsotopic);
904+
break;
864905
}
865906
return mass;
866907
}
867908

868909
/**
869-
* Get the summed major isotopic mass of all elements from an MolecularFormula.
910+
* Calculate the mass of a molecule, this function takes an optional
911+
* 'mass flavour' that switches the computation type, the flavours are:
912+
* <br>
913+
* <ul>
914+
* <li>{@link #MolWeight} (default) - use and isotopes the natural mass
915+
* unless a specific isotope is specified</li>
916+
* <li>{@link #AverageWeight} - use and isotopes the natural mass even
917+
* if a specific isotope is specified</li>
918+
* <li>{@link #MonoIsotopic} - use and isotopes the major isotope mass
919+
* even if a specific isotope is specified</li>
920+
* <li>{@link #MostAbundant} - use the distribution of isotopes
921+
* based on their abundance and select the most abundant. For example
922+
* C<sub>6</sub>Br<sub>6</sub> would have three <sup>79</sup>Br and
923+
* <sup>81</sup>Br because their abundance is 51 and 49%.
924+
* </ul>
870925
*
871-
* @param formula The IMolecularFormula to calculate
872-
* @return The summed exact major isotope masses of all atoms in this MolecularFormula
926+
* @param mf molecular formula
927+
* @return the mass of the molecule
928+
* @see #MolWeight
929+
* @see #AverageWeight
930+
* @see #MonoIsotopic
931+
* @see #MostAbundant
873932
*/
874-
public static double getMajorIsotopeMass(IMolecularFormula formula) {
875-
double mass = 0.0;
876-
IsotopeFactory factory;
877-
try {
878-
factory = Isotopes.getInstance();
879-
} catch (IOException e) {
880-
throw new RuntimeException("Could not instantiate the IsotopeFactory.");
881-
}
882-
for (IIsotope isotope : formula.isotopes()) {
883-
IIsotope major = factory.getMajorIsotope(isotope.getSymbol());
884-
if (major != null) {
885-
mass += major.getExactMass() * formula.getIsotopeCount(isotope);
933+
public static double getMass(IMolecularFormula mf) {
934+
return getMass(mf, MolWeight);
886935
}
936+
937+
/**
938+
* @deprecated use {@link #getMass(IMolecularFormula, int)} with option
939+
* {@link #AverageWeight}.
940+
*/
941+
@Deprecated
942+
public static double getNaturalExactMass(IMolecularFormula formula) {
943+
return getMass(formula, AverageWeight);
887944
}
888-
return mass;
945+
946+
/**
947+
* @deprecated use {@link #getMass(IMolecularFormula, int)} with option
948+
* {@link #MonoIsotopic}.
949+
*/
950+
@Deprecated
951+
public static double getMajorIsotopeMass(IMolecularFormula formula) {
952+
return getMass(formula, MonoIsotopic);
889953
}
890954

891955
/**
@@ -960,15 +1024,17 @@ public static IMolecularFormula getMolecularFormula(IAtomContainer atomContainer
9601024
*/
9611025
public static IMolecularFormula getMolecularFormula(IAtomContainer atomContainer, IMolecularFormula formula) {
9621026
int charge = 0;
963-
IAtom hAtom = null;
1027+
int hcnt = 0;
9641028
for (IAtom iAtom : atomContainer.atoms()) {
9651029
formula.addIsotope(iAtom);
966-
if (iAtom.getFormalCharge() != null) charge += iAtom.getFormalCharge();
967-
968-
if (iAtom.getImplicitHydrogenCount() != null && (iAtom.getImplicitHydrogenCount() > 0)) {
969-
if (hAtom == null) hAtom = atomContainer.getBuilder().newInstance(IAtom.class, "H");
970-
formula.addIsotope(hAtom, iAtom.getImplicitHydrogenCount());
1030+
if (iAtom.getFormalCharge() != null)
1031+
charge += iAtom.getFormalCharge();
1032+
if (iAtom.getImplicitHydrogenCount() != null)
1033+
hcnt += iAtom.getImplicitHydrogenCount();
9711034
}
1035+
if (hcnt != 0) {
1036+
IAtom hAtom = atomContainer.getBuilder().newInstance(IAtom.class, "H");
1037+
formula.addIsotope(hAtom, hcnt);
9721038
}
9731039
formula.setCharge(charge);
9741040
return formula;
@@ -1005,6 +1071,7 @@ public static IAtomContainer getAtomContainer(IMolecularFormula formula, IAtomCo
10051071
int occur = formula.getIsotopeCount(isotope);
10061072
for (int i = 0; i < occur; i++) {
10071073
IAtom atom = formula.getBuilder().newInstance(IAtom.class, isotope);
1074+
atom.setImplicitHydrogenCount(0);
10081075
atomContainer.addAtom(atom);
10091076
}
10101077
}

tool/formula/src/test/java/org/openscience/cdk/tools/manipulator/MolecularFormulaManipulatorTest.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,4 +1397,49 @@ public void getMostAbundantFe100() {
13971397
assertThat(MolecularFormulaManipulator.getString(mamf, false, true),
13981398
is("[54]Fe6[56]Fe92[57]Fe2"));
13991399
}
1400+
1401+
@Test public void getMassCranbin() {
1402+
IChemObjectBuilder bldr = SilentChemObjectBuilder.getInstance();
1403+
IMolecularFormula mf =
1404+
MolecularFormulaManipulator.getMolecularFormula("C202H315N55O64S6",
1405+
bldr);
1406+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, MolWeight),
1407+
closeTo(4730.397, 0.001));
1408+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, AverageWeight),
1409+
closeTo(4730.397, 0.001));
1410+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, MonoIsotopic),
1411+
closeTo(4727.140, 0.001));
1412+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, MostAbundant),
1413+
closeTo(4729.147, 0.001));
1414+
}
1415+
1416+
@Test public void getMassCranbinSpecIsotopes() {
1417+
IChemObjectBuilder bldr = SilentChemObjectBuilder.getInstance();
1418+
IMolecularFormula mf =
1419+
MolecularFormulaManipulator.getMolecularFormula("[12]C200[13]C2[1]H315[14]N55[16]O64[32]S6",
1420+
bldr);
1421+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, MolWeight),
1422+
closeTo(4729.147, 0.001));
1423+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, AverageWeight),
1424+
closeTo(4730.397, 0.001));
1425+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, MonoIsotopic),
1426+
closeTo(4729.147, 0.001));
1427+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, MostAbundant),
1428+
closeTo(4729.147, 0.001));
1429+
}
1430+
1431+
@Test public void getMassCranbinMixedSpecIsotopes() {
1432+
IChemObjectBuilder bldr = SilentChemObjectBuilder.getInstance();
1433+
IMolecularFormula mf =
1434+
MolecularFormulaManipulator.getMolecularFormula("C200[13]C2H315N55O64S6",
1435+
bldr);
1436+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, MolWeight),
1437+
closeTo(4732.382, 0.001));
1438+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, AverageWeight),
1439+
closeTo(4730.397, 0.001));
1440+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, MonoIsotopic),
1441+
closeTo(4729.147, 0.001));
1442+
Assert.assertThat(MolecularFormulaManipulator.getMass(mf, MostAbundant),
1443+
closeTo(4731.154, 0.001));
1444+
}
14001445
}

0 commit comments

Comments
 (0)