A Synapt - or something like that...

As I mentioned, our university bought a Synapt G2 HDMS with an upstream 2D-UPLC. And what should I say, we are not amused.. But let’s start with the good things.

The innovative

As far as I know Waters is the first manufacturer who joined the IMS- and QTOF-technologies to combine all well known benefits from the QTOF instruments plus the advantages of separating ions by their shape and size. They developed a Triwave technology, consisting of a trap cell, the new IMS cell and a transfer cell. Trap and transfer cell are able to fragment the ions, so you can produce fragment ions before and/or after separation by ion mobility. Producing fragments is nothing new, most of the MS instruments out there are able to do so. The innovation is located at the IMS. In front of this cell you can find a Helium chamber, working as a gate. During an IMS cycle no further ions are able to pass this gate. The IMS cell itself is flooded with nitrogen. Ions that want to pass this cell interact with those nitrogen molecules, so they will slow down. The bigger the ionshape the higher the braking force of nitrogen.

The energy inside isn’t that high that ions decay to further fragments. The energy beam transporting the ions through the IMS cell can be understood as a wave. You can define the wave height and the velocity to effectively separate your present ions. Don’t ask me why the call it height and velocity, and not amplitude and frequency, but what ever ;-) Waters provides some videos to visualize this technology, and here you can find some smart pictures of the Triwave system in a Synapt.

If you now think about an 4m IMS cell take a look at figures 2 and 3, it’s a bit more than half of a keyboard length.

The other very cool thing is their UPLC. Never seen a two-dimensional LC! In one dimension you’ll find one C18 column to separate your complex sample. With this UPLC you can also trap species in columns with different pH values, so they are also separated by their different pH-column-interactions. This is really great if you want to analyze incredible complex samples.

Looking at these very cute technologies, what are we arguing about!?

The annoying

First of all, the sales process did not run as smoothly as one might expect and took a very long time. But since I wasn’t involved I can’t tell you anymore.

The first thing we recognized when the machine arrived was a 4kDa RF generator. But we ordered a 8kDa generator! How could this happen? Waters guarantees that each instrument will be tested before it leaves their plant.. The next thing followed immediately. All configurations of the EPC were lost.. While delivering! Seems that the postman is a pickpocket..

And, to carry it too far, within the first tests the IMS cell crashed unrecoverably, have a look at figures 2 and 3. So we had to wait for a new one from Manchester. To also name the positives, the shipment took less then one day.

Even if some innocent people think they can operate a MS (who told them!? hope they got paid), it took the technicians about six weeks to get the Synapt operating… Always arguing about nano-ESI… They had big problems to install the 2D-LC, the peaks still look freaky tailing… (I don’t want to run down the technicians, they were always very committed and tried to help us as far as possible!)

Ok, so far, all is not lost if we can operate now! But can we?

For calibration you need exact masses. Calculating masses of molecules isn’t a problem for waters, but adding a proton (H+) is! Instead of a proton they add a hydrogen (H+ + e-)!? Assume you want to calibrate with Leucine Enkephaline (Leu-Enk). Leu-Enk is a peptide whose sequence is Tyr-Gly-Gly-Phe-Leu (C28H37N5O7) with a mass of . Adding a proton results in a single charged ion with a mass of (Adam Ries told us!): When they add a hydrogen their mass becomes: , that’s a diff of (it’s the mass of an electron). Seems to be small, but think in ppm: . A systematic discrepancy of almost 1 ppm for an instrument specified for 1 ppm precision. Just because of a calculation error! And things become even worse at higher charge states, compare to the green part of figure 4. Do we (stupid scientists) really have to help them (MS specialists) summing up?

Playing a bit with the machine we figured out, that it is not constructed for static measurements. We had to be creative to get some backpreasure. You also have to unmount the whole static source block to load the needle with sample. Yes, they have these fluidics, but we have samples of few μl. Ok, prepared the system with some more handwork for static measurments, the results were disgusting. The acquired spectra had errors of more than 50 ppm (read box in figure 4)!? Calling Waters we found out that this is a known bug… Even if the acquisition-window leads to believe that the machine is calibrated and provides a button to start an acquisition, acquisitions have to be started from the MassLynx sample list. Not enough hands for face palms! It’s very complicated to create a sample for each static measurement, since you have to create a new method for each sample! Also the technicians weren’t able to tell us a lot about the working principle with IMS. But we, of course, want to try some things before running 9h experiments through LC just to see that the actual parameters for the IMS are crap…

Last but not least, they are not very cooperative when we call to tell them their faults…

If the policy of their company doesn’t change I don’t believe that we buy further instruments from Waters… Looking at the price for the machine I think buying some big cars to impress the girls would have been a much better investment ;-)

Very first time with a Synapt

Yesterday I had my first date with a SYNAPT™ from Waters. A workgroup from the biocentrum bought one, this week it was delivered.

So what’s a SYNAPT™? I would say it’s actually the cream of the crop of mass spectrometry platforms. It primarily differs from other platform in the feature of separation in terms of ion mobility.

Common platforms like QTof’s might distinguish between two peptides based on their mass, so they are separated in an Quadrupole, their mass over charge (m/z) is afterwards measured by their TOF. But there is a challenge with isobars. Since they have the same mass you’ll only get one peak for all of them. You are not able to differentiate between different elementary compositions with equal masses.

Waters now brings light to the dark. They developed a very new dimension of discovery. Their Triwave™ Technology allows you to dissolve different shapes of ions with equally mass. Actually I can’t tell you how it works, but take two sheets of paper, crush one of it and throw both out of your window. You see, there are some physics that let one of these papers reach the ground faster than the other one. With the SYNAPT™ you are able to distinguish between elements in your sample based on their shape.

With the upstream UPLC a species gives a peak in an spectrum, specified by retention time, m/z, shape and intensity. A new challenge to analyze and evaluate the resulting data.

(Fortunately) there was a small problem with the machine, so I was able to take a look inside. It was amazing to see the guts of this big box, stuffed with filigree technique!!

I think I felt in love with this machine.. Bad news for my wife, but that’s life ;-)

ShortCut[RegEx]: x-modifier

Independent of your programming experiences, you should have learned that regular expressions are more or less write-only.

Write-only? What is he talking about!? Actually I revisited some Perl code with a relatively short reg-ex. Do you think I was able to understand what I’ve thought when I created that piece of code? Not in the slightest!

But there is a smart modifier, that enables you to comment your regular expressions: x. With /x all white-spaces are ignored and with an unescaped # the rest of the line is treated as a comment. I found a nice example, what do you think is this expression for:

/^1?$|^(11+?)\\1+$/

No idea? Don’t even bother, I’m also stumped… Here is the solution: It’s used to check for prime numbers ;-) Using the x-mod the explanation looks much more readable (via Neil Kandalgaonkar):

/
  ^1?$   # matches beginning, optional 1, ending.
         # thus matches the empty string and "1".
         # this matches the cases where N was 0 and 1
         # and since it matches, will not flag those as prime.
|   # or...
  ^                # match beginning of string
    (              # begin first stored group
     1             # match a one
      1+?          # then match one or more ones, minimally.
    )              # end storing first group
    \\1+            # match the first group, repeated one or more times.
  $                # match end of string.
/x

So you see, it’s really helpful to use the x-modifier. At least for your own understanding :-P

A bit more explanation can be found on Perl.com.

Talking R through Java

Today I played a bit with JRI as part of rJava, a Java-R-interface. Here you can learn how to setup for Debian/Ubuntu/akins.

Installation

Assuming you have a running version of Java and GNU’s R, you have to install r-cran-rjava :

aptitude install r-cran-rjava

Shell environment

To talk to R through Java you have to specify three more environmental variables. First of all you need to publish you R installation path, my R is found in /usr/lib64/R :

export R_HOME=/usr/lib64/R

If you didn’t or the path is wrong you’ll fall into trouble:

R_HOME is not set. Please set all required environment variables before running this program.

Second the $CLASSPATH needs to get an update. Precisely you have to add the archives JRIEngine.jar , JRI.jar and REngine.jar . In my case all of them can be found in /usr/lib/R/site-library/rJava/jri/ , so the $CLASSPATH should be set like that:

export CLASSPATH=.:/usr/lib/R/site-library/rJava/jri/

If the $CLASSPATH isn’t defined correctly you won’t be able to compile your Java code.

Last but not least you have to add the native JRI-library to your $LD_LIBRARY_PATH , by default this lib is located in the same directory like the jar’s:

export LD_LIBRARY_PATH=/usr/lib/R/site-library/rJava/jri/

If the $LD_LIBRARY_PATH isn’t proper you’ll experience errors like this:

Cannot find JRI native library!
Please make sure that the JRI native library is in a directory listed in java.library.path.

java.lang.UnsatisfiedLinkError: no jri in java.library.path
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1734)
        at java.lang.Runtime.loadLibrary0(Runtime.java:823)
        at java.lang.System.loadLibrary(System.java:1028)
        at org.rosuda.JRI.Rengine.<clinit>(Rengine.java:19)

To not always do the same you might write these export stuff to your .bashrc or .zshrc respectively.

Eclipse setup

Of course in Eclipse you’ll also have to define these three things. Where are the jar’s located? Add them to your libraries in Project > Properties > Java Build Path > Libraries. Instead of the $LD_LIBRARY_PATH you can set the java.library.path in Run > Run Configurations > Arguments. Add -Djava.library.path=.:/usr/lib/R/site-library/rJava/jri/ to the VM arguments (modify the path to match your criteria). The R_HOME can be published in Run > Run Configurations > Environment. Create a new variable with the name R_HOME and the value /usr/lib64/R (or an equivalent path). That’s it, see the section above to identify what went wrong if something fails.

Netbeans setup

Two of these three parts are also straight forward in Netbeans. First publish the location of the jar’s. Right-click on your project and choose Properties > Libraries. In the Compile-tab click Add JAR/Folder and search for the jar files. Next task is to adjust the library-path. Right-click on your project and choose Properties > Run. Add -Djava.library.path=.:/usr/lib/R/site-library/rJava/jri/ to the VM Options (modify the path to match your criteria). The third step is a little tricky. As far as I know there is no way to change the environment from within Netbeans, so you can’t create the variable R_HOME after Netbeans is started. In my opinion you have two options:

  1. Export the variable before starting Netbeans:
   usr@srv $ export R_HOME=/usr/lib64/R
   usr@srv $ netbeans
   

you might want to write a wrapper script that does this step for you, or include the export in any of the resource files that are called before Netbeans starts (e.g. your .bashrc ).

  1. Change the environment from within your project. At stackoverflow you can find a workaround, but I think this is a very lousy solution..

If you have further suggestions please let me know! Meanwhile George Bull published a setup guide for Netbeans on Windows hosts. Seems to be worthy to take a look at it ;-)

Testcase

If you defined your environment properly, you should be able to utilize the REngine. I have a small script for you to test whether all things are fine:

package de.binfalse.martin;

import org.rosuda.JRI.Rengine;

public class JRItest
{
  public static void main (String[] args)
  {
    // new R-engine
    Rengine re=new Rengine (new String [] {"--vanilla"}, false, null);
    if (!re.waitForR())
    {
      System.out.println ("Cannot load R");
      return;
    }

    // print a random number from uniform distribution
    System.out.println (re.eval ("runif(1)").asDouble ());

    // done...
    re.end();
  }

}

You should be able to compile and run it, afterwards you’ll see a random number from an uniform distribution. Congratulations, well done :-P

For more information see the JRI and rJava sites at RForge.net.

Download: Java: JRItest.java (Please take a look at the man-page. Browse bugs and feature requests.)

Readability vs speed in R

I have bad news for those of you trying to produce lucid code!

In his blog Radford M. Neal, Professor at the University of Toronto, published an article with the headline Two Surprising Things about R. He worked out, that parentheses in mathematical expression slow down the run-time dramatically! In contrast it seems to be less time consuming to use curly brackets. I verified these circumstances to be true:

> x=10
> f <- function (n) for (i in 1:n) 1/(1*(1+x))
> g <- function (n) for (i in 1:n) (((1/(((1*(((1+x)))))))))
> system.time(f(10^6))
   user  system elapsed 
  2.231   0.000   2.232 
> system.time(g(10^6))
   user  system elapsed 
  3.896   0.000   3.923 
> 
> # in contrast with curly brackets
> h <- function (n) for (i in 1:n) 1/{1*{1+x}}
> i <- function (n) for (i in 1:n) {{{1/{{{1*{{{1+x}}}}}}}}}
> system.time(h(10^6))
   user  system elapsed 
  1.974   0.000   1.974 
> system.time(i(10^6))
   user  system elapsed 
  3.204   0.000   3.228

As you can see adding extra parentheses is not really intelligent concerning run-time, and not in a negligible way. This fact shocked me, because I always tried to group expressions to increase the readability of my code! Using curly brackets speeds up the execution in comparison to parentheses. Both observations are also surprising to me! So the conclusion is: Try to avoid redundant parentheses and/or brackets!

To learn more about the why you are referred to his article. He also found a interesting observation about squares. In a further article he presents some patches to speed up R.



Martin Scharm

stuff. just for the records.