Skip to content

Commit

Permalink
Add first version of DistributedIntensityCorrectionSolver
Browse files Browse the repository at this point in the history
  • Loading branch information
minnerbe committed Aug 17, 2023
1 parent 36663c4 commit 4842497
Show file tree
Hide file tree
Showing 5 changed files with 316 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package org.janelia.render.client.newsolver;

import mpicbg.models.AffineModel1D;
import mpicbg.models.TranslationModel1D;
import org.janelia.render.client.newsolver.assembly.Assembler;
import org.janelia.render.client.newsolver.assembly.ZBlockSolver;
import org.janelia.render.client.newsolver.assembly.matches.SameTileMatchCreatorAffineIntensity;
import org.janelia.render.client.newsolver.blockfactories.ZBlockFactory;
import org.janelia.render.client.newsolver.blocksolveparameters.FIBSEMIntensityCorrectionParameters;
import org.janelia.render.client.newsolver.setup.IntensityCorrectionSetup;
import org.janelia.render.client.newsolver.setup.RenderSetup;
import org.janelia.render.client.newsolver.solvers.Worker;
import org.janelia.render.client.newsolver.solvers.WorkerTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class DistributedIntensityCorrectionSolver {
final IntensityCorrectionSetup cmdLineSetup;
final RenderSetup renderSetup;
BlockCollection<?, ArrayList<AffineModel1D>, ? extends FIBSEMIntensityCorrectionParameters<?>, ZBlockFactory> col;
ZBlockFactory blockFactory;

public DistributedIntensityCorrectionSolver(
final IntensityCorrectionSetup cmdLineSetup,
final RenderSetup renderSetup) {
this.cmdLineSetup = cmdLineSetup;
this.renderSetup = renderSetup;
}

public static void main(final String[] args) throws IOException {
final IntensityCorrectionSetup cmdLineSetup = new IntensityCorrectionSetup();

// TODO: remove testing hack ...
if (args.length == 0) {
final String[] testArgs = {
"--baseDataUrl", "http://em-services-1.int.janelia.org:8080/render-ws/v1",
"--owner", "Z0720_07m_BR",
"--project", "Sec24",
"--stack", "v5_acquire_trimmed_align",
"--targetStack", "v5_acquire_trimmed_test",
"--completeCorrectedStack",
"--numThreads", "12",
// for entire stack minZ is 1 and maxZ is 63,300
"--zDistance", "1", "--minZ", "1000", "--maxZ", "1001"
};
cmdLineSetup.parse(testArgs);
} else {
cmdLineSetup.parse(args);
}

final RenderSetup renderSetup = RenderSetup.setupSolve(cmdLineSetup);

// Note: different setups can be used if specific things need to be done for the solve or certain blocks
final DistributedIntensityCorrectionSolver solverSetup = new DistributedIntensityCorrectionSolver(cmdLineSetup, renderSetup);

// create all block instances
final BlockCollection<?, ArrayList<AffineModel1D>, ?, ZBlockFactory> blockCollection = solverSetup.setupSolve();

//
// multi-threaded solve
//
LOG.info("Multithreading with thread num=" + cmdLineSetup.threadsGlobal);

final ArrayList<Callable<List<BlockData<?, ArrayList<AffineModel1D>, ?, ZBlockFactory>>>> workers = new ArrayList<>();


for (final BlockData<?, ArrayList<AffineModel1D>, ?, ZBlockFactory> block : blockCollection.allBlocks()) {
workers.add(() ->
{
final Worker<?, ArrayList<AffineModel1D>, ?, ZBlockFactory> worker = block.createWorker(
solverSetup.col.maxId() + 1,
cmdLineSetup.threadsWorker);

worker.run();

return new ArrayList<>(worker.getBlockDataList());
});
}

final ArrayList<BlockData<?, ArrayList<AffineModel1D>, ?, ZBlockFactory>> allItems = new ArrayList<>();

try {
final ExecutorService taskExecutor = Executors.newFixedThreadPool(cmdLineSetup.threadsGlobal);

taskExecutor.invokeAll(workers).forEach(future -> {
try {
allItems.addAll(future.get());
} catch (final InterruptedException | ExecutionException e) {
LOG.error("Failed to compute alignments: " + e);
e.printStackTrace();
}
});

taskExecutor.shutdown();
} catch (final InterruptedException e) {
LOG.error("Failed to compute alignments: " + e);
e.printStackTrace();
return;
}

// avoid duplicate id assigned while splitting solveitems in the workers
// but do keep ids that are smaller or equal to the maxId of the initial solveset
final int maxId = WorkerTools.fixIds(allItems, solverSetup.col.maxId());

LOG.info("computed " + allItems.size() + " blocks, maxId=" + maxId);

final ZBlockSolver<ArrayList<AffineModel1D>, TranslationModel1D, ArrayList<AffineModel1D>> solver =
new ZBlockSolver<>(
new TranslationModel1D(),
new SameTileMatchCreatorAffineIntensity(),
cmdLineSetup.distributedSolve.maxPlateauWidthGlobal,
cmdLineSetup.distributedSolve.maxAllowedErrorGlobal,
cmdLineSetup.distributedSolve.maxIterationsGlobal,
cmdLineSetup.threadsGlobal);

final Assembler<ArrayList<AffineModel1D>, TranslationModel1D, ArrayList<AffineModel1D>, ZBlockFactory> assembler = new Assembler<>(allItems, solver);
assembler.createAssembly();
}

public <M> BlockCollection<M, ArrayList<AffineModel1D>, FIBSEMIntensityCorrectionParameters<M>, ZBlockFactory> setupSolve() {

final ZBlockFactory blockFactory = setupBlockFactory();
this.blockFactory = blockFactory;

final BlockCollection<M, ArrayList<AffineModel1D>, FIBSEMIntensityCorrectionParameters<M>, ZBlockFactory> col =
setupBlockCollection(blockFactory);

this.col = col;

return col;
}

protected ZBlockFactory setupBlockFactory() {
final int minZ = (int) Math.round(renderSetup.minZ);
final int maxZ = (int) Math.round(renderSetup.maxZ);
final int blockSize = cmdLineSetup.distributedSolve.blockSize;
final int minBlockSize = cmdLineSetup.distributedSolve.minBlockSize;

return new ZBlockFactory(minZ, maxZ, blockSize, minBlockSize);
}

protected <M> FIBSEMIntensityCorrectionParameters<M> setupSolveParameters() {

return new FIBSEMIntensityCorrectionParameters<>(
null,
cmdLineSetup.renderWeb.baseDataUrl,
cmdLineSetup.renderWeb.owner,
cmdLineSetup.renderWeb.project,
cmdLineSetup.stack,
cmdLineSetup.intensityCorrectedFilterStack,
cmdLineSetup.maxPixelCacheGb,
cmdLineSetup.lambdaTranslation,
cmdLineSetup.lambdaIdentity,
cmdLineSetup.renderScale,
cmdLineSetup.numCoefficients,
cmdLineSetup.zDistance);
}

protected <M> BlockCollection<M, ArrayList<AffineModel1D>, FIBSEMIntensityCorrectionParameters<M>, ZBlockFactory> setupBlockCollection( final ZBlockFactory blockFactory){

final FIBSEMIntensityCorrectionParameters<M> defaultSolveParams = setupSolveParameters();
return blockFactory.defineBlockCollection(rtsc -> defaultSolveParams);
}

private static final Logger LOG = LoggerFactory.getLogger(DistributedIntensityCorrectionSolver.class);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class Assembler< Z, G, R, F extends BlockFactory< F > >

/**
* @param blocks - all individually computed blocks
* @param startId - we may need to create DummyBlocks where z slices do not overlap with anything (beginning and end of stack)
* @param blockSolver - solver to use for the final assembly
*/
public Assembler(
final List<BlockData<?, R, ?, F> > blocks,
Expand All @@ -49,7 +49,7 @@ public AssemblyMaps< Z > createAssembly()
{
blockSolver.globalSolve( blocks, am );
}
catch ( Exception e)
catch (final Exception e)
{
e.printStackTrace();
}
Expand Down Expand Up @@ -82,7 +82,7 @@ protected AssemblyMaps< Z > handleTrivialCase()
final HashSet< String > tileIds = solveItem.zToTileId().get( z );

// if there are none, we continue with the next
if ( tileIds.size() == 0 )
if (tileIds.isEmpty())
continue;

am.zToTileIdGlobal.putIfAbsent( z, new HashSet<>() );
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.janelia.render.client.newsolver.assembly.matches;

import java.util.ArrayList;
import java.util.List;

import org.janelia.alignment.spec.TileSpec;
Expand All @@ -9,7 +10,7 @@
import mpicbg.models.Point;
import mpicbg.models.PointMatch;

public class SameTileMatchCreatorAffineIntensity implements SameTileMatchCreator< List< AffineModel1D > >
public class SameTileMatchCreatorAffineIntensity implements SameTileMatchCreator<ArrayList<AffineModel1D>>
{
final int samplesPerDimension;

Expand All @@ -21,7 +22,7 @@ public SameTileMatchCreatorAffineIntensity( final int samplesPerDimension )
public SameTileMatchCreatorAffineIntensity() { this( 2 ); }

@Override
public void addMatches(TileSpec tileSpec, List< AffineModel1D > modelA, List< AffineModel1D > modelB, List<PointMatch> matchesAtoB)
public void addMatches(TileSpec tileSpec, ArrayList< AffineModel1D > modelA, ArrayList< AffineModel1D > modelB, List<PointMatch> matchesAtoB)
{
// TODO: make 64 matches that map A to p and B to q

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package org.janelia.render.client.newsolver.setup;

import com.beust.jcommander.IStringConverter;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParametersDelegate;
import org.janelia.render.client.intensityadjust.AdjustBlock;
import org.janelia.render.client.intensityadjust.AffineIntensityCorrectionStrategy;
import org.janelia.render.client.parameter.CommandLineParameters;
import org.janelia.render.client.parameter.RenderWebServiceParameters;
import org.janelia.render.client.parameter.ZRangeParameters;
import org.janelia.render.client.solver.SerializableValuePair;

import java.util.List;

public class IntensityCorrectionSetup extends CommandLineParameters {
private static final long serialVersionUID = -932686804562684884L;

@ParametersDelegate
public RenderWebServiceParameters renderWeb = new RenderWebServiceParameters();

@ParametersDelegate
public DistributedSolveParameters distributedSolve = new DistributedSolveParameters();

@Parameter(
names = "--stack",
description = "Stack name",
required = true)
public String stack;

@Parameter(
names = "--intensityCorrectedFilterStack",
description = "Name of stack to store tile specs with intensity corrected filter data. " +
"Omit to render intensity corrected scape-images to disk.")
public String intensityCorrectedFilterStack;

@ParametersDelegate
public ZRangeParameters layerRange = new ZRangeParameters();

@Parameter(
names = "--z",
description = "Explicit z values for sections to be processed",
variableArity = true) // e.g. --z 20.0 21.0 22.0
public List<Double> zValues;

@Parameter(
names = "--numThreads",
description = "Number of threads to use")
public Integer numThreads = 1;

@Parameter(
names = "--lambdaTranslation",
description = "Lambda for regularization with translation model")
public Double lambdaTranslation = AffineIntensityCorrectionStrategy.DEFAULT_LAMBDA;

@Parameter(
names = "--lambdaIdentity",
description = "Lambda for regularization with identity model")
public Double lambdaIdentity = AffineIntensityCorrectionStrategy.DEFAULT_LAMBDA;

@Parameter(
names = { "--maxPixelCacheGb" },
description = "Maximum number of gigabytes of pixels to cache"
)
public Integer maxPixelCacheGb = 1;

@Parameter(
names = "--renderScale",
description = "Scale for rendered tiles used during intensity comparison")
public double renderScale = 0.1;

@Parameter(
names = "--zDistance",
description = "If specified, apply correction across this many z-layers from the current z-layer " +
"(omit to only correct in 2D)")
public Integer zDistance;

@Parameter(
names = { "--numCoefficients" },
description = "Number of correction coefficients to derive in each dimension " +
"(e.g. value of 8 will divide each tile into 8x8 = 64 sub-regions)"
)
public int numCoefficients = AdjustBlock.DEFAULT_NUM_COEFFICIENTS;

//
// for saving and running
//

@Parameter(
names = "--targetOwner",
description = "Owner name for intensity corrected result stack (default is same as owner)"
)
public String targetOwner;

@Parameter(
names = "--targetProject",
description = "Project name for intensity corrected result stack (default is same as project)"
)
public String targetProject;

@Parameter(
names = "--targetStack",
description = "Name for intensity corrected result stack (if omitted, models are simply logged)")
public String targetStack;

@Parameter(
names = "--completeTargetStack",
description = "Complete the target stack after processing",
arity = 0)
public boolean completeTargetStack = false;

@Parameter(names = "--threadsWorker", description = "Number of threads to be used within each worker job (default:1)")
public int threadsWorker = 1;

@Parameter(names = "--threadsGlobal", description = "Number of threads to be used for global intensity correction (default: numProcessors/2)")
public int threadsGlobal = Math.max( 1, Runtime.getRuntime().availableProcessors() / 2 );

@Parameter(
names = "--visualizeResults",
description = "Visualize results (if running interactively)",
arity = 0)
public boolean visualizeResults = false;

public void initDefaultValues() {
// owner for target is the same as owner for render, if not specified otherwise
if ( this.targetOwner == null )
this.targetOwner = renderWeb.owner;

// project for target is the same as project for render, if not specified otherwise
if ( this.targetProject == null )
this.targetProject = renderWeb.project;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class AffineIntensityCorrectionBlockWorker<M extends Model<M> & Affine1D<M>, F extends BlockFactory<F>>
extends Worker<M, M, FIBSEMIntensityCorrectionParameters<M>, F> {
public class AffineIntensityCorrectionBlockWorker<M, F extends BlockFactory<F>>
extends Worker<M, ArrayList<AffineModel1D>, FIBSEMIntensityCorrectionParameters<M>, F> {

private final FIBSEMIntensityCorrectionParameters<M> parameters;

public AffineIntensityCorrectionBlockWorker(
final BlockData<M, M, FIBSEMIntensityCorrectionParameters<M>, F> blockData,
final BlockData<M, ArrayList<AffineModel1D>, FIBSEMIntensityCorrectionParameters<M>, F> blockData,
final int startId,
final int numThreads) throws IOException {
super(startId, blockData, numThreads);
Expand Down Expand Up @@ -311,7 +311,7 @@ public ArrayList<OnTheFlyIntensity> convertModelsToOtfIntensities(
* @return - the result(s) of the solve, multiple ones if they were not connected
*/
@Override
public ArrayList<BlockData<M, M, FIBSEMIntensityCorrectionParameters<M>, F>> getBlockDataList() {
public ArrayList<BlockData<M, ArrayList<AffineModel1D>, FIBSEMIntensityCorrectionParameters<M>, F>> getBlockDataList() {
return null;
}

Expand Down

0 comments on commit 4842497

Please sign in to comment.