All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.mianalysis.mia.module.Modules Maven / Gradle / Ivy

Go to download

ModularImageAnalysis (MIA) is an ImageJ plugin which provides a modular framework for assembling image and object analysis workflows. Detected objects can be transformed, filtered, measured and related. Analysis workflows are batch-enabled by default, allowing easy processing of high-content datasets.

There is a newer version: 1.6.12
Show newest version
// TODO: Could addRef optional argument to getParametersMatchingType for the removal type (i.e. if it matches type 1 addRef
// to the list, but if it matches type 2 remove the same parameter from the list.  Would need to compare Parameters for
// value.

package io.github.mianalysis.mia.module;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;

import io.github.mianalysis.mia.MIA;
import io.github.mianalysis.mia.macro.MacroHandler;
import io.github.mianalysis.mia.module.core.InputControl;
import io.github.mianalysis.mia.module.core.OutputControl;
import io.github.mianalysis.mia.module.script.AbstractMacroRunner;
import io.github.mianalysis.mia.object.Workspace;
import io.github.mianalysis.mia.object.parameters.OutputImageP;
import io.github.mianalysis.mia.object.parameters.Parameters;
import io.github.mianalysis.mia.object.parameters.RemovableInputImageP;
import io.github.mianalysis.mia.object.parameters.RemovedImageP;
import io.github.mianalysis.mia.object.parameters.abstrakt.Parameter;
import io.github.mianalysis.mia.object.parameters.objects.OutputObjectsP;
import io.github.mianalysis.mia.object.parameters.objects.RemovedObjectsP;
import io.github.mianalysis.mia.object.refs.ImageMeasurementRef;
import io.github.mianalysis.mia.object.refs.ObjMeasurementRef;
import io.github.mianalysis.mia.object.refs.ObjMetadataRef;
import io.github.mianalysis.mia.object.refs.collections.ImageMeasurementRefs;
import io.github.mianalysis.mia.object.refs.collections.MetadataRefs;
import io.github.mianalysis.mia.object.refs.collections.ObjMeasurementRefs;
import io.github.mianalysis.mia.object.refs.collections.ObjMetadataRefs;
import io.github.mianalysis.mia.object.refs.collections.ParentChildRefs;
import io.github.mianalysis.mia.object.refs.collections.PartnerRefs;
import io.github.mianalysis.mia.object.refs.collections.Refs;
import io.github.mianalysis.mia.object.system.Status;
import io.github.mianalysis.mia.process.logging.LogRenderer;
import io.github.mianalysis.mia.process.logging.ProgressBar;

/**
 * Created by sc13967 on 03/05/2017.
 */
public class Modules extends ArrayList implements Refs {
    /**
     *
     */
    private static final long serialVersionUID = -2862089290555674650L;
    private InputControl inputControl = new InputControl(this);
    private OutputControl outputControl = new OutputControl(this);
    private String analysisFilename = "";

    public boolean execute(Workspace workspace) {
        return execute(workspace, true);
    }

    /*
     * The method that gets called by the AnalysisRunner. This shouldn't have any
     * user interaction elements
     */
    public boolean execute(Workspace workspace, boolean clearMemoryAtEnd) {
        MIA.log.writeDebug("Processing file \"" + workspace.getMetadata().getFile().getAbsolutePath() + "\"");

        // Setting the MacroHandler to the current workspace (only if macro modules are
        // present)
        if (hasModuleMatchingType(AbstractMacroRunner.class)) {
            MacroHandler.setWorkspace(workspace);
            MacroHandler.setModules(this);
        }

        // Running through modules
        Status status = Status.PASS;

        for (int i = 0; i < size(); i++) {
            Module module = get(i);

            if (Thread.currentThread().isInterrupted())
                break;

            if (status == Status.PASS && module.isEnabled() && module.isRunnable()) {
                status = module.execute(workspace);
                workspace.setStatus(status);

                switch (status) {
                    case PASS:
                        break;
                    case FAIL:
                        MIA.log.writeWarning("Analysis failed for file \"" + workspace.getMetadata().getFile()
                                + "\" (series " + workspace.getMetadata().getSeriesNumber() + ") by module \""
                                + module.getName() + "\" (\"" + module.getNickname() + "\").");
                        break;
                    case REDIRECT:
                        // Getting index of module before one to move to
                        Module redirectModule = getModuleByID(module.getRedirectModuleID(workspace));
                        if (redirectModule == null)
                            break;
                        i = indexOf(redirectModule) - 1;
                        status = Status.PASS;
                        break;
                    case TERMINATE:
                        MIA.log.writeWarning("Analysis terminated early for file \"" + workspace.getMetadata().getFile()
                                + "\" (series " + workspace.getMetadata().getSeriesNumber() + ") by module \""
                                + module.getName() + "\" (\"" + module.getNickname() + "\").");
                        break;
                    case TERMINATE_SILENT:
                        break;
                }
            }

            // Updating progress bar
            double fractionComplete = ((double) (i + 1)) / ((double) size());
            workspace.setProgress(fractionComplete);

            if (MIA.isHeadless())
                LogRenderer.setProgress(workspace.getWorkspaces());
            else
                ProgressBar.update(workspace.getWorkspaces().getOverallProgress());

        }

        // We're only interested in the measurements now, so clearing images and object
        // coordinates
        if (clearMemoryAtEnd) {
            workspace.clearAllImages(true);
            workspace.clearAllObjects(true);
        }
        // If enabled, write the current memory usage to the console
        if (MIA.getMainRenderer().isWriteEnabled(LogRenderer.Level.MEMORY)) {
            double totalMemory = Runtime.getRuntime().totalMemory();
            double usedMemory = totalMemory - Runtime.getRuntime().freeMemory();
            String dateTime = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());

            DecimalFormat df = new DecimalFormat("#.0");

            String memoryMessage = df.format(usedMemory * 1E-6) + " MB of " + df.format(totalMemory * 1E-6) + " MB"
                    + ", ANALYSIS COMPLETE, DATE/TIME = " + dateTime + ", FILE = \"" + workspace.getMetadata().getFile()
                    + "\"";

            MIA.log.write(memoryMessage, LogRenderer.Level.MEMORY);

        }

        return true;

    }

    public void removeAllModules() {
        clear();

    }

    public String getAnalysisFilename() {
        return analysisFilename;
    }

    public void setAnalysisFilename(String analysisFilename) {
        this.analysisFilename = analysisFilename;
    }

    public Module getModuleByID(String ID) {
        for (Module module : this) {
            if (module.getModuleID().equals(ID))
                return module;
        }

        // Return null if no module found
        return null;

    }

    public ImageMeasurementRefs getImageMeasurementRefs(String imageName) {
        return getImageMeasurementRefs(imageName, null);
    }

    public ImageMeasurementRefs getImageMeasurementRefs(String imageName, Module cutoffModule) {
        ImageMeasurementRefs measurementRefs = new ImageMeasurementRefs();

        addImageMeasurementRefs(inputControl, measurementRefs, imageName);
        addImageMeasurementRefs(outputControl, measurementRefs, imageName);

        // Iterating over all modules, collecting any measurements for the current image
        for (Module module : this) {
            if (module == cutoffModule)
                break;
            if (!module.isEnabled() | !module.isRunnable())
                continue;
            addImageMeasurementRefs(module, measurementRefs, imageName);
        }

        return measurementRefs;

    }

    void addImageMeasurementRefs(Module module, ImageMeasurementRefs measurementRefs, String imageName) {
        if (!module.isEnabled())
            return;
        ImageMeasurementRefs currentMeasurementRefs = module.updateAndGetImageMeasurementRefs();

        if (currentMeasurementRefs == null)
            return;

        for (ImageMeasurementRef measurementRef : currentMeasurementRefs.values()) {
            if (measurementRef.getImageName() == null)
                continue;
            if (measurementRef.getImageName().equals(imageName))
                measurementRefs.put(measurementRef.getName(), measurementRef);

        }
    }

    public ObjMeasurementRefs getObjectMeasurementRefs(String objectName) {
        return getObjectMeasurementRefs(objectName, null);

    }

    public ObjMeasurementRefs getObjectMeasurementRefs(String objectName, Module cutoffModule) {
        ObjMeasurementRefs measurementRefs = new ObjMeasurementRefs();

        // If this is a distant relative there will be "//" in the name that need to be
        // removed
        if (objectName.contains("//"))
            objectName = objectName.substring(objectName.lastIndexOf("//") + 3);

        addObjectMeasurementRefs(inputControl, measurementRefs, objectName);
        addObjectMeasurementRefs(outputControl, measurementRefs, objectName);

        // Iterating over all modules, collecting any measurements for the current
        // objects
        for (Module module : this) {
            if (module == cutoffModule)
                break;
            if (!module.isEnabled() | !module.isRunnable())
                continue;
            addObjectMeasurementRefs(module, measurementRefs, objectName);
        }

        return measurementRefs;

    }

    public boolean objectsExportMeasurements(String objectName) {
        ObjMeasurementRefs refCollection = getObjectMeasurementRefs(objectName);

        for (ObjMeasurementRef ref : refCollection.values()) {
            if (ref.isExportIndividual() && ref.isExportGlobal())
                return true;
        }

        return false;

    }

    void addObjectMeasurementRefs(Module module, ObjMeasurementRefs measurementRefs, String objectName) {
        if (!module.isEnabled())
            return;
        ObjMeasurementRefs currentMeasurementRefs = module.updateAndGetObjectMeasurementRefs();
        if (currentMeasurementRefs == null)
            return;

        for (ObjMeasurementRef ref : currentMeasurementRefs.values()) {
            if (ref.getObjectsName() == null)
                continue;
            if (ref.getObjectsName().equals(objectName))
                measurementRefs.put(ref.getName(), ref);

        }
    }

    public ObjMetadataRefs getObjectMetadataRefs(String objectName) {
        return getObjectMetadataRefs(objectName, null);

    }

    public ObjMetadataRefs getObjectMetadataRefs(String objectName, Module cutoffModule) {
        ObjMetadataRefs metadataRefs = new ObjMetadataRefs();

        // If this is a distant relative there will be "//" in the name that need to be
        // removed
        if (objectName.contains("//"))
            objectName = objectName.substring(objectName.lastIndexOf("//") + 3);

        addObjectMetadataRefs(inputControl, metadataRefs, objectName);
        addObjectMetadataRefs(outputControl, metadataRefs, objectName);

        // Iterating over all modules, collecting any measurements for the current
        // objects
        for (Module module : this) {
            if (module == cutoffModule)
                break;
            if (!module.isEnabled() | !module.isRunnable())
                continue;
            addObjectMetadataRefs(module, metadataRefs, objectName);
        }

        return metadataRefs;

    }

    public boolean objectsExportMetadata(String objectName) {
        ObjMetadataRefs refCollection = getObjectMetadataRefs(objectName);

        for (ObjMetadataRef ref : refCollection.values()) {
            if (ref.isExportIndividual() && ref.isExportGlobal())
                return true;
        }

        return false;

    }

    void addObjectMetadataRefs(Module module, ObjMetadataRefs metadataRefs, String objectName) {
        if (!module.isEnabled())
            return;
        ObjMetadataRefs currentMetadataRefs = module.updateAndGetObjectMetadataRefs();
        if (currentMetadataRefs == null)
            return;

        for (ObjMetadataRef ref : currentMetadataRefs.values()) {
            if (ref.getObjectsName() == null)
                continue;
            if (ref.getObjectsName().equals(objectName))
                metadataRefs.put(ref.getName(), ref);

        }
    }

    public MetadataRefs getMetadataRefs() {
        return getMetadataRefs(null);

    }

    public MetadataRefs getMetadataRefs(Module cutoffModule) {
        MetadataRefs metadataRefs = new MetadataRefs();

        addMetadataRefs(inputControl, metadataRefs);
        addMetadataRefs(outputControl, metadataRefs);

        // Iterating over all modules, collecting any measurements for the current
        // objects
        for (Module module : this) {
            if (module == cutoffModule)
                break;
            addMetadataRefs(module, metadataRefs);
        }

        return metadataRefs;

    }

    void addMetadataRefs(Module module, MetadataRefs metadataRefs) {
        if (!module.isEnabled())
            return;

        MetadataRefs currentMetadataReferences = module.updateAndGetMetadataReferences();
        if (currentMetadataReferences == null)
            return;

        metadataRefs.putAll(currentMetadataReferences);

    }

    public ParentChildRefs getParentChildRefs() {
        return getParentChildRefs(null);

    }

    public ParentChildRefs getParentChildRefs(Module cutoffModule) {
        ParentChildRefs parentChildRefs = new ParentChildRefs();

        addParentChildRefs(inputControl, parentChildRefs);
        addParentChildRefs(outputControl, parentChildRefs);

        for (Module module : this) {
            if (module == cutoffModule)
                break;
            if (!module.isEnabled() | !module.isRunnable())
                continue;

            addParentChildRefs(module, parentChildRefs);

        }

        return parentChildRefs;

    }

    void addParentChildRefs(Module module, ParentChildRefs parentChildRefs) {
        if (!module.isEnabled())
            return;

        ParentChildRefs currentParentChildRefs = module.updateAndGetParentChildRefs();
        if (currentParentChildRefs == null)
            return;

        parentChildRefs.putAll(currentParentChildRefs);

    }

    public PartnerRefs getPartnerRefs() {
        return getPartnerRefs(null);

    }

    public PartnerRefs getPartnerRefs(Module cutoffModule) {
        PartnerRefs partnerRefs = new PartnerRefs();

        addPartnerRefs(inputControl, partnerRefs);
        addPartnerRefs(outputControl, partnerRefs);

        for (Module module : this) {
            if (module == cutoffModule)
                break;
            if (!module.isEnabled() | !module.isRunnable())
                continue;

            addPartnerRefs(module, partnerRefs);

        }

        return partnerRefs;

    }

    void addPartnerRefs(Module module, PartnerRefs partnerRefs) {
        if (!module.isEnabled())
            return;

        PartnerRefs currentPartnerRefs = module.updateAndGetPartnerRefs();
        if (currentPartnerRefs == null)
            return;

        partnerRefs.addAll(currentPartnerRefs);

    }

    /*
     * Returns an LinkedHashSet of all parameters of a specific type
     */
    public  LinkedHashSet getParametersMatchingType(Class type, Module cutoffModule) {
        LinkedHashSet parameters = new LinkedHashSet<>();

        for (Module module : this) {
            // If the current module is the cutoff the loop terminates. This prevents the
            // system offering measurements
            // that are created after this module or are currently unavailable.
            if (module == cutoffModule)
                break;
            if (!module.isEnabled())
                continue;
            if (!module.isRunnable())
                continue;

            // Running through all parameters, adding all images to the list
            Parameters currParameters = module.updateAndGetParameters();
            for (Parameter currParameter : currParameters.values()) {
                if (type.isInstance(currParameter)) {
                    parameters.add((T) currParameter);
                }
            }
        }

        return parameters;

    }

    public  LinkedHashSet getParametersMatchingType(Class type) {
        return getParametersMatchingType(type, null);
    }

    public Parameter getObjectSource(String objectName, Module cutoffModule) {
        Parameter sourceParameter = null;

        for (Module module : this) {
            if (module == cutoffModule)
                break;

            // Get the added and removed images
            LinkedHashSet addedObjects = module.getParametersMatchingType(OutputObjectsP.class);
            if (addedObjects == null)
                continue;

            // Find most recent instance of this object being created
            for (OutputObjectsP addedObject : addedObjects)
                if (addedObject.getValue(null).equals(objectName))
                    sourceParameter = addedObject;

        }

        return sourceParameter;

    }

    public  LinkedHashSet getAvailableObjects(Module cutoffModule,
            Class objectClass, boolean ignoreRemoved) {
        LinkedHashSet objects = new LinkedHashSet<>();

        for (Module module : this) {
            if (module == cutoffModule)
                break;

            // Get the added and removed objects
            LinkedHashSet addedObjects = module.getParametersMatchingType(objectClass);
            LinkedHashSet removedObjects = module.getParametersMatchingType(RemovedObjectsP.class);

            // Adding new objects
            if (addedObjects != null)
                objects.addAll(addedObjects);

            // Removing objects
            if (!ignoreRemoved || removedObjects == null)
                continue;

            for (Parameter removedObject : removedObjects) {
                String removeObjectName = removedObject.getRawStringValue();
                objects.removeIf(outputObjectP -> outputObjectP.getObjectsName().equals(removeObjectName));
            }
        }

        return objects;

    }

    public  LinkedHashSet getAvailableObjects(Module cutoffModule,
            Class objectClass) {
        return getAvailableObjects(cutoffModule, objectClass, true);
    }

    public LinkedHashSet getAvailableObjects(Module cutoffModule, boolean ignoreRemoved) {
        return getAvailableObjects(cutoffModule, OutputObjectsP.class, ignoreRemoved);
    }

    public LinkedHashSet getAvailableObjects(Module cutoffModule) {
        return getAvailableObjects(cutoffModule, OutputObjectsP.class, true);
    }

    public Parameter getImageSource(String imageName, Module cutoffModule) {
        Parameter sourceParameter = null;

        for (Module module : this) {
            if (module == cutoffModule)
                break;

            // Get the added and removed images
            LinkedHashSet addedImages = module.getParametersMatchingType(OutputImageP.class);

            // Find most recent instance of this object being created
            for (OutputImageP addedImage : addedImages)
                if (addedImage.getValue(null).equals(imageName))
                    sourceParameter = addedImage;

        }

        return sourceParameter;

    }

    public LinkedHashSet getAvailableImages(Module cutoffModule) {
        return getAvailableImages(cutoffModule, true);
    }

    public LinkedHashSet getAvailableImages(Module cutoffModule, boolean ignoreRemoved) {
        LinkedHashSet images = new LinkedHashSet<>();

        for (Module module : this) {
            if (module == cutoffModule)
                break;

            // Get the added and removed images
            LinkedHashSet addedImages = module.getParametersMatchingType(OutputImageP.class);
            LinkedHashSet removedImages = module.getParametersMatchingType(RemovedImageP.class);
            LinkedHashSet removableImages = module
                    .getParametersMatchingType(RemovableInputImageP.class);

            // Adding new images
            if (addedImages != null)
                images.addAll(addedImages);

            // Removing images
            if (!ignoreRemoved || removedImages == null)
                continue;

            for (Parameter removedImage : removedImages) {
                String removeImageName = removedImage.getRawStringValue();
                images.removeIf(outputImageP -> outputImageP.getImageName().equals(removeImageName));
            }

            for (RemovableInputImageP removeableImage : removableImages) {
                if (!removeableImage.isRemoveInputImages())
                    continue;

                String removeImageName = removeableImage.getRawStringValue();
                images.removeIf(outputImageP -> outputImageP.getImageName().equals(removeImageName));
            }
        }

        return images;

    }

    public boolean hasModuleMatchingType(Class clazz) {
        for (Module module : this) {
            if (clazz.isAssignableFrom(module.getClass()))
                return true;
        }

        return false;

    }

    public boolean hasVisibleParameters() {
        if (inputControl.hasVisibleParameters())
            return true;
        if (outputControl.hasVisibleParameters())
            return true;

        for (Module module : this) {
            if (module.hasVisibleParameters())
                return true;
        }

        return false;

    }

    public InputControl getInputControl() {
        return inputControl;
    }

    public void setInputControl(InputControl inputControl) {
        this.inputControl = inputControl;
    }

    public OutputControl getOutputControl() {
        return outputControl;
    }

    public void setOutputControl(OutputControl outputControl) {
        this.outputControl = outputControl;
    }

    public void reorder(int[] fromIndices, int toIndex) {
        // Creating a list of initial indices
        ArrayList inIdx = new ArrayList<>();
        for (int i = 0; i < size(); i++)
            inIdx.add(i);

        // Creating a list of the indices to move
        ArrayList toMove = new ArrayList<>();
        for (int fromIndex : fromIndices)
            toMove.add(fromIndex);

        // Removing the indices to be moved
        inIdx.removeAll(toMove);

        // Iterating over all input indices, when we get to the target index, add the
        // moved values
        Modules newModules = new Modules();
        for (int idx = 0; idx < inIdx.size() + fromIndices.length + 1; idx++) {
            // If this is the target, move the relevant indices, else move the current value
            if (idx == toIndex) {
                for (int toMoveIdx : toMove)
                    newModules.add(get(toMoveIdx));
            }

            if (idx < size() & !toMove.contains(idx)) {
                newModules.add(get(idx));
            }
        }

        removeAll(this);
        addAll(newModules);

    }

    public void reorder(Module[] modulesToMove, Module moduleToFollow) {
        int[] fromIndices = new int[modulesToMove.length];
        for (int i = 0; i < modulesToMove.length; i++) {
            fromIndices[i] = indexOf(modulesToMove[i]);
        }

        int toIndex;
        if (moduleToFollow == null)
            toIndex = 0;
        else
            toIndex = indexOf(moduleToFollow) + 1;

        reorder(fromIndices, toIndex);

    }

    public void insert(Modules modulesToInsert, int toIndex) {
        // Iterating over all input indices, when we get to the target index, add the
        // moved values
        Modules newModules = new Modules();
        for (Module module : this) {
            int idx = indexOf(module);

            // Adding in the module at this location
            newModules.add(module);

            // If this is where the modules should go, add them in
            if (idx == toIndex)
                newModules.addAll(modulesToInsert);

        }

        removeAll(this);
        addAll(newModules);

    }

    public Modules duplicate(boolean copyIDs) {
        Modules copyModules = new Modules();

        copyModules.setInputControl((InputControl) inputControl.duplicate(copyModules, copyIDs));
        copyModules.setOutputControl((OutputControl) outputControl.duplicate(copyModules, copyIDs));
        copyModules.setAnalysisFilename(analysisFilename);

        for (Module module : values())
            copyModules.add(module.duplicate(copyModules, copyIDs));
        
        return copyModules;

    }

    @Override
    public Collection values() {
        return this;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy