[Micromanager] Autofocus routine on only one position then apply offset to all positions

Hello,

I have a list of P positions in a MDA and would like to program Micromanager to make an Autofocus on only the first position of the list, and apply the offset to the P positions. I don’t want to do the autofocus on all the positions for technical reasons.

I have 2 different ideas to achieve that:

  1. To create a beanshell runnable and attach it to my MDA. (As seen at the Janelia 2020 workshop with @nicost :wink: )
    In this runnable would be:
    -autofocus algorithm called at position 1 -> return z-offset
    -apply the z-offset to the whole mm.positions()

  2. Tweak the autofocus plugin so that it does:
    -Compare the XY of the current position with the XY of the first position of the position list.
    ----If they are identical (or very close), run the routine, find the z-offset and apply it to the whole mm.positions()
    ----Else If the current position is different from the first position of the list, do nothing.

But since I’m a beginner in MM scripting, I was wondering if this sounds OK, or if an easier solution would exist, before starting the struggle :laughing:.

Thanks!
Best,
Théo

1 Like

Sounds like the right approach! And since you were at the workshop, this should be a piece of cake :cake: :wink: Just post questions here if you get stuck with anything, and it would also be nice if you could post your working script so that others can benefit.

Thanks for your answer @nicost!
So you would go for 1) rather than 2) right?

Ah, sorry missed the second part of your post. It all depends on how automatic you want it to be. If semi-automatic is OK, you could write a script that moves to the first position in the list, reads the z-position, runs the autofocus, reads the z position again, and then applies that difference to all positions in the list. You can even have that script start the MDA if you would like. If it is for other users, you can attach the script to a button on the Quick Access Panel.

2 Likes

Thanks for your reply @nicost
Yes that sounds like a good way to do it.

And yes I definetly have a bunch of questions, probably silly but I’m struggling to find the info (+ I’m new to java):

  • A part of my script is
    pl=mm.positions().getPositionList();
    // record the position before autofocus
	zpos=mmc.getPosition();
	//autocofus
	mm.autofocusNow();
	//compute the z-offset
	offset=zpos-mmc.getPosition();

However, nothing says to the script to wait the end of the autofocus routine to go to the next line. What is the cleanest way to do it so it’s universal (or at list works for any software autofocus)? I could set a timer mmc.sleep(t) that is superior to the time of autofocus, but that’s a sloppy and risky way of doing it.

  • How to simply modify the Z coordinate of a position, without having to create a MultiStagePosition msp = new MultiStagePosition(xyStage, x, y, zStage, z+offset);? I can’t find a .setZ() method or anything similar in the MultiStagePosition class. It would be easier for me since I have several Z stages.

I will of course publish the script once it’s done and working.
Thanks a lot!

Solution to my first point:
Micro-Manager - Wait for Autofocus (+kudo to Max Deforet)

So in other words, replace

mm.autofocusNow();

by

AfM=mm.getAutofocusManager();
AfMM=AfM.getAutofocusMethod();
AfMM.fullFocus();
1 Like

The following code applies an offset to all positions in the position list (for a zDrive called “Z”):

offset = 2.0;
zDrive = "Z";

posList = mm.positions().getPositionList();
list = posList.getPositions();

for (msp : list) {
	sp = msp.get(zDrive);
	sp.set1DPosition(zDrive, sp.get1DPosition() + offset);
}

posList.setPositions(list);
mm.positions().setPositionList(posList);
2 Likes

Thank you @nicost, that’s more elegant than what I did before. I now understand better how to deal with MultiStagePosition :slight_smile:

I just have a technical problem in my MDA:

runnable= new Runnable(){
  print(0);
};
mm.acquisitions().clearRunnables();
mm.acquisitions().attachRunnable(0,0,0,0,runnable);
mm.acquisitions().runAcquisition();

sends an error: Acquisition failed.
Whatever the parameters of the .attachRunnable(), the error appears just after the first run of the runnable. Did I miss something in the way of how runnables work? (I’m using the latest MM build + I attached a Problem Report.txt (72.6 KB) , cf line 1161-1167)

Appart from that, everything is working.
Where should I share the script? Should I make a pull request somewhere?

Thank you!

Not sure. I kind of try to stay away from those runnables, as they are complex structures. In your case, it seems so much easier to just run the script and start the acquisition from the script. Unless you really need it, I’d rather not spend time researching those runnables;)

As for the script, posting it here seems a fine idea.

I think I need runnables because I’m running timelapses of several hundreds of timepoints and I need this routine to be run at each timepoint, unless there is an other way?

Besides, here is the script:

I found the problem, it was stupid…
I simply needed to add

public void run() {
//do my stuff here
};

inside of the runnable.

I hope it helps someone else in the futur.