Browse Source

Initial commit of the piv program

All code written by Alexandre Lewkowicz (lewkow_a@epita.fr).
Matthias Vogelgesang 9 years ago
commit
4f6e129101
11 changed files with 623 additions and 0 deletions
  1. 1 0
      .gitignore
  2. 21 0
      CMakeLists.txt
  3. 90 0
      ConfigurePaths.cmake
  4. 68 0
      config.h
  5. 129 0
      piv-nodes.c
  6. 54 0
      piv-nodes.h
  7. 34 0
      piv-scheduler.c
  8. 15 0
      piv-scheduler.h
  9. 95 0
      piv-ufo-base.c
  10. 27 0
      piv-ufo-base.h
  11. 89 0
      piv.c

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+build/

+ 21 - 0
CMakeLists.txt

@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.6)
+
+set(piv_srcs
+    piv.c
+    piv-nodes.c
+    piv-scheduler.c
+    piv-ufo-base.c)
+
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}")
+
+include(ConfigurePaths)
+configure_paths(PIV)
+
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(UFO ufo>=0.6.0 REQUIRED)
+
+include_directories(${UFO_INCLUDE_DIRS})
+link_directories(${UFO_LIBRARY_DIRS})
+
+add_executable(piv ${piv_srcs})
+target_link_libraries(piv ${UFO_LIBRARIES})

+ 90 - 0
ConfigurePaths.cmake

@@ -0,0 +1,90 @@
+# - pre-configured paths for CMake
+#
+# Usage:
+#   configure_paths(<PREFIX>)
+#
+# Checks if configure-like prefix and installation paths were passed by the user
+# and sets up corresponding variables for use in install() commands and to fill
+# out .pc files:
+#
+#   PREFIX_PREFIX       defaults to ...     CMAKE_INSTALL_PREFIX
+#   PREFIX_EPREFIX                          PREFIX_PREFIX
+#   PREFIX_SBINDIR                          PREFIX_EPREFIX/sbin
+#   PREFIX_SYSCONFDIR                       PREFIX_PREFIX/etc
+#   PREFIX_LOCALSTATEDIR                    PREFIX_PREFIX/var
+#   PREFIX_BINDIR                           PREFIX_EPREFIX/bin
+#   PREFIX_LIBDIR                           PREFIX_EPREFIX/lib
+#   PREFIX_INCLUDEDIR                       PREFIX_PREFIX/include
+#   PREFIX_PKGCONFIGDIR                     PREFIX_LIBDIR/pkgconfig
+#   PREFIX_TYPELIBDIR                       PREFIX_LIBDIR/girepository-1.0
+#   PREFIX_DATAROOTDIR                      PREFIX_PREFIX/share
+#   PREFIX_DATADIR                          PREFIX_DATAROOTDIR
+#   PREFIX_INFODIR                          PREFIX_DATAROOTDIR/info
+#   PREFIX_MANDIR                           PREFIX_DATAROOTDIR/man
+#   PREFIX_LOCALEDIR                        PREFIX_DATAROOTDIR/locale
+#   PREFIX_GIRDIR                           PREFIX_DATAROOTDIR/gir-1.0
+
+# Copyright (C) 2013 Matthias Vogelgesang <matthias.vogelgesang@gmail.com>
+#
+# Redistribution and use, with or without modification, are permitted
+# provided that the following conditions are met:
+# 
+#    1. Redistributions must retain the above copyright notice, this
+#       list of conditions and the following disclaimer.
+#    2. The name of the author may not be used to endorse or promote
+#       products derived from this software without specific prior
+#       written permission.
+# 
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+if(__configure_paths)
+    return()
+endif()
+
+set(__configure_paths YES)
+
+macro(_set_var _prefix _var _user _override _description)
+    set(_name "${_prefix}_${_var}")
+
+    set("${_name}" "${_user}")
+
+    if("${_name}" STREQUAL "")
+        set("${_name}" "${_override}")
+    endif()
+
+    set(${_name} "${${_name}}" CACHE PATH "${_description}")
+    mark_as_advanced(${_name})
+endmacro()
+
+function(configure_paths _prefix)
+    _set_var("${_prefix}" "PREFIX"          "${PREFIX}"         "${CMAKE_INSTALL_PREFIX}"               "install architecture-independent files in PREFIX")
+    _set_var("${_prefix}" "EPREFIX"         "${EXEC_PREFIX}"    "${${_prefix}_PREFIX}"                  "install architecture-dependent files in EPREFIX")
+
+    _set_var("${_prefix}" "SBINDIR"         "${SBINDIR}"        "${${_prefix}_EPREFIX}/sbin"            "system admin executabls")
+    _set_var("${_prefix}" "SYSCONFDIR"      "${SYSCONFDIR}"     "${${_prefix}_PREFIX}/etc"              "read-only single-machine data")
+    _set_var("${_prefix}" "LOCALSTATEDIR"   "${LOCALSTATEDIR}"  "${${_prefix}_PREFIX}/var"              "modifiable single-machine data")
+    _set_var("${_prefix}" "BINDIR"          "${BINDIR}"         "${${_prefix}_EPREFIX}/bin"             "user executables")
+    _set_var("${_prefix}" "LIBDIR"          "${LIBDIR}"         "${${_prefix}_EPREFIX}/lib"             "object code libraries")
+    _set_var("${_prefix}" "INCLUDEDIR"      "${INCLUDEDIR}"     "${${_prefix}_PREFIX}/include"          "C header files")
+    _set_var("${_prefix}" "PKGCONFIGDIR"    "${PKGCONFIGDIR}"   "${${_prefix}_LIBDIR}/pkgconfig"        "pkg-config files")
+    _set_var("${_prefix}" "TYPELIBDIR"      "${TYPELIBDIR}"     "${${_prefix}_LIBDIR}/girepository-1.0" "GObject run-time introspection data")
+    _set_var("${_prefix}" "DATAROOTDIR"     "${DATAROOTDIR}"    "${${_prefix}_PREFIX}/share"            "read-only arch.-independent data root")
+    _set_var("${_prefix}" "DATADIR"         "${DATADIR}"        "${${_prefix}_DATAROOTDIR}"             "read-only architecture-independent data")
+    _set_var("${_prefix}" "INFODIR"         "${INFODIR}"        "${${_prefix}_DATAROOTDIR}/info"        "info documentation")
+    _set_var("${_prefix}" "MANDIR"          "${MANDIR}"         "${${_prefix}_DATAROOTDIR}/man"         "man documentation")
+    _set_var("${_prefix}" "LOCALEDIR"       "${LOCALEDIR}"      "${${_prefix}_DATAROOTDIR}/locale"      "locale-dependent data")
+    _set_var("${_prefix}" "GIRDIR"          "${GIRDIR}"         "${${_prefix}_DATAROOTDIR}/gir-1.0"     "GObject introspection data")
+endfunction()
+
+# vim: tw=0:

+ 68 - 0
config.h

@@ -0,0 +1,68 @@
+/* When scale == 2, image is reduced by 2 */
+/* When scale == 1, full resolution image is used */
+unsigned scale = 2;
+/* Variable used to determine how many images are being processed
+ * Command : ls 'input_str' | wc -l'
+ * can tell you have files match the expression passed to the reader plugin */
+unsigned number_of_images = 1;
+/* When dump_ring_to_image == 1, data is written to an image
+ * When dump_ring_to_image == 0, data is written in a text file as
+ * coordinates with the first line being the number of rings and all
+ * subsequent lines the "x y r" coordinates. */
+unsigned dump_ring_to_image = 0;
+
+char *input_str = "data/Image0.tif";
+g_object_set (G_OBJECT (global_reader), "path", input_str, NULL);
+g_object_set (G_OBJECT (piv.writer), "filename", "res%i.tif", NULL);
+g_object_set (G_OBJECT (piv.ringwriter), "filename", "results", NULL);
+/* Define matrix_size to determines the number of surrounding pixels to
+ * be compared with, ideally make this number uneven
+ * Being twice the size of the actual ring thickness tends to be good */
+g_object_set (G_OBJECT (piv.denoise), "matrix_size", 26 / scale, NULL);
+/* Boolean to say whether or not to romve high intensity pixels */
+g_object_set (G_OBJECT (piv.contrast), "remove_high", 0, NULL);
+/* Giving ring radius, when using reduce plugin divide them by 2 */
+unsigned ring_start = 10 / scale;
+unsigned ring_end = 130 / scale;
+unsigned ring_step = 2 / scale;
+g_object_set (G_OBJECT (piv.ring_pattern), "ring_start", ring_start, NULL);
+g_object_set (G_OBJECT (piv.ring_pattern), "ring_end", ring_end, NULL);
+g_object_set (G_OBJECT (piv.ring_pattern), "ring_step", ring_step, NULL);
+/* Should be the same dimension as input image */
+/* When using reduce plugin divide it by 2 */
+g_object_set (G_OBJECT (piv.ring_pattern), "width", 1080 / scale, NULL);
+g_object_set (G_OBJECT (piv.ring_pattern), "height", 1280 / scale, NULL);
+/* Giving thickness of rpiv.ing
+ * NOTE if rings raddi apiv.nd thickness are too big, you will get errors from
+ * the gpu * saying  CL_piv.INVALID_WORK_GROUP_SIZE */
+g_object_set (G_OBJECT (piv.ring_pattern), "ring_thickness", 6 / scale, NULL);
+
+/* Set the maximum number of rings that should detected per ring pattern, if
+ * the number of found rings is greater than max_count, then the output is
+ * ignored */
+g_object_set (G_OBJECT (piv.concatenate_result), "max_count", 100, NULL);
+
+/* When images maximum is less than min ignore  output. Min is the
+ * likelyness value for a pixel to be the center of a ring and ranges from 0
+ * to 1 */
+g_object_set (G_OBJECT (piv.filter_particle), "min", 0.125, NULL);
+/* Consider only pixels that are above 0.8 * max when searching for clusters
+* of pixels.  Where max, is the highest intensity in the image */
+g_object_set (G_OBJECT (piv.filter_particle), "threshold", 0.8, NULL);
+
+/* Set minumum distance between rings, and how close two different radius
+ * are considerend to be same ring */
+g_object_set (G_OBJECT (piv.get_dup_circ), "threshold", 8. / scale, NULL);
+
+/* Up to what radii difference is a ring considered an inner or outer ring
+ * of two intersecting rings */
+g_object_set (G_OBJECT (piv.remove_circle), "threshold", 4. / scale, NULL);
+
+/* Vary up from -radii_range to randii_range the radius to find the
+ * polynomial that corresponds to the rings contrast */
+g_object_set (G_OBJECT (piv.multi_search), "radii_range", 6 / scale, NULL);
+/* Set the minimum contrast a ring should have to be considered a ring */
+g_object_set (G_OBJECT (piv.multi_search), "threshold", 0.01, NULL);
+/* By how much may the ring center be displaced to find it's actual center and
+ * it's actual radius */
+g_object_set (G_OBJECT (piv.multi_search), "displacement", 1, NULL);

+ 129 - 0
piv-nodes.c

@@ -0,0 +1,129 @@
+#include "piv-nodes.h"
+#include "piv-ufo-base.h"
+
+struct piv_nodes *
+piv_nodes_copy(struct piv_nodes *src)
+{
+    GError *error = NULL;
+    struct piv_nodes *res = g_malloc (sizeof (struct piv_nodes));
+    PIV_COPY_TASK_NODE (res->denoise, src->denoise, &error);
+    PIV_COPY_TASK_NODE (res->contrast, src->contrast, &error);
+
+    PIV_COPY_TASK_NODE (res->broadcast_contrast, src->broadcast_contrast, &error);
+    PIV_COPY_TASK_NODE (res->broadcast_reader, src->broadcast_reader, &error);
+    PIV_COPY_TASK_NODE (res->copy_replicater, src->copy_replicater, &error);
+    PIV_COPY_TASK_NODE (res->replicater, src->replicater, &error);
+    PIV_COPY_TASK_NODE (res->replicate_reader, src->replicate_reader, &error);
+    PIV_COPY_TASK_NODE (res->duplicater, src->duplicater, &error);
+
+    PIV_COPY_TASK_NODE (res->ring_pattern, src->ring_pattern, &error);
+    PIV_COPY_TASK_NODE (res->ordfilt, src->ordfilt, &error);
+    PIV_COPY_TASK_NODE (res->filter_particle, src->filter_particle, &error);
+    PIV_COPY_TASK_NODE (res->concatenate_result, src->concatenate_result, &error);
+    PIV_COPY_TASK_NODE (res->get_dup_circ, src->get_dup_circ, &error);
+    PIV_COPY_TASK_NODE (res->remove_circle, src->remove_circle, &error);
+    PIV_COPY_TASK_NODE (res->multi_search, src->multi_search, &error);
+    PIV_COPY_TASK_NODE (res->dump_ring, src->dump_ring, &error);
+    PIV_COPY_TASK_NODE (res->fftmult, src->fftmult, &error);
+
+    PIV_COPY_TASK_NODE (res->reduce, src->reduce, &error);
+    PIV_COPY_TASK_NODE (res->writer, src->writer, &error);
+    PIV_COPY_TASK_NODE (res->ringwriter, src->ringwriter, &error);
+    PIV_COPY_TASK_NODE (res->fft, src->fft, &error);
+    PIV_COPY_TASK_NODE (res->ringfft, src->ringfft, &error);
+    PIV_COPY_TASK_NODE (res->loop_ringfft, src->loop_ringfft, &error);
+    PIV_COPY_TASK_NODE (res->ringifft, src->ringifft, &error);
+    PIV_COPY_TASK_NODE (res->ifft, src->ifft, &error);
+
+    if (error)
+        g_print("Error %s\n", error->message);
+    return res;
+}
+
+void
+piv_nodes_init(struct piv_nodes *piv, struct piv_ufo_base *base)
+{
+    GError *error = base->error;
+    UfoPluginManager *manager = base->manager;
+    piv->broadcast_reader = UFO_TASK_NODE (ufo_copy_task_new ());
+    piv->copy_replicater = UFO_TASK_NODE (ufo_copy_task_new ());
+    piv->broadcast_contrast = UFO_TASK_NODE (ufo_copy_task_new ());
+    piv->replicater = ufo_plugin_manager_get_task (manager, "buffer", &error);
+    piv->replicate_reader = ufo_plugin_manager_get_task (manager, "buffer", &error);
+    piv->duplicater = ufo_plugin_manager_get_task (manager, "buffer", &error);
+    piv->loop_ringfft = ufo_plugin_manager_get_task (manager, "buffer", &error);
+    piv->denoise = ufo_plugin_manager_get_task (manager, "denoise", &error);
+    piv->ring_pattern = ufo_plugin_manager_get_task (manager, "ring_pattern", &error);
+    piv->reduce = ufo_plugin_manager_get_task (manager, "reduce", &error);
+    piv->contrast = ufo_plugin_manager_get_task (manager, "contrast", &error);
+    piv->filter_particle = ufo_plugin_manager_get_task (manager, "filter_particle", &error);
+    piv->concatenate_result = ufo_plugin_manager_get_task (manager, "concatenate_result", &error);
+    piv->get_dup_circ = ufo_plugin_manager_get_task (manager, "get_dup_circ", &error);
+    piv->remove_circle = ufo_plugin_manager_get_task (manager, "remove_circle", &error);
+    piv->multi_search = ufo_plugin_manager_get_task (manager, "multi_search", &error);
+    piv->dump_ring = ufo_plugin_manager_get_task (manager, "dump_ring", &error);
+    piv->fftmult = ufo_plugin_manager_get_task (manager, "fftmult", &error);
+    piv->ordfilt = ufo_plugin_manager_get_task (manager, "ordfilt", &error);
+    piv->writer = ufo_plugin_manager_get_task (manager, "writer", &error);
+    piv->ringwriter = ufo_plugin_manager_get_task (manager, "ringwriter", &error);
+    piv->fft = ufo_plugin_manager_get_task (manager, "fft", &error);
+    piv->ringfft = ufo_plugin_manager_get_task (manager, "fft", &error);
+    piv->ringifft = ufo_plugin_manager_get_task (manager, "ifft", &error);
+    piv->ifft = ufo_plugin_manager_get_task (manager, "ifft", &error);
+}
+
+void piv_nodes_unref(struct piv_nodes *piv)
+{
+    g_object_unref (piv->broadcast_contrast);
+    g_object_unref (piv->broadcast_reader);
+    g_object_unref (piv->denoise);
+    g_object_unref (piv->contrast);
+    g_object_unref (piv->ring_pattern);
+    g_object_unref (piv->ordfilt);
+    g_object_unref (piv->filter_particle);
+    g_object_unref (piv->concatenate_result);
+    g_object_unref (piv->get_dup_circ);
+    g_object_unref (piv->remove_circle);
+    g_object_unref (piv->multi_search);
+    g_object_unref (piv->dump_ring);
+    g_object_unref (piv->fftmult);
+    g_object_unref (piv->writer);
+    g_object_unref (piv->ringwriter);
+    g_object_unref (piv->fft);
+    g_object_unref (piv->ringfft);
+    g_object_unref (piv->loop_ringfft);
+    g_object_unref (piv->ringifft);
+    g_object_unref (piv->ifft);
+    g_object_unref (piv->reduce);
+}
+
+void piv_nodes_set_gpu(struct piv_nodes *piv, UfoNode *proc_node)
+{
+    piv->proc_node = proc_node;
+    ufo_task_node_set_proc_node (piv->broadcast_reader, proc_node);
+    ufo_task_node_set_proc_node (piv->broadcast_reader, proc_node);
+    ufo_task_node_set_proc_node (piv->copy_replicater , proc_node);
+    ufo_task_node_set_proc_node (piv->broadcast_contrast , proc_node);
+    ufo_task_node_set_proc_node (piv->replicater      , proc_node);
+    ufo_task_node_set_proc_node (piv->replicate_reader, proc_node);
+    ufo_task_node_set_proc_node (piv->duplicater      , proc_node);
+    ufo_task_node_set_proc_node (piv->loop_ringfft    , proc_node);
+    ufo_task_node_set_proc_node (piv->denoise         , proc_node);
+    ufo_task_node_set_proc_node (piv->ring_pattern    , proc_node);
+    ufo_task_node_set_proc_node (piv->reduce          , proc_node);
+    ufo_task_node_set_proc_node (piv->contrast        , proc_node);
+    ufo_task_node_set_proc_node (piv->filter_particle , proc_node);
+    ufo_task_node_set_proc_node (piv->concatenate_result, proc_node);
+    ufo_task_node_set_proc_node (piv->get_dup_circ    , proc_node);
+    ufo_task_node_set_proc_node (piv->remove_circle   , proc_node);
+    ufo_task_node_set_proc_node (piv->multi_search    , proc_node);
+    ufo_task_node_set_proc_node (piv->dump_ring       , proc_node);
+    ufo_task_node_set_proc_node (piv->fftmult         , proc_node);
+    ufo_task_node_set_proc_node (piv->ordfilt         , proc_node);
+    ufo_task_node_set_proc_node (piv->writer          , proc_node);
+    ufo_task_node_set_proc_node (piv->ringwriter      , proc_node);
+    ufo_task_node_set_proc_node (piv->fft             , proc_node);
+    ufo_task_node_set_proc_node (piv->ringfft         , proc_node);
+    ufo_task_node_set_proc_node (piv->ringifft        , proc_node);
+    ufo_task_node_set_proc_node (piv->ifft            , proc_node);
+}

+ 54 - 0
piv-nodes.h

@@ -0,0 +1,54 @@
+#ifndef PIV_NODES_H
+#define PIV_NODES_H
+
+#include <ufo/ufo.h>
+
+#define PIV_COPY_TASK_NODE(dst, src1, src2) \
+    (((dst) = UFO_TASK_NODE (ufo_node_copy(UFO_NODE (src1), (src2)))));
+
+struct piv_ufo_base;
+
+struct piv_nodes
+{
+    UfoTaskNode *denoise;
+    UfoTaskNode *contrast;
+
+    /* Add broadcast plugins to attach to dump_rings wihch writes rings to a new
+     * image and a new contrast to be sent to the azimuthal checker */
+    UfoTaskNode *broadcast_contrast;
+    UfoTaskNode *broadcast_reader;
+    UfoTaskNode *copy_replicater;
+    UfoTaskNode *replicater;
+    UfoTaskNode *replicate_reader;
+    UfoTaskNode *duplicater;
+
+    UfoTaskNode *ring_pattern;
+    UfoTaskNode *ordfilt;
+    UfoTaskNode *filter_particle;
+    UfoTaskNode *concatenate_result;
+    UfoTaskNode *get_dup_circ;
+    UfoTaskNode *remove_circle;
+    UfoTaskNode *multi_search;
+    UfoTaskNode *dump_ring;
+    UfoTaskNode *fftmult;
+
+    // Plugin can be used to divide image by 4
+    UfoTaskNode *reduce;
+    UfoTaskNode *writer;
+    UfoTaskNode *ringwriter;
+    UfoTaskNode *fft;
+    UfoTaskNode *ringfft;
+    UfoTaskNode *loop_ringfft;
+    UfoTaskNode *ringifft;
+    UfoTaskNode *ifft;
+
+    // The gpu node that processes this structure
+    UfoNode *proc_node;
+};
+
+struct piv_nodes * piv_nodes_copy(struct piv_nodes *src);
+void piv_nodes_init(struct piv_nodes *piv, struct piv_ufo_base *b);
+void piv_nodes_unref(struct piv_nodes *piv);
+void piv_nodes_set_gpu(struct piv_nodes *piv, UfoNode *proc_node);
+
+#endif /* PIV_NODES_H */

+ 34 - 0
piv-scheduler.c

@@ -0,0 +1,34 @@
+#include "piv-scheduler.h"
+
+void expand_graph(UfoPluginManager *manager, GList *gpu_nodes,
+                  UfoTaskNode *src1, UfoTaskNode *src2, UfoTaskNode *out,
+                  unsigned ring_start, unsigned ring_end, unsigned ring_step,
+                  GError **error, UfoTaskGraph *graph)
+{
+    GList *it;
+    UfoTaskNode *fftmult;
+    for (it = gpu_nodes; it; it = it->next) {
+        fftmult = ufo_plugin_manager_get_task (manager, "fftmult", error);
+        g_object_set (G_OBJECT (fftmult), "ring_start", ring_start, NULL);
+        g_object_set (G_OBJECT (fftmult), "ring_end", ring_end, NULL);
+        g_object_set (G_OBJECT (fftmult), "ring_step", ring_step, NULL);
+        ufo_task_graph_connect_nodes_full (graph, src1, fftmult, 0);
+        ufo_task_graph_connect_nodes_full (graph, src2, fftmult, 1);
+        ufo_task_graph_connect_nodes (graph, fftmult, out);
+        ufo_task_node_set_proc_node (fftmult, it->data);
+    }
+}
+
+void expand_graph2(UfoPluginManager *manager, GList *gpu_nodes,
+                   UfoTaskNode *src, UfoTaskNode *out, const char *plugin_str,
+                   GError **error, UfoTaskGraph *graph)
+{
+    GList *it;
+    UfoTaskNode *plugin;
+    for (it = gpu_nodes; it; it = it->next) {
+        plugin = ufo_plugin_manager_get_task (manager, plugin_str, error);
+        ufo_task_graph_connect_nodes (graph, src, plugin);
+        ufo_task_graph_connect_nodes (graph, plugin, out);
+        ufo_task_node_set_proc_node (plugin, gpu_nodes->data);
+    }
+}

+ 15 - 0
piv-scheduler.h

@@ -0,0 +1,15 @@
+#ifndef SCHEDULER_HH
+#define SCHEDULER_HH
+
+#include <ufo/ufo.h>
+
+void expand_graph(UfoPluginManager *manager, GList *gpu_nodes,
+                  UfoTaskNode *src1, UfoTaskNode *src2, UfoTaskNode *out,
+                  unsigned ring_start, unsigned ring_end, unsigned ring_step,
+                  GError **error, UfoTaskGraph *graph);
+
+void expand_graph2(UfoPluginManager *manager, GList *gpu_nodes,
+                   UfoTaskNode *src, UfoTaskNode *out, const char *plugin_str,
+                   GError **error, UfoTaskGraph *graph);
+
+#endif // SCHEDULER_HH

+ 95 - 0
piv-ufo-base.c

@@ -0,0 +1,95 @@
+#include "piv-ufo-base.h"
+#include "piv-nodes.h"
+
+void
+piv_ufo_base_init(struct piv_ufo_base *piv_base)
+{
+    piv_base->error = NULL;
+
+    piv_base->graph = UFO_TASK_GRAPH (ufo_task_graph_new ());
+    piv_base->manager = ufo_plugin_manager_new ();
+    piv_base->resources = ufo_resources_new (&piv_base->error);
+    if (piv_base->error)
+        g_print("Error %s\n", piv_base->error->message);
+    ufo_resources_add_path (piv_base->resources, "src/kernel/denoise");
+    ufo_resources_add_path (piv_base->resources, "src/kernel/ordfilt");
+    ufo_resources_add_path (piv_base->resources, "src/kernel/fft");
+
+    piv_base->scheduler = ufo_fixed_scheduler_new ();
+    piv_base->arch = UFO_ARCH_GRAPH(ufo_arch_graph_new(piv_base->resources,
+                                                       NULL));
+    piv_base->gpu_nodes = ufo_arch_graph_get_gpu_nodes(piv_base->arch);
+    ufo_base_scheduler_set_gpu_nodes(piv_base->scheduler, piv_base->arch,
+                                     piv_base->gpu_nodes);
+}
+
+void piv_ufo_base_unref(struct piv_ufo_base *piv_base)
+{
+    g_object_unref (piv_base->graph);
+    g_object_unref (piv_base->scheduler);
+    g_object_unref (piv_base->manager);
+    g_object_unref (piv_base->resources);
+    g_object_unref (piv_base->arch);
+}
+
+void piv_ufo_base_connect(struct piv_ufo_base *piv_base, struct piv_nodes *piv,
+                          unsigned scale, unsigned dump_ring_to_image,
+                          UfoTaskNode* global_reader)
+{
+
+    UfoTaskGraph *graph = piv_base->graph;
+    ufo_task_graph_connect_nodes (graph, global_reader, piv->broadcast_reader);
+    if (scale > 1) {
+        ufo_task_graph_connect_nodes (graph, piv->broadcast_reader, piv->reduce);
+        ufo_task_graph_connect_nodes (graph, piv->reduce, piv->denoise);
+    }
+    else
+        ufo_task_graph_connect_nodes (graph, piv->broadcast_reader, piv->denoise);
+    ufo_task_graph_connect_nodes (graph, piv->denoise, piv->contrast);
+    ufo_task_graph_connect_nodes (graph, piv->contrast, piv->broadcast_contrast);
+    ufo_task_graph_connect_nodes (graph, piv->broadcast_contrast, piv->fft);
+    ufo_task_graph_connect_nodes (graph, piv->fft, piv->duplicater);
+
+    ufo_task_graph_connect_nodes (graph, piv->ring_pattern, piv->ringfft);
+    ufo_task_graph_connect_nodes (graph, piv->ringfft, piv->loop_ringfft);
+    //expand_graph(manager, gpu_nodes, duplicater, loop_ringfft, ringifft,
+    //             ring_start, ring_end, ring_step, piv_base->error, graph);
+    ufo_task_graph_connect_nodes_full (graph, piv->duplicater, piv->fftmult, 0);
+    ufo_task_graph_connect_nodes_full (graph, piv->loop_ringfft, piv->fftmult, 1);
+
+    //expand_graph2 (manager, gpu_nodes, piv->fftmult, piv->filter_particle, "ringifft",
+    //               &piv_base->error, graph);
+    ufo_task_graph_connect_nodes (graph, piv->fftmult, piv->ringifft);
+    ufo_task_graph_connect_nodes (graph, piv->ringifft, piv->filter_particle);
+    ufo_task_graph_connect_nodes (graph, piv->filter_particle, piv->concatenate_result);
+
+    ufo_task_graph_connect_nodes (graph, piv->broadcast_contrast, piv->replicater);
+
+    ufo_task_graph_connect_nodes_full (graph, piv->replicater,
+                                       piv->multi_search, 0);
+    ufo_task_graph_connect_nodes_full (graph, piv->concatenate_result,
+                                       piv->multi_search, 1);
+
+
+    ufo_task_graph_connect_nodes (graph, piv->multi_search, piv->remove_circle);
+    ufo_task_graph_connect_nodes (graph, piv->remove_circle, piv->get_dup_circ);
+
+    if (dump_ring_to_image) {
+        ufo_task_graph_connect_nodes (graph, piv->broadcast_reader,
+                                      piv->replicate_reader);
+        // Hack required to silence ERROR message for dead lock
+        ufo_task_graph_connect_nodes (graph, piv->replicate_reader,
+                                      piv->copy_replicater);
+        ufo_task_graph_connect_nodes_full (graph, piv->copy_replicater,
+                                           piv->dump_ring, 0);
+        ufo_task_graph_connect_nodes_full (graph, piv->get_dup_circ,
+                                           piv->dump_ring, 1);
+
+        ufo_task_graph_connect_nodes (graph, piv->dump_ring, piv->writer);
+    }
+    else
+        ufo_task_graph_connect_nodes (graph, piv->get_dup_circ, piv->ringwriter);
+
+    if (piv_base->error)
+        g_print("Error %s\n", piv_base->error->message);
+}

+ 27 - 0
piv-ufo-base.h

@@ -0,0 +1,27 @@
+#ifndef PIV_UFO_BASE_H
+#define PIV_UFO_BASE_H
+
+#include <ufo/ufo.h>
+
+struct piv_nodes;
+
+struct piv_ufo_base
+{
+    UfoTaskGraph *graph;
+    UfoArchGraph *arch;
+    UfoResources *resources;
+    UfoPluginManager *manager;
+    UfoBaseScheduler *scheduler;
+    GList *gpu_nodes;
+    GError *error;
+};
+
+
+void piv_ufo_base_init(struct piv_ufo_base *piv_base);
+void piv_ufo_base_unref(struct piv_ufo_base *piv_base);
+void piv_ufo_base_connect(struct piv_ufo_base *piv_base, struct piv_nodes *piv,
+                       unsigned scale, unsigned dump_ring_to_image,
+                       UfoTaskNode* global_reader);
+
+#endif /* PIV_UFO_BASE_H */
+

+ 89 - 0
piv.c

@@ -0,0 +1,89 @@
+#include <ufo/ufo.h>
+#include <stdio.h>
+#include "piv-scheduler.h"
+#include "piv-nodes.h"
+#include "piv-ufo-base.h"
+
+int main (void)
+{
+    struct piv_nodes piv;
+    struct piv_ufo_base piv_base;
+
+#if !(GLIB_CHECK_VERSION (2, 36, 0))
+    g_type_init ();
+#endif
+
+    piv_ufo_base_init(&piv_base);
+    piv_nodes_init(&piv, &piv_base);
+    if (piv_base.error)
+        printf("Error %s\n", piv_base.error->message);
+
+    /* This file include all the configurations that can be passed to the
+     * plugins */
+
+    /*********************/
+    /* CONFIGURATION *****/
+    /*********************/
+    UfoTaskNode *global_reader;
+    global_reader = ufo_plugin_manager_get_task (piv_base.manager, "reader",
+                                                 &piv_base.error);
+#include "config.h"
+
+    g_object_set (G_OBJECT (piv.ringwriter), "scale", scale, NULL);
+
+    g_object_set (G_OBJECT (piv.fft), "dimensions", 2, NULL);
+    g_object_set (G_OBJECT (piv.ifft), "dimensions", 2, NULL);
+    g_object_set (G_OBJECT (piv.ringfft), "dimensions", 2, NULL);
+    g_object_set (G_OBJECT (piv.ringifft), "dimensions", 2, NULL);
+
+    /* Give ring scale, when image is reduced by two, then scale should be 2 */
+    g_object_set (G_OBJECT (piv.dump_ring), "scale", scale, NULL);
+
+    /* Does not need user configuration */
+    unsigned number_of_rings = (ring_end - ring_start) / ring_step + 1;
+    g_object_set (G_OBJECT (piv.duplicater), "dup_count", number_of_rings,
+                  NULL);
+    g_object_set (G_OBJECT (piv.concatenate_result), "ring_count", number_of_rings, NULL);
+    g_object_set (G_OBJECT (piv.loop_ringfft), "loop", 1, NULL);
+    g_object_set (G_OBJECT (piv.loop_ringfft), "dup_count", number_of_images, NULL);
+
+    /*********************/
+    /* GRAPH SETUP *******/
+    /*********************/
+
+    GList* piv_nodes = NULL;
+    GList* it = piv_base.gpu_nodes;
+    if (!it) {
+        g_print("Main : No GPUs found\n");
+        return 1;
+    }
+    g_print("Main : Connecting nodes %p\n", it->data);
+    piv_nodes_set_gpu(&piv, it->data);
+    piv_nodes = g_list_append(piv_nodes, &piv);
+    piv_ufo_base_connect(&piv_base, &piv, scale, dump_ring_to_image, global_reader);
+
+    // Graph expansion for usage of multiple GPUs.  Uncomment lines when UFO
+    // supports calling plug-ins on demand
+    //for (it = it->next; it; it = it->next) {
+    //    g_print("Main : Connecting nodes %p\n", it->data);
+    //    struct piv_nodes *cpy = piv_nodes_copy(&piv);
+    //    piv_nodes = g_list_append(piv_nodes, cpy);
+    //    piv_nodes_set_gpu(cpy, it->data);
+    //    piv_ufo_base_connect(&piv_base, cpy, scale, dump_ring_to_image, global_reader);
+    //}
+    ufo_base_scheduler_run(piv_base.scheduler, piv_base.graph, &piv_base.error);
+    if (piv_base.error)
+        g_print("Error %s\n", piv_base.error->message);
+
+
+    /*********************/
+    /* CLEANUP ***********/
+    /*********************/
+
+    piv_ufo_base_unref(&piv_base);
+    for (it = piv_nodes; it; it = it->next)
+        piv_nodes_unref(it->data);
+    g_object_unref (global_reader);
+
+    return 0;
+}