[SCM] Gerris Flow Solver branch, upstream, updated. e8f73a07832050124d2b8bf6c6f35b33180e65a8

Stephane Popinet popinet at users.sf.net
Tue Nov 24 12:24:31 UTC 2009


The following commit has been merged in the upstream branch:
commit d330d3a8fc88cd7ed6705b52007b5fb42b671136
Author: Stephane Popinet <popinet at users.sf.net>
Date:   Tue Jul 14 11:36:51 2009 +1000

    Dynamic parallel load-balancing (EventBalance)
    
    darcs-hash:20090714013651-d4795-aedb8a52b8a2c1f3410412501146adfc23a8bcbd.gz

diff --git a/src/Makefile.am b/src/Makefile.am
index 9c21263..6b0aa37 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -58,6 +58,7 @@ GFS_HDS = \
 	map.h \
 	river.h \
 	moving.h \
+	balance.h \
 	version.h
 
 pkginclude_HEADERS = \
@@ -102,6 +103,7 @@ SRC = \
 	map.c \
 	river.c \
 	moving.c \
+	balance.c \
 	$(GFS_HDS)
 
 domain.c: version.h
diff --git a/src/balance.c b/src/balance.c
new file mode 100644
index 0000000..81274ad
--- /dev/null
+++ b/src/balance.c
@@ -0,0 +1,300 @@
+/* Gerris - The GNU Flow Solver
+ * Copyright (C) 2001-2009 National Institute of Water and Atmospheric Research
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "balance.h"
+#include "mpi_boundary.h"
+#include "adaptive.h"
+
+/* GfsEventBalance: Object */
+
+#ifdef HAVE_MPI
+
+static void find_neighbors (GfsBox * box, GArray * pe)
+{
+  FttDirection d;
+  for (d = 0; d < FTT_NEIGHBORS; d++)
+    if (GFS_IS_BOUNDARY_MPI (box->neighbor[d])) {
+      guint process = GFS_BOUNDARY_MPI (box->neighbor[d])->process;
+      gboolean found = FALSE;
+      gint i;
+      for (i = 0; i < pe->len && !found; i++)
+	if (g_array_index (pe, guint, i) == process)
+	  found = TRUE;
+      if (!found)
+	g_array_append_val (pe, process);
+    }      
+}
+
+static GArray * neighboring_processors (GfsDomain * domain)
+{
+  GArray * pe = g_array_new (FALSE, FALSE, sizeof (guint));
+  if (domain->pid >= 0)
+    gts_container_foreach (GTS_CONTAINER (domain), (GtsFunc) find_neighbors, pe);
+  return pe;
+}
+
+static void count (FttCell * cell, int * n)
+{
+  (*n)++;
+}
+
+#define NITERMAX 100
+#define TOL 0.001
+
+typedef struct {
+  guint * pid;     /* pid of neighbors */
+  gdouble * flow;  /* flow to neighbors */
+  guint n;         /* number of neighbors */
+} BalancingFlow;
+
+/*
+ * Computes the "balancing flow" necessary to balance the domain
+ * sizes on all the processes. @average is the average domain size
+ * (i.e. the target domain size).
+ */
+static BalancingFlow * balancing_flow_new (GfsDomain * domain, int average)
+{
+  BalancingFlow * b;
+
+  b = g_malloc0 (sizeof (BalancingFlow));
+  GArray * pe = neighboring_processors (domain);
+  if (pe->len == 0) {
+    g_array_free (pe, TRUE);
+    return b;
+  }
+  int size = 0, i;
+  gfs_domain_traverse_leaves (domain, (FttCellTraverseFunc) count, &size);
+  gdouble rsize = size - average;
+  gdouble * lambda = g_malloc (sizeof (gdouble)*(pe->len + 1)), lambda1, eps = G_MAXDOUBLE;
+  MPI_Request * request = g_malloc (sizeof (MPI_Request)*pe->len);
+  lambda1 = 0.;
+  /* this is Gamma and s from the "double-loop" fix of Johnson,
+     Bickson and Dolev, 2009, equation (6) */
+  gdouble Gamma = 0.5*pe->len, s = 0.5;
+  gdouble tolerance = MAX (TOL*average, 1.);
+  int niter = NITERMAX;
+  while (niter-- && eps > tolerance) {
+    MPI_Status status;
+    /* Send lambda to all neighbors */
+    lambda[0] = lambda1;
+    for (i = 0; i < pe->len; i++)
+      MPI_Isend (&(lambda[0]), 1, MPI_DOUBLE, g_array_index (pe, guint , i), 
+		 domain->pid,
+		 MPI_COMM_WORLD,
+		 &(request[i]));
+    /* Do one iteration of the "double-loop"-fixed Jacobi method for
+       the (graph)-Poisson equation */
+    gdouble rhs = rsize;
+    for (i = 0; i < pe->len; i++) {
+      MPI_Recv (&(lambda[i + 1]), 1, MPI_DOUBLE, g_array_index (pe, guint , i), 
+		g_array_index (pe, guint , i),
+		MPI_COMM_WORLD, &status);
+      rhs += lambda[i + 1];
+    }
+    /* update RHS and lambda for "double-loop"-fix */
+    rsize = (1. - s)*rsize + s*(size - average + Gamma*lambda[0]);
+    lambda1 = rhs/(Gamma + pe->len);
+    eps = fabs (lambda[0] - lambda1);
+    /* synchronize */
+    for (i = 0; i < pe->len; i++)
+      MPI_Wait (&request[i], &status);
+    gfs_all_reduce (domain, eps, MPI_DOUBLE, MPI_MAX);
+  }
+  g_free (request);
+  if (niter < 0 && domain->pid == 0)
+    g_warning ("balancing_flow(): could not converge after %d iterations", NITERMAX);
+
+  b->n = pe->len;
+  lambda1 = lambda[0];
+  for (i = 0; i < b->n; i++)
+    lambda[i] = lambda1 - lambda[i + 1];
+  b->flow = lambda;
+  b->pid = (guint *) g_array_free (pe, FALSE);
+  return b;
+}
+
+static void balancing_flow_destroy (BalancingFlow * b)
+{
+  g_free (b->pid);
+  g_free (b->flow);
+  g_free (b);
+}
+
+typedef struct {
+  GfsBox * box;
+  gint dest, n, min, neighboring;
+} BoxData;
+
+static void select_neighbouring_box (GfsBox * box, BoxData * b)
+{
+  gint neighboring = 0;
+  FttDirection d;
+
+  for (d = 0; d < FTT_NEIGHBORS; d++)
+    if (GFS_IS_BOUNDARY_MPI (box->neighbor[d]) &&
+	GFS_BOUNDARY_MPI (box->neighbor[d])->process == b->dest)
+      neighboring++;
+
+  if (neighboring && neighboring >= b->neighboring) {
+    box->size = 0;
+    ftt_cell_traverse (box->root, FTT_PRE_ORDER, FTT_TRAVERSE_LEAFS, -1,
+		       (FttCellTraverseFunc) count, &(box->size));
+    if (neighboring > b->neighboring ||
+	fabs (box->size - b->n) < fabs (b->box->size - b->n)) {
+      b->box = box;
+      b->neighboring = neighboring;
+    }
+  }
+}
+
+static void get_pid (GfsBox * box, guint * pid)
+{
+  pid[box->id - 1] = gfs_box_domain (box)->pid;
+}
+
+static void update_box_pid (GfsBox * box, guint * pid)
+{
+  FttDirection d;
+  for (d = 0; d < FTT_NEIGHBORS; d++)
+    if (GFS_IS_BOUNDARY_MPI (box->neighbor[d]))
+      GFS_BOUNDARY_MPI (box->neighbor[d])->process = 
+	pid[GFS_BOUNDARY_MPI (box->neighbor[d])->id - 1];
+}
+
+#endif /* HAVE_MPI */
+
+static void gfs_event_balance_write (GtsObject * o, FILE * fp)
+{
+  GfsEventBalance * s = GFS_EVENT_BALANCE (o);
+
+  if (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->write)
+    (* GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->write)
+      (o, fp);
+
+  fprintf (fp, " %g", s->max);
+}
+
+static void gfs_event_balance_read (GtsObject ** o, GtsFile * fp)
+{
+  GfsEventBalance * s = GFS_EVENT_BALANCE (*o);
+  GfsDomain * domain =  GFS_DOMAIN (gfs_object_simulation (s));
+
+  if (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->read)
+    (* GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->read) 
+      (o, fp);
+  if (fp->type == GTS_ERROR)
+    return;
+  
+  s->max = gfs_read_constant (fp, domain);
+}
+
+static gboolean gfs_event_balance_event (GfsEvent * event, GfsSimulation * sim)
+{
+  if ((* GFS_EVENT_CLASS (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class)->event) 
+      (event, sim)) {
+    GfsDomain * domain = GFS_DOMAIN (sim);
+    GfsEventBalance * s = GFS_EVENT_BALANCE (event);
+    GtsRange size, boundary, mpiwait;
+
+    gfs_domain_stats_balance (domain, &size, &boundary, &mpiwait);
+    if (size.max/size.min > 1. + s->max) {
+#ifdef HAVE_MPI
+      BalancingFlow * balance = balancing_flow_new (domain, size.mean);
+      GPtrArray * request = g_ptr_array_new ();
+      int modified = FALSE;
+      int i;
+      /* Send boxes */
+      for (i = 0; i < balance->n; i++)
+	if (balance->flow[i] > 0.) { /* largest subdomain */
+	  GSList * l = NULL;
+	  if (gts_container_size (GTS_CONTAINER (domain)) > 1) {
+	    BoxData b;
+	    b.box = NULL; b.neighboring = 0; b.n = balance->flow[i];
+	    b.dest = balance->pid[i];
+	    /* we need to find the list of boxes which minimizes 
+	       |\sum n_i - n| where n_i is the size of box i. This is known in
+	       combinatorial optimisation as a "knapsack problem". */
+	    gts_container_foreach (GTS_CONTAINER (domain), (GtsFunc) select_neighbouring_box, &b);
+	    if (b.box && b.box->size <= 2*b.n) {
+	      l = g_slist_prepend (l, b.box);
+	      modified = TRUE;
+	    }
+	  }
+	  g_ptr_array_add (request, gfs_send_boxes (domain, l, balance->pid[i]));
+	  g_slist_free (l);
+	}
+      /* Receive boxes */
+      for (i = 0; i < balance->n; i++)
+	if (balance->flow[i] < 0.) /* smallest subdomain */
+	  g_slist_free (gfs_receive_boxes (domain, balance->pid[i]));
+      /* Synchronize */
+      for (i = 0; i < request->len; i++)
+	gfs_wait (g_ptr_array_index (request, i));
+      g_ptr_array_free (request, TRUE);
+      balancing_flow_destroy (balance);
+      /* Reshape */
+      gfs_all_reduce (domain, modified, MPI_INT, MPI_MAX);
+      if (modified) {
+	/* Updates the pid associated with each box */
+	guint nb = gts_container_size (GTS_CONTAINER (domain));
+	gfs_all_reduce (domain, nb, MPI_UNSIGNED, MPI_SUM);
+	guint * pid = g_malloc0 (sizeof (guint)*nb);
+	gts_container_foreach (GTS_CONTAINER (domain), (GtsFunc) get_pid, pid);
+	MPI_Allreduce (pid, pid, nb, MPI_UNSIGNED, MPI_MAX, MPI_COMM_WORLD);
+	/* pid[id] now contains the current pid of box with index id */
+	gts_container_foreach (GTS_CONTAINER (domain), (GtsFunc) update_box_pid, pid);
+	g_free (pid);
+	gfs_domain_reshape (domain, gfs_domain_depth (domain));
+      }
+#else /* not HAVE_MPI */
+      g_assert_not_reached ();
+#endif /* not HAVE_MPI */
+    }
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static void gfs_event_balance_class_init (GfsEventClass * klass)
+{
+  GTS_OBJECT_CLASS (klass)->read = gfs_event_balance_read;
+  GTS_OBJECT_CLASS (klass)->write = gfs_event_balance_write;
+  GFS_EVENT_CLASS (klass)->event = gfs_event_balance_event;
+}
+
+GfsEventClass * gfs_event_balance_class (void)
+{
+  static GfsEventClass * klass = NULL;
+
+  if (klass == NULL) {
+    GtsObjectClassInfo gfs_event_balance_info = {
+      "GfsEventBalance",
+      sizeof (GfsEventBalance),
+      sizeof (GfsEventClass),
+      (GtsObjectClassInitFunc) gfs_event_balance_class_init,
+      (GtsObjectInitFunc) NULL,
+      (GtsArgSetFunc) NULL,
+      (GtsArgGetFunc) NULL
+    };
+    klass = gts_object_class_new (GTS_OBJECT_CLASS (gfs_event_class ()),
+				  &gfs_event_balance_info);
+  }
+
+  return klass;
+}
diff --git a/src/init.h b/src/balance.h
similarity index 58%
copy from src/init.h
copy to src/balance.h
index 425b2a2..2f5281f 100644
--- a/src/init.h
+++ b/src/balance.h
@@ -1,5 +1,5 @@
 /* Gerris - The GNU Flow Solver
- * Copyright (C) 2001 National Institute of Water and Atmospheric Research
+ * Copyright (C) 2001-2009 National Institute of Water and Atmospheric Research
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -17,21 +17,35 @@
  * 02111-1307, USA.  
  */
 
-#ifndef __INIT_H__
-#define __INIT_H__
-
-#include <gts.h>
+#ifndef __BALANCE_H__
+#define __BALANCE_H__
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
-GtsObjectClass ** gfs_classes             (void);
-void              gfs_init                (int * argc, 
-					   char *** argv);
+#include "event.h"
+
+/* GfsEventBalance: Header */
+
+typedef struct _GfsEventBalance         GfsEventBalance;
+
+struct _GfsEventBalance {
+  GfsEvent parent;
+
+  gdouble max;
+};
+
+#define GFS_EVENT_BALANCE(obj)            GTS_OBJECT_CAST (obj,\
+					         GfsEventBalance,\
+					         gfs_event_balance_class ())
+#define GFS_IS_EVENT_BALANCE(obj)         (gts_object_is_from_class (obj,\
+						 gfs_event_balance_class ()))
+
+GfsEventClass * gfs_event_balance_class  (void);
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 
-#endif /* __INIT_H__ */
+#endif /* __BALANCE_H__ */
diff --git a/src/domain.c b/src/domain.c
index 0ce0496..518c9ce 100644
--- a/src/domain.c
+++ b/src/domain.c
@@ -3849,41 +3849,78 @@ void gfs_domain_filter (GfsDomain * domain, GfsVariable * v, GfsVariable * fv)
     gfs_domain_copy_bc (domain, FTT_TRAVERSE_LEAFS, -1, v, fv);
 }
 
+struct _GfsRequest {  
+  FILE * fp;
+  long length;
+#ifdef HAVE_MPI
+  MPI_Request request[2];
+  void * buf;
+#endif
+};
+
 /**
  * gfs_send_objects:
  * @list: a list of #GtsObject.
  * @dest: the rank of the destination PE.
  *
  * Sends the objects in @list to PE @dest of a parallel simulation.
+ * This is a non-blocking operation which returns a handler which must
+ * be cleared by calling gfs_wait().
  *
  * Note that this functions assumes that the write() method of the
  * #GtsObject sent begins by writing the object class name.
+ *
+ * Returns: a #GfsRequest.
  */
-void gfs_send_objects (GSList * list, int dest)
+GfsRequest * gfs_send_objects (GSList * list, int dest)
 {
 #ifdef HAVE_MPI
-  FILE * fp = tmpfile ();
-  int fd = fileno (fp);
+  GfsRequest * r = g_malloc (sizeof (GfsRequest));
+  r->fp = tmpfile ();
+  int fd = fileno (r->fp);
   struct stat sb;
   while (list) {
     GtsObject * object = list->data;
     g_assert (object->klass->write != NULL);
-    (* object->klass->write) (object, fp);
-    fputc ('\n', fp);
+    (* object->klass->write) (object, r->fp);
+    fputc ('\n', r->fp);
     list = list->next;
   }
-  fflush (fp);
+  fflush (r->fp);
   g_assert (fstat (fd, &sb) != -1);
-  long length = sb.st_size;
-  MPI_Send (&length, 1, MPI_LONG, dest, 0, MPI_COMM_WORLD);
+  r->length = sb.st_size;
+  MPI_Isend (&r->length, 1, MPI_LONG, dest, 0, MPI_COMM_WORLD, &r->request[0]);
   /*  g_log (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "sending %ld bytes to PE %d", length, dest); */
-  if (length > 0) {
-    char * buf = mmap (NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
-    g_assert (buf != MAP_FAILED);
-    MPI_Send (buf, length, MPI_BYTE, dest, 1, MPI_COMM_WORLD);
-    munmap (buf, length);
+  if (r->length > 0) {
+    r->buf = mmap (NULL, r->length, PROT_READ, MAP_PRIVATE, fd, 0);
+    g_assert (r->buf != MAP_FAILED);
+    MPI_Isend (r->buf, r->length, MPI_BYTE, dest, 1, MPI_COMM_WORLD, &r->request[1]);
   }
-  fclose (fp);
+  return r;
+#else  /* not HAVE_MPI */
+  return NULL;
+#endif /* HAVE_MPI */
+}
+
+/**
+ * gfs_wait:
+ * @r: a #GfsRequest.
+ *
+ * Waits for completion of and deallocates @r.
+ */
+void gfs_wait (GfsRequest * r)
+{
+#ifdef HAVE_MPI
+  g_return_if_fail (r != NULL);
+
+  MPI_Status status;
+  MPI_Wait (&r->request[0], &status);
+  if (r->length > 0) {
+    MPI_Wait (&r->request[1], &status);
+    munmap (r->buf, r->length);
+  }
+  fclose (r->fp);
+  g_free (r);
 #endif /* HAVE_MPI */
 }
 
@@ -3963,22 +4000,37 @@ static void setup_binary_IO (GfsDomain * domain)
   domain->binary = TRUE;	
 }
 
-void gfs_send_boxes (GfsDomain * domain, GSList * boxes, int dest)
+/**
+ * gfs_send_boxes:
+ * @domain: a #GfsDomain.
+ * @boxes: a list of #GfsBox belonging to @domain.
+ * @dest: the destination processor id.
+ *
+ * Send boxes to @dest and removes them from @domain.
+ * This is a non-blocking operation.
+ *
+ * Returns: a #GfsRequest which must be cleared using gfs_wait().
+ */
+GfsRequest * gfs_send_boxes (GfsDomain * domain, GSList * boxes, int dest)
 {
-  g_return_if_fail (domain != NULL);
-  g_return_if_fail (dest != domain->pid);
+  g_return_val_if_fail (domain != NULL, NULL);
+  g_return_val_if_fail (dest != domain->pid, NULL);
 
   g_slist_foreach (boxes, (GFunc) unlink_box, &dest);
   setup_binary_IO (domain);
-  gfs_send_objects (boxes, dest);
+  GfsRequest * r = gfs_send_objects (boxes, dest);
   g_slist_foreach (boxes, (GFunc) gts_object_destroy, NULL);
-  if (boxes)
-    gfs_domain_reshape (domain, gfs_domain_depth (domain));
+  return r;
 }
 
 /**
  * gfs_receive_boxes:
- * @domain: 
+ * @domain: a #GfsDomain.
+ * @src: the source processor id.
+ *
+ * Receive boxes from @src and adds them to @domain.
+ *
+ * Returns: the list of boxes received.
  */
 GSList * gfs_receive_boxes (GfsDomain * domain, int src)
 {
@@ -3994,8 +4046,6 @@ GSList * gfs_receive_boxes (GfsDomain * domain, int src)
     /* Convert internal GfsBoundaryMpi into graph edges */
     g_slist_foreach (boxes, (GFunc) convert_boundary_mpi_into_edges, ids);
     g_ptr_array_free (ids, TRUE);
-
-    gfs_domain_reshape (domain, gfs_domain_depth (domain));
   }
   return boxes;
 }
diff --git a/src/domain.h b/src/domain.h
index ac811f5..2c38299 100644
--- a/src/domain.h
+++ b/src/domain.h
@@ -298,11 +298,13 @@ void         gfs_domain_sum                     (GfsDomain * domain,
 void         gfs_domain_filter                  (GfsDomain * domain, 
 						 GfsVariable * v,
 						 GfsVariable * fv);
-void         gfs_send_objects                   (GSList * list,
+typedef struct _GfsRequest GfsRequest;
+GfsRequest * gfs_send_objects                   (GSList * list,
 						 int dest);
+void         gfs_wait                           (GfsRequest * r);
 GSList *     gfs_receive_objects                (GfsDomain * domain, 
 						 int src);
-void         gfs_send_boxes                     (GfsDomain * domain, 
+GfsRequest * gfs_send_boxes                     (GfsDomain * domain, 
 						 GSList * boxes, 
 						 int dest);
 GSList *     gfs_receive_boxes                  (GfsDomain * domain, 
diff --git a/src/event.c b/src/event.c
index cda9a48..9f74a2c 100644
--- a/src/event.c
+++ b/src/event.c
@@ -27,7 +27,6 @@
 #include "event.h"
 #include "solid.h"
 #include "output.h"
-#include "mpi_boundary.h"
 
 /**
  * gfs_event_next:
@@ -1691,148 +1690,6 @@ GfsEventClass * gfs_event_script_class (void)
   return klass;
 }
 
-/* GfsEventBalance: Object */
-
-static void gfs_event_balance_write (GtsObject * o, FILE * fp)
-{
-  GfsEventBalance * s = GFS_EVENT_BALANCE (o);
-
-  if (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->write)
-    (* GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->write)
-      (o, fp);
-
-  fprintf (fp, " %g", s->max);
-}
-
-static void gfs_event_balance_read (GtsObject ** o, GtsFile * fp)
-{
-  GfsEventBalance * s = GFS_EVENT_BALANCE (*o);
-  GfsDomain * domain =  GFS_DOMAIN (gfs_object_simulation (s));
-
-  if (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->read)
-    (* GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->read) 
-      (o, fp);
-  if (fp->type == GTS_ERROR)
-    return;
-  
-  s->max = gfs_read_constant (fp, domain);
-}
-
-static void count (FttCell * cell, int * n)
-{
-  (*n)++;
-}
-
-typedef struct {
-  GfsBox * box;
-  gint dest, n, min, neighboring;
-} BoxData;
-
-#define LAMBDA 0.3
-
-static void select_neighbouring_box (GfsBox * box, BoxData * b)
-{
-  gint neighboring = 0;
-  FttDirection d;
-
-  for (d = 0; d < FTT_NEIGHBORS && !neighboring; d++)
-    if (GFS_IS_BOUNDARY_MPI (box->neighbor[d]) &&
-	GFS_BOUNDARY_MPI (box->neighbor[d])->process == b->dest)
-      neighboring++;
-
-  if (neighboring) {
-    box->size = 0;
-    ftt_cell_traverse (box->root, FTT_PRE_ORDER, FTT_TRAVERSE_LEAFS, -1,
-		       (FttCellTraverseFunc) count, &(box->size));
-    if (!b->box ||
-	(fabs (box->size - b->n) < (1. - LAMBDA)*fabs (b->box->size - b->n)) ||
-	(fabs (box->size - b->n) < (1. + LAMBDA)*fabs (b->box->size - b->n) &&
-	 neighboring > b->neighboring)) {
-      b->box = box;
-      b->neighboring = neighboring;
-    }
-  }
-}
-
-static gboolean gfs_event_balance_event (GfsEvent * event, GfsSimulation * sim)
-{
-  if ((* GFS_EVENT_CLASS (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class)->event) 
-      (event, sim)) {
-    GfsDomain * domain = GFS_DOMAIN (sim);
-    GfsEventBalance * s = GFS_EVENT_BALANCE (event);
-    GtsRange size, boundary, mpiwait;
-
-    gfs_domain_stats_balance (domain, &size, &boundary, &mpiwait);
-    if (size.max/size.min > s->max) {
-#ifdef HAVE_MPI
-      int n, other;
-      MPI_Comm_size (MPI_COMM_WORLD, &n);
-      if (n != 2)
-	g_assert_not_implemented ();
-      
-      n = 0;
-      gfs_domain_cell_traverse (domain, FTT_PRE_ORDER, FTT_TRAVERSE_LEAFS, -1,
-				(FttCellTraverseFunc) count, &n);
-      other = (domain->pid + 1) % 2;
-      if (n > size.mean) { /* largest subdomain */
-	if (gts_container_size (GTS_CONTAINER (domain)) < 2)
-	  gfs_send_boxes (domain, NULL, other);
-	else {
-	  n -= size.mean;
-	  
-	  BoxData b;
-	  b.box = NULL; b.n = n;
-	  b.dest = other;
-	  /* we need to find the list of boxes which minimizes 
-	     |\sum n_i - n| where n_i is the size of box i. This is known in
-	     combinatorial optimisation as a "knapsack problem". */
-	  gts_container_foreach (GTS_CONTAINER (domain), (GtsFunc) select_neighbouring_box, &b);
-	  if (b.box && b.box->size <= size.max - size.min) {
-	    GSList * l = g_slist_prepend (NULL, b.box);
-	    gfs_send_boxes (domain, l, other);
-	    g_slist_free (l);
-	  }
-	  else
-	    gfs_send_boxes (domain, NULL, other);
-	}
-      }
-      else /* smallest subdomain */
-	g_slist_free (gfs_receive_boxes (domain, other));
-#endif     
-    }
-    return TRUE;
-  }
-  return FALSE;
-}
-
-static void gfs_event_balance_class_init (GfsEventClass * klass)
-{
-  GTS_OBJECT_CLASS (klass)->read = gfs_event_balance_read;
-  GTS_OBJECT_CLASS (klass)->write = gfs_event_balance_write;
-  GFS_EVENT_CLASS (klass)->event = gfs_event_balance_event;
-}
-
-GfsEventClass * gfs_event_balance_class (void)
-{
-  static GfsEventClass * klass = NULL;
-
-  if (klass == NULL) {
-    GtsObjectClassInfo gfs_event_balance_info = {
-      "GfsEventBalance",
-      sizeof (GfsEventBalance),
-      sizeof (GfsEventClass),
-      (GtsObjectClassInitFunc) gfs_event_balance_class_init,
-      (GtsObjectInitFunc) NULL,
-      (GtsArgSetFunc) NULL,
-      (GtsArgGetFunc) NULL
-    };
-    klass = gts_object_class_new (GTS_OBJECT_CLASS (gfs_event_class ()),
-				  &gfs_event_balance_info);
-  }
-
-  return klass;
-}
-
 /* GfsInitFraction: Object */
 
 static void gfs_init_fraction_destroy (GtsObject * object)
diff --git a/src/event.h b/src/event.h
index 9d6a270..ceaf86f 100644
--- a/src/event.h
+++ b/src/event.h
@@ -251,24 +251,6 @@ struct _GfsEventScript {
 
 GfsEventClass * gfs_event_script_class  (void);
 
-/* GfsEventBalance: Header */
-
-typedef struct _GfsEventBalance         GfsEventBalance;
-
-struct _GfsEventBalance {
-  GfsEvent parent;
-
-  gdouble max;
-};
-
-#define GFS_EVENT_BALANCE(obj)            GTS_OBJECT_CAST (obj,\
-					         GfsEventBalance,\
-					         gfs_event_balance_class ())
-#define GFS_IS_EVENT_BALANCE(obj)         (gts_object_is_from_class (obj,\
-						 gfs_event_balance_class ()))
-
-GfsEventClass * gfs_event_balance_class  (void);
-
 /* GfsInitFraction: Header */
 
 typedef struct _GfsInitFraction         GfsInitFraction;
diff --git a/src/init.c b/src/init.c
index b0064a8..91c0d68 100644
--- a/src/init.c
+++ b/src/init.c
@@ -42,6 +42,7 @@
 #include "solid.h"
 #include "moving.h"
 #include "river.h"
+#include "balance.h"
 
 #include "modules.h"
 
diff --git a/src/mpi_boundary.c b/src/mpi_boundary.c
index e0063f5..8951196 100644
--- a/src/mpi_boundary.c
+++ b/src/mpi_boundary.c
@@ -74,6 +74,7 @@ fprintf (DEBUG, "%d send to %d with tag %d match variable size\n",
 	 domain->pid, 
 	 mpi->process,
 	 TAG (GFS_BOUNDARY (boundary)));
+fflush (DEBUG);
 #endif
     MPI_Isend (&boundary->sndcount, 1, MPI_UNSIGNED,
 	       mpi->process,
@@ -88,6 +89,7 @@ fprintf (DEBUG, "%d send to %d with tag %d, size %d\n",
 	 mpi->process,
 	 TAG (GFS_BOUNDARY (boundary)),
 	 boundary->sndcount);
+fflush (DEBUG);
 #endif
   MPI_Isend (boundary->sndbuf->data, boundary->sndcount, MPI_DOUBLE,
 	     mpi->process,
@@ -124,6 +126,7 @@ fprintf (DEBUG, "%d wait on %d with tag %d for match variable size\n",
 	 gfs_box_domain (bb->box)->pid,
 	 mpi->process,
 	 MATCHING_TAG (GFS_BOUNDARY (boundary)));
+fflush (DEBUG);
 #endif
     MPI_Recv (&boundary->rcvcount, 1, MPI_UNSIGNED,
 	      mpi->process,
@@ -145,6 +148,7 @@ fprintf (DEBUG, "%d wait on %d with tag %d for match variable size\n",
 	   gfs_box_domain (bb->box)->pid,
 	   mpi->process,
 	   MATCHING_TAG (GFS_BOUNDARY (boundary)));
+fflush (DEBUG);
 #endif
   g_assert (boundary->rcvcount <= boundary->rcvbuf->len);
   MPI_Recv (boundary->rcvbuf->data,
@@ -207,6 +211,7 @@ static void synchronize (GfsBoundary * bb)
   /*  rewind (DEBUG); */
   fprintf (DEBUG, "==== %d synchronised ====\n",
 	   gfs_box_domain (bb->box)->pid);
+  fflush (DEBUG);
 #endif
   (* gfs_boundary_periodic_class ()->synchronize) (bb);
 }

-- 
Gerris Flow Solver



More information about the debian-science-commits mailing list