Zoltan is added as thirdParty package

This commit is contained in:
Hamidreza
2025-05-15 21:58:43 +03:30
parent 83a6e4baa1
commit d7479cf1bd
3392 changed files with 318142 additions and 1 deletions

View File

@ -0,0 +1,68 @@
TRIBITS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${PACKAGE_SOURCE_DIR}/src/zz)
TRIBITS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${PACKAGE_SOURCE_DIR}/src/lb)
TRIBITS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${PACKAGE_SOURCE_DIR}/src/Utilities/shared)
TRIBITS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${PACKAGE_SOURCE_DIR}/src/params)
TRIBITS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${PACKAGE_SOURCE_DIR}/src/order)
TRIBITS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${PACKAGE_SOURCE_DIR}/src/par)
TRIBITS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${PACKAGE_SOURCE_DIR}/src/tpls)
TRIBITS_ADD_EXECUTABLE_AND_TEST(
simpleHIER
SOURCES simpleHIER.c
ARGS
COMM mpi
NUM_MPI_PROCS 1-4
)
TRIBITS_ADD_EXECUTABLE_AND_TEST(
simpleBLOCK
SOURCES simpleBLOCK.c
ARGS
COMM serial mpi
NUM_MPI_PROCS 1-4
)
TRIBITS_ADD_EXECUTABLE_AND_TEST(
simpleRCB
SOURCES simpleRCB.c
ARGS
COMM serial mpi
NUM_MPI_PROCS 1-4
)
TRIBITS_ADD_EXECUTABLE_AND_TEST(
simpleGRAPH
SOURCES simpleGRAPH.c
ARGS
COMM serial mpi
NUM_MPI_PROCS 1-4
)
TRIBITS_ADD_EXECUTABLE_AND_TEST(
simplePHG
SOURCES simplePHG.c
ARGS
COMM serial mpi
NUM_MPI_PROCS 1-4
)
TRIBITS_ADD_EXECUTABLE_AND_TEST(
migrateGRAPH
SOURCES migrateGRAPH.c
ARGS
COMM serial mpi
NUM_MPI_PROCS 1-4
)
TRIBITS_ADD_EXECUTABLE_AND_TEST(
problemGRAPH
SOURCES problemGRAPH.c
ARGS
COMM serial mpi
NUM_MPI_PROCS 1-4
)
TRIBITS_COPY_FILES_TO_BINARY_DIR(CExamplesCopyFiles
SOURCE_FILES hypergraph.txt mesh.txt objects.txt graph.txt
)

85
thirdParty/Zoltan/example/C/Makefile.am vendored Normal file
View File

@ -0,0 +1,85 @@
# @HEADER
#
########################################################################
#
# Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
# Copyright 2012 Sandia Corporation
#
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the Corporation nor the names of the
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "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 SANDIA CORPORATION OR THE
# CONTRIBUTORS 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.
#
# Questions? Contact Karen Devine kddevin@sandia.gov
# Erik Boman egboman@sandia.gov
#
########################################################################
#
# @HEADER
# The following line helps the test harness recover from build errors.
all-local:
include $(top_builddir)/Makefile.export.zoltan
EXEEXT = .exe
noinst_PROGRAMS = simpleBLOCK simpleRCB simpleGRAPH simplePHG problemGRAPH
simpleBLOCK_SOURCES = simpleBLOCK.c
simpleBLOCK_DEPENDENCIES = $(ZOLTAN_DEPS)
simpleBLOCK_CFLAGS = $(ZOLTAN_INCLUDES)
simpleBLOCK_LDADD = $(ZOLTAN_LIBS)
simpleRCB_SOURCES = simpleRCB.c
simpleRCB_DEPENDENCIES = $(ZOLTAN_DEPS)
simpleRCB_CFLAGS = $(ZOLTAN_INCLUDES)
simpleRCB_LDADD = $(ZOLTAN_LIBS)
simpleGRAPH_SOURCES = simpleGRAPH.c
simpleGRAPH_DEPENDENCIES = $(ZOLTAN_DEPS)
simpleGRAPH_CFLAGS = $(ZOLTAN_LIBRARY_INCLUDES)
simpleGRAPH_LDADD = $(ZOLTAN_LIBS)
simplePHG_SOURCES = simplePHG.c
simplePHG_DEPENDENCIES = $(ZOLTAN_DEPS)
simplePHG_CFLAGS = $(ZOLTAN_INCLUDES)
simplePHG_LDADD = $(ZOLTAN_LIBS)
problemGRAPH_SOURCES = problemGRAPH.c
problemGRAPH_DEPENDENCIES = $(ZOLTAN_DEPS)
problemGRAPH_CFLAGS = $(ZOLTAN_LIBRARY_INCLUDES)
problemGRAPH_LDADD = $(ZOLTAN_LIBS)
EXTRA_DIST = classicMakefile objects.txt hypergraph.txt graph.txt mesh.txt
FNAMES=$(EXTRA_DIST:%=$(srcdir)/%)
all-local:
if test -e Makefile.am ; then : ; else cp $(FNAMES) $(builddir); fi

656
thirdParty/Zoltan/example/C/Makefile.in vendored Normal file
View File

@ -0,0 +1,656 @@
# Makefile.in generated by automake 1.11.3 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
# Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
# @HEADER
#
########################################################################
#
# Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
# Copyright 2012 Sandia Corporation
#
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the Corporation nor the names of the
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "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 SANDIA CORPORATION OR THE
# CONTRIBUTORS 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.
#
# Questions? Contact Karen Devine kddevin@sandia.gov
# Erik Boman egboman@sandia.gov
#
########################################################################
#
# @HEADER
# The following line helps the test harness recover from build errors.
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
noinst_PROGRAMS = simpleBLOCK$(EXEEXT) simpleRCB$(EXEEXT) \
simpleGRAPH$(EXEEXT) simplePHG$(EXEEXT) problemGRAPH$(EXEEXT)
subdir = example/C
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/config/ax_f90_module_case.m4 \
$(top_srcdir)/config/ax_f90_module_flag.m4 \
$(top_srcdir)/config/tac_arg_check_mpi.m4 \
$(top_srcdir)/config/tac_arg_enable_export-makefiles.m4 \
$(top_srcdir)/config/tac_arg_enable_feature.m4 \
$(top_srcdir)/config/tac_arg_enable_feature_sub.m4 \
$(top_srcdir)/config/tac_arg_enable_feature_sub_check.m4 \
$(top_srcdir)/config/tac_arg_enable_option.m4 \
$(top_srcdir)/config/tac_arg_with_3pl_sub.m4 \
$(top_srcdir)/config/tac_arg_with_ar.m4 \
$(top_srcdir)/config/tac_arg_with_flags.m4 \
$(top_srcdir)/config/tac_arg_with_incdirs.m4 \
$(top_srcdir)/config/tac_arg_with_libdirs.m4 \
$(top_srcdir)/config/tac_arg_with_libs.m4 \
$(top_srcdir)/config/tac_arg_with_package.m4 \
$(top_srcdir)/config/tac_arg_with_perl.m4 \
$(top_srcdir)/config/wk_fc_get_vendor.m4 \
$(top_srcdir)/config/zac_arg_config_mpi.m4 \
$(top_srcdir)/config/zac_arg_with_id.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/src/include/Zoltan_config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
PROGRAMS = $(noinst_PROGRAMS)
am_problemGRAPH_OBJECTS = problemGRAPH-problemGRAPH.$(OBJEXT)
problemGRAPH_OBJECTS = $(am_problemGRAPH_OBJECTS)
problemGRAPH_LINK = $(CCLD) $(problemGRAPH_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
am_simpleBLOCK_OBJECTS = simpleBLOCK-simpleBLOCK.$(OBJEXT)
simpleBLOCK_OBJECTS = $(am_simpleBLOCK_OBJECTS)
simpleBLOCK_LINK = $(CCLD) $(simpleBLOCK_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
am_simpleGRAPH_OBJECTS = simpleGRAPH-simpleGRAPH.$(OBJEXT)
simpleGRAPH_OBJECTS = $(am_simpleGRAPH_OBJECTS)
simpleGRAPH_LINK = $(CCLD) $(simpleGRAPH_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
am_simplePHG_OBJECTS = simplePHG-simplePHG.$(OBJEXT)
simplePHG_OBJECTS = $(am_simplePHG_OBJECTS)
simplePHG_LINK = $(CCLD) $(simplePHG_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
am_simpleRCB_OBJECTS = simpleRCB-simpleRCB.$(OBJEXT)
simpleRCB_OBJECTS = $(am_simpleRCB_OBJECTS)
simpleRCB_LINK = $(CCLD) $(simpleRCB_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/src/include
depcomp = $(SHELL) $(top_srcdir)/config/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(problemGRAPH_SOURCES) $(simpleBLOCK_SOURCES) \
$(simpleGRAPH_SOURCES) $(simplePHG_SOURCES) \
$(simpleRCB_SOURCES)
DIST_SOURCES = $(problemGRAPH_SOURCES) $(simpleBLOCK_SOURCES) \
$(simpleGRAPH_SOURCES) $(simplePHG_SOURCES) \
$(simpleRCB_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ALTERNATE_AR = @ALTERNATE_AR@
AMTAR = @AMTAR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EXEEXT = .exe
FC = @FC@
FCFLAGS = @FCFLAGS@
FCFLAGS_f = @FCFLAGS_f@
FCFLAGS_f90 = @FCFLAGS_f90@
FCLIBS = @FCLIBS@
FC_MAJOR_VERSION = @FC_MAJOR_VERSION@
FC_MODNAME = @FC_MODNAME@
FC_MODNAME_Q = @FC_MODNAME_Q@
FC_VENDOR = @FC_VENDOR@
FC_VERSION = @FC_VERSION@
FC_VERSION_STRING = @FC_VERSION_STRING@
HAVE_PERL = @HAVE_PERL@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
MPI_CC = @MPI_CC@
MPI_CXX = @MPI_CXX@
MPI_FC = @MPI_FC@
MPI_RECV_LIMIT_FLAG = @MPI_RECV_LIMIT_FLAG@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL_EXE = @PERL_EXE@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_aux_dir = @ac_aux_dir@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_FC = @ac_ct_FC@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
simpleBLOCK_SOURCES = simpleBLOCK.c
simpleBLOCK_DEPENDENCIES = $(ZOLTAN_DEPS)
simpleBLOCK_CFLAGS = $(ZOLTAN_INCLUDES)
simpleBLOCK_LDADD = $(ZOLTAN_LIBS)
simpleRCB_SOURCES = simpleRCB.c
simpleRCB_DEPENDENCIES = $(ZOLTAN_DEPS)
simpleRCB_CFLAGS = $(ZOLTAN_INCLUDES)
simpleRCB_LDADD = $(ZOLTAN_LIBS)
simpleGRAPH_SOURCES = simpleGRAPH.c
simpleGRAPH_DEPENDENCIES = $(ZOLTAN_DEPS)
simpleGRAPH_CFLAGS = $(ZOLTAN_LIBRARY_INCLUDES)
simpleGRAPH_LDADD = $(ZOLTAN_LIBS)
simplePHG_SOURCES = simplePHG.c
simplePHG_DEPENDENCIES = $(ZOLTAN_DEPS)
simplePHG_CFLAGS = $(ZOLTAN_INCLUDES)
simplePHG_LDADD = $(ZOLTAN_LIBS)
problemGRAPH_SOURCES = problemGRAPH.c
problemGRAPH_DEPENDENCIES = $(ZOLTAN_DEPS)
problemGRAPH_CFLAGS = $(ZOLTAN_LIBRARY_INCLUDES)
problemGRAPH_LDADD = $(ZOLTAN_LIBS)
EXTRA_DIST = classicMakefile objects.txt hypergraph.txt graph.txt mesh.txt
FNAMES = $(EXTRA_DIST:%=$(srcdir)/%)
all: all-am
.SUFFIXES:
.SUFFIXES: .c .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu example/C/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --gnu example/C/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstPROGRAMS:
-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
problemGRAPH$(EXEEXT): $(problemGRAPH_OBJECTS) $(problemGRAPH_DEPENDENCIES) $(EXTRA_problemGRAPH_DEPENDENCIES)
@rm -f problemGRAPH$(EXEEXT)
$(problemGRAPH_LINK) $(problemGRAPH_OBJECTS) $(problemGRAPH_LDADD) $(LIBS)
simpleBLOCK$(EXEEXT): $(simpleBLOCK_OBJECTS) $(simpleBLOCK_DEPENDENCIES) $(EXTRA_simpleBLOCK_DEPENDENCIES)
@rm -f simpleBLOCK$(EXEEXT)
$(simpleBLOCK_LINK) $(simpleBLOCK_OBJECTS) $(simpleBLOCK_LDADD) $(LIBS)
simpleGRAPH$(EXEEXT): $(simpleGRAPH_OBJECTS) $(simpleGRAPH_DEPENDENCIES) $(EXTRA_simpleGRAPH_DEPENDENCIES)
@rm -f simpleGRAPH$(EXEEXT)
$(simpleGRAPH_LINK) $(simpleGRAPH_OBJECTS) $(simpleGRAPH_LDADD) $(LIBS)
simplePHG$(EXEEXT): $(simplePHG_OBJECTS) $(simplePHG_DEPENDENCIES) $(EXTRA_simplePHG_DEPENDENCIES)
@rm -f simplePHG$(EXEEXT)
$(simplePHG_LINK) $(simplePHG_OBJECTS) $(simplePHG_LDADD) $(LIBS)
simpleRCB$(EXEEXT): $(simpleRCB_OBJECTS) $(simpleRCB_DEPENDENCIES) $(EXTRA_simpleRCB_DEPENDENCIES)
@rm -f simpleRCB$(EXEEXT)
$(simpleRCB_LINK) $(simpleRCB_OBJECTS) $(simpleRCB_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/problemGRAPH-problemGRAPH.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpleBLOCK-simpleBLOCK.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpleGRAPH-simpleGRAPH.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simplePHG-simplePHG.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/simpleRCB-simpleRCB.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
problemGRAPH-problemGRAPH.o: problemGRAPH.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(problemGRAPH_CFLAGS) $(CFLAGS) -MT problemGRAPH-problemGRAPH.o -MD -MP -MF $(DEPDIR)/problemGRAPH-problemGRAPH.Tpo -c -o problemGRAPH-problemGRAPH.o `test -f 'problemGRAPH.c' || echo '$(srcdir)/'`problemGRAPH.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/problemGRAPH-problemGRAPH.Tpo $(DEPDIR)/problemGRAPH-problemGRAPH.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='problemGRAPH.c' object='problemGRAPH-problemGRAPH.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(problemGRAPH_CFLAGS) $(CFLAGS) -c -o problemGRAPH-problemGRAPH.o `test -f 'problemGRAPH.c' || echo '$(srcdir)/'`problemGRAPH.c
problemGRAPH-problemGRAPH.obj: problemGRAPH.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(problemGRAPH_CFLAGS) $(CFLAGS) -MT problemGRAPH-problemGRAPH.obj -MD -MP -MF $(DEPDIR)/problemGRAPH-problemGRAPH.Tpo -c -o problemGRAPH-problemGRAPH.obj `if test -f 'problemGRAPH.c'; then $(CYGPATH_W) 'problemGRAPH.c'; else $(CYGPATH_W) '$(srcdir)/problemGRAPH.c'; fi`
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/problemGRAPH-problemGRAPH.Tpo $(DEPDIR)/problemGRAPH-problemGRAPH.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='problemGRAPH.c' object='problemGRAPH-problemGRAPH.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(problemGRAPH_CFLAGS) $(CFLAGS) -c -o problemGRAPH-problemGRAPH.obj `if test -f 'problemGRAPH.c'; then $(CYGPATH_W) 'problemGRAPH.c'; else $(CYGPATH_W) '$(srcdir)/problemGRAPH.c'; fi`
simpleBLOCK-simpleBLOCK.o: simpleBLOCK.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleBLOCK_CFLAGS) $(CFLAGS) -MT simpleBLOCK-simpleBLOCK.o -MD -MP -MF $(DEPDIR)/simpleBLOCK-simpleBLOCK.Tpo -c -o simpleBLOCK-simpleBLOCK.o `test -f 'simpleBLOCK.c' || echo '$(srcdir)/'`simpleBLOCK.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/simpleBLOCK-simpleBLOCK.Tpo $(DEPDIR)/simpleBLOCK-simpleBLOCK.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='simpleBLOCK.c' object='simpleBLOCK-simpleBLOCK.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleBLOCK_CFLAGS) $(CFLAGS) -c -o simpleBLOCK-simpleBLOCK.o `test -f 'simpleBLOCK.c' || echo '$(srcdir)/'`simpleBLOCK.c
simpleBLOCK-simpleBLOCK.obj: simpleBLOCK.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleBLOCK_CFLAGS) $(CFLAGS) -MT simpleBLOCK-simpleBLOCK.obj -MD -MP -MF $(DEPDIR)/simpleBLOCK-simpleBLOCK.Tpo -c -o simpleBLOCK-simpleBLOCK.obj `if test -f 'simpleBLOCK.c'; then $(CYGPATH_W) 'simpleBLOCK.c'; else $(CYGPATH_W) '$(srcdir)/simpleBLOCK.c'; fi`
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/simpleBLOCK-simpleBLOCK.Tpo $(DEPDIR)/simpleBLOCK-simpleBLOCK.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='simpleBLOCK.c' object='simpleBLOCK-simpleBLOCK.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleBLOCK_CFLAGS) $(CFLAGS) -c -o simpleBLOCK-simpleBLOCK.obj `if test -f 'simpleBLOCK.c'; then $(CYGPATH_W) 'simpleBLOCK.c'; else $(CYGPATH_W) '$(srcdir)/simpleBLOCK.c'; fi`
simpleGRAPH-simpleGRAPH.o: simpleGRAPH.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleGRAPH_CFLAGS) $(CFLAGS) -MT simpleGRAPH-simpleGRAPH.o -MD -MP -MF $(DEPDIR)/simpleGRAPH-simpleGRAPH.Tpo -c -o simpleGRAPH-simpleGRAPH.o `test -f 'simpleGRAPH.c' || echo '$(srcdir)/'`simpleGRAPH.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/simpleGRAPH-simpleGRAPH.Tpo $(DEPDIR)/simpleGRAPH-simpleGRAPH.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='simpleGRAPH.c' object='simpleGRAPH-simpleGRAPH.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleGRAPH_CFLAGS) $(CFLAGS) -c -o simpleGRAPH-simpleGRAPH.o `test -f 'simpleGRAPH.c' || echo '$(srcdir)/'`simpleGRAPH.c
simpleGRAPH-simpleGRAPH.obj: simpleGRAPH.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleGRAPH_CFLAGS) $(CFLAGS) -MT simpleGRAPH-simpleGRAPH.obj -MD -MP -MF $(DEPDIR)/simpleGRAPH-simpleGRAPH.Tpo -c -o simpleGRAPH-simpleGRAPH.obj `if test -f 'simpleGRAPH.c'; then $(CYGPATH_W) 'simpleGRAPH.c'; else $(CYGPATH_W) '$(srcdir)/simpleGRAPH.c'; fi`
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/simpleGRAPH-simpleGRAPH.Tpo $(DEPDIR)/simpleGRAPH-simpleGRAPH.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='simpleGRAPH.c' object='simpleGRAPH-simpleGRAPH.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleGRAPH_CFLAGS) $(CFLAGS) -c -o simpleGRAPH-simpleGRAPH.obj `if test -f 'simpleGRAPH.c'; then $(CYGPATH_W) 'simpleGRAPH.c'; else $(CYGPATH_W) '$(srcdir)/simpleGRAPH.c'; fi`
simplePHG-simplePHG.o: simplePHG.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simplePHG_CFLAGS) $(CFLAGS) -MT simplePHG-simplePHG.o -MD -MP -MF $(DEPDIR)/simplePHG-simplePHG.Tpo -c -o simplePHG-simplePHG.o `test -f 'simplePHG.c' || echo '$(srcdir)/'`simplePHG.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/simplePHG-simplePHG.Tpo $(DEPDIR)/simplePHG-simplePHG.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='simplePHG.c' object='simplePHG-simplePHG.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simplePHG_CFLAGS) $(CFLAGS) -c -o simplePHG-simplePHG.o `test -f 'simplePHG.c' || echo '$(srcdir)/'`simplePHG.c
simplePHG-simplePHG.obj: simplePHG.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simplePHG_CFLAGS) $(CFLAGS) -MT simplePHG-simplePHG.obj -MD -MP -MF $(DEPDIR)/simplePHG-simplePHG.Tpo -c -o simplePHG-simplePHG.obj `if test -f 'simplePHG.c'; then $(CYGPATH_W) 'simplePHG.c'; else $(CYGPATH_W) '$(srcdir)/simplePHG.c'; fi`
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/simplePHG-simplePHG.Tpo $(DEPDIR)/simplePHG-simplePHG.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='simplePHG.c' object='simplePHG-simplePHG.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simplePHG_CFLAGS) $(CFLAGS) -c -o simplePHG-simplePHG.obj `if test -f 'simplePHG.c'; then $(CYGPATH_W) 'simplePHG.c'; else $(CYGPATH_W) '$(srcdir)/simplePHG.c'; fi`
simpleRCB-simpleRCB.o: simpleRCB.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleRCB_CFLAGS) $(CFLAGS) -MT simpleRCB-simpleRCB.o -MD -MP -MF $(DEPDIR)/simpleRCB-simpleRCB.Tpo -c -o simpleRCB-simpleRCB.o `test -f 'simpleRCB.c' || echo '$(srcdir)/'`simpleRCB.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/simpleRCB-simpleRCB.Tpo $(DEPDIR)/simpleRCB-simpleRCB.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='simpleRCB.c' object='simpleRCB-simpleRCB.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleRCB_CFLAGS) $(CFLAGS) -c -o simpleRCB-simpleRCB.o `test -f 'simpleRCB.c' || echo '$(srcdir)/'`simpleRCB.c
simpleRCB-simpleRCB.obj: simpleRCB.c
@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleRCB_CFLAGS) $(CFLAGS) -MT simpleRCB-simpleRCB.obj -MD -MP -MF $(DEPDIR)/simpleRCB-simpleRCB.Tpo -c -o simpleRCB-simpleRCB.obj `if test -f 'simpleRCB.c'; then $(CYGPATH_W) 'simpleRCB.c'; else $(CYGPATH_W) '$(srcdir)/simpleRCB.c'; fi`
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/simpleRCB-simpleRCB.Tpo $(DEPDIR)/simpleRCB-simpleRCB.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='simpleRCB.c' object='simpleRCB-simpleRCB.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(simpleRCB_CFLAGS) $(CFLAGS) -c -o simpleRCB-simpleRCB.obj `if test -f 'simpleRCB.c'; then $(CYGPATH_W) 'simpleRCB.c'; else $(CYGPATH_W) '$(srcdir)/simpleRCB.c'; fi`
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
set x; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) '{ files[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in files) print i; }; }'`; \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(PROGRAMS) all-local
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-noinstPROGRAMS mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am:
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS all all-am all-local check check-am clean \
clean-generic clean-noinstPROGRAMS ctags distclean \
distclean-compile distclean-generic distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
uninstall-am
all-local:
include $(top_builddir)/Makefile.export.zoltan
all-local:
if test -e Makefile.am ; then : ; else cp $(FNAMES) $(builddir); fi
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

View File

@ -0,0 +1,78 @@
##
## a basic makefile to build examples
##
##
## The default type for a Zoltan global ID is "int". This can be changed
## with compile-time flags like:
##
## -DZOLTAN_ID_TYPE_LONG_LONG
##
## See src/include/zoltan_types.h for the valid id type macros. If Zoltan was compiled
## with one of these flags, then these examples need to be compiled with the same flag.
##
ID_TYPE_FLAG=-DZOLTAN_ID_TYPE_LONG_LONG
##
## Location of zoltan library, also location of Zoltan_config.h if
## using the autoconf build
BLD=../../build/src
##
## Location of zoltan "src" directory (for header files)
##
SRC=../../src
# Location of zoltan header files
ZOLTAN_INCLUDE=-I$(SRC)/include
##
## For an autoconf build, the location of Zoltan_config.h
##
ZOLTAN_CONFIG_INCLUDE=-I$(BLD)/include
##
## Headers for zoltan utilities, not often used by applications
## Needed for use of Zoltan_Hash in simpleGRAPH.c
##
ZOLTAN_UTIL_INCLUDE=-I$(SRC)/zz \
-I$(SRC)/par \
-I$(SRC)/order \
-I$(SRC)/tpls \
-I$(SRC)/lb \
-I$(SRC)/params \
-I$(SRC)/Utilities/shared
##
## If Zoltan was built with a third party library, provide the information required
## to link with that library.
##
SCOTCH=/home/lriesen/system/scotch_5.1.10a-32
PARMETIS=/home/lafisk/system/parmetis/ParMetis-3.1
TPL_LIB_DIR=-L$(PARMETIS) -L$(SCOTCH)/lib
TPL_INCLUDE=-I$(PARMETIS) -I$(SCOTCH)/include
TPL_LIBS=-lparmetis -lmetis -lptscotch -lscotch -lptscotcherr -lscotcherr
CC=mpicc
CFLAGS =$(ID_TYPE_FLAG)
EXAMPLE_NAMES= simpleBLOCK simpleRCB simpleGRAPH simplePHG migrateGRAPH simpleHIER problemGRAPH
all: $(EXAMPLE_NAMES)
%: %.c
$(CC) $(CFLAGS) $(TPL_LIB_DIR) \
-I$(BLD)/include $(TPL_INCLUDE) $(ZOLTAN_INCLUDE) $(ZOLTAN_UTIL_INCLUDE) \
-o $@ $< $(BLD)/libzoltan.a $(TPL_LIBS) -lm
clean:
@rm -rf $(EXAMPLE_NAMES)

View File

@ -0,0 +1,6 @@
These examples show how coloring can be done, but
unfortunately the coloring computed is not always valid
(in parallel). The reason is unclear.
TODO: These examples should either be fixed or removed.

View File

@ -0,0 +1,77 @@
# @HEADER
#
########################################################################
#
# Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
# Copyright 2012 Sandia Corporation
#
# Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
# the U.S. Government retains certain rights in this software.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the Corporation nor the names of the
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "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 SANDIA CORPORATION OR THE
# CONTRIBUTORS 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.
#
# Questions? Contact Karen Devine kddevin@sandia.gov
# Erik Boman egboman@sandia.gov
#
########################################################################
#
# @HEADER
CC = mpicc
CFLAGS = -Wall -Wstrict-prototypes -O3 -m64
# CFLAGS = -Wall -Wstrict-prototypes -g -m64 -DZOLTANV31
# CFLAGS = -Wall -Wstrict-prototypes -g -m64 -D_DEBUG
BUILD = linux
ZOLTAN31 = ../../../Zoltan_v3.1_Release
ZOLTAN32 = ../../../Zoltan_v3.2_buggy
INC31 = -I$(ZOLTAN31)/src/include
LIBP31 = $(ZOLTAN31)/src/Obj_$(BUILD)
LIBS31 = -L$(LIBP31) -lzoltan -lm
INC32 = -I$(ZOLTAN32)/src/include
LIBP32 = $(ZOLTAN32)/src/Obj_$(BUILD)
LIBS32 = -L$(LIBP32) -lzoltan -lm
all: zcol zcoldriver zcoldriver-v3.1
zcol : zcol.c $(LIBP31)/libzoltan.a makefile
$(CC) $(CFLAGS) -DZOLTANV31 -o $@ zcol.c $(INC31) $(LIBS31)
zcoldriver-v3.1 : zcoldriver.c $(LIBP31)/libzoltan.a makefile
$(CC) $(CFLAGS) -DZOLTANV31 -o $@ zcoldriver.c $(INC31) $(LIBS31)
zcoldriver : zcoldriver.c $(LIBP32)/libzoltan.a makefile
$(CC) $(CFLAGS) -o $@ zcoldriver.c $(INC32) $(LIBS32)
clean:
rm -f *.o zcoldriver zcoldriver-v3.1 zcol

View File

@ -0,0 +1,689 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "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 SANDIA CORPORATION OR THE
* CONTRIBUTORS 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.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
/***************************************************************
File : zcoldrive.c
Date :
Author : Umit V. Catalyurek
Descr : based on Zoltan simpleGraph example, a driver
for coloring codes that generates 5, 7 or 9
point stencil on the fly and colors them.
***************************************************************/
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "zoltan.h"
/*
#define _DEBUG
#define ZOLTANV31
*/
#define pID(i, j) ((i)*uz->procC + (j))
#define gID(i, j) ((i)*uz->meshC + (j))
#define lID(i, j) (((i)-uz->_sr)*(uz->_ec-uz->_sc) + ((j)-uz->_sc))
#define getR(id) ((id) / uz->meshC)
#define getC(id) ((id) % uz->meshC)
#define pIDfRC(r, c) pID(r/(uz->meshR/uz->procR), c/(uz->meshC/uz->procC))
#define pIDfGID(gid) pIDfRC(getR(gid), getC(gid))
#define lIDfGID(gid) lID(getR(gid), getC(gid))
#define gIDfLID(lid) gID(uz->_sr+(lid/(uz->_ec-uz->_sc)), uz->_sc+(lid%(uz->_ec-uz->_sc)))
static int *xadj=NULL, *adj=NULL, *adjTemp=NULL;
struct edge {
int c, r;
};
struct edge neig[8] = {
{0, -1}, {1, 0}, {0, 1}, {-1, 0},
{-1, -1}, {1, 1}, {1, -1}, {-1, 1}
};
typedef struct {
int stencil; /* for 5, 7 and 9-point, 4, 6 and 8 edges will be created, respectively,
hence stencil value will be 4, 6 or 8 */
int procR, procC; /* proc mesh is R x C */
int meshR, meshC; /* input mesh is R x C */
int _sr, _er, _sc, _ec; /* proc's start (inclusive) and end (exclusive) rows/cols of input mesh */
int myRank, myR, myC;
int numProcs;
double beta;
int numredge;
int *redgeto; /* if beta>0; contains end point of my random edges;
redgeto[lID(i,j)] = -1 means no random edge,
>= 0 points to end point */
} UZData;
extern unsigned int Zoltan_Rand_InRange(unsigned int *, unsigned int);
double u_wseconds(void)
{
struct timeval tp;
gettimeofday(&tp, NULL);
return (double) tp.tv_sec + (double) tp.tv_usec / 1000000.0;
}
static int get_number_of_objects(void *data, int *ierr)
{
UZData *uz = (UZData *) data;
*ierr = ZOLTAN_OK;
return (uz->_er-uz->_sr) * (uz->_ec-uz->_sc);
}
static void get_object_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr)
{
UZData *uz = (UZData *) data;
int i, j, next=0;
/* By setting parameters, I previously gave the Zoltan library
* the length of my global IDs, local IDs, and object weights.
*/
if (sizeGID != 1 || sizeLID !=1 ){ /* My global/local IDs are 1 integer */
*ierr = ZOLTAN_FATAL;
return;
}
for (i=uz->_sr; i<uz->_er; ++i)
for (j=uz->_sc; j<uz->_ec; ++j) {
globalID[next] = gID(i, j); /* application wide global ID */
localID[next] = lID(i, j); /* process specific local ID */
/* sanity check */
if (lID(i, j)!=next) {
fprintf(stderr, "umit something is wrong lID(%d, %d) is %d but next is %d\n", i, j, lID(i, j), next);
exit(1);
}
#if 0
if (wgt_dim>0)
obj_wgts[next] = uz->stencil; /* weight */
#endif
++next;
}
*ierr = ZOLTAN_OK;
}
/* let's keep this in the code for now; may be we'll use it later */
#if 0
/*
**************************************************************
* Prototype: ZOLTAN_NUM_GEOM_FN
* Return the dimension of a vertex, for geometric methods
**************************************************************
*/
static int get_num_geometry(void *data, int *ierr)
{
*ierr = ZOLTAN_OK;
return 2;
}
/*
**************************************************************
* Prototype: ZOLTAN_GEOM_MULTI_FN
* Return the coordinates of my objects (vertices), for
* geometric methods.
**************************************************************
*/
static void get_geometry_list(void *data, int sizeGID, int sizeLID,
int num_obj,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int num_dim, double *geom_vec, int *ierr)
{
UZData *uz = (UZData *) data;
int i, j, next=0;
if ( (sizeGID != 1) || (sizeLID != 1) || (num_dim != 2)){
*ierr = ZOLTAN_FATAL;
return;
}
for (i=uz->_sr; i<uz->_er; ++i)
for (j=uz->_sc; j<uz->_ec; ++j) {
geom_vec[next++] = (double) i;
geom_vec[next++] = (double) j;
}
*ierr = ZOLTAN_OK;
}
#endif
static int filledges(int lid, int *adjID, int *adjProc, UZData *uz)
{
int *nextID = adjID, *ptr;
int *nextProc = adjProc;
int gid = gIDfLID(lid);
int r = getR(gid), r2;
int c = getC(gid), c2, e, j;
/* printf(" %d (%d,%d) : ", id, r, c); */
for (e=0; e<uz->stencil; ++e) {
r2 = r+neig[e].r;
c2 = c+neig[e].c;
if (r2>=0 && r2<uz->meshR &&
c2>=0 && c2<uz->meshC) {
*nextID++ = gID(r2, c2);
if (adjProc)
*nextProc++ = pID(r2/(uz->meshR/uz->procR), c2/(uz->meshC/uz->procC));
/* printf(" %d (%d, %d) [%d] ", *(nextID-1), r2, c2, *(nextProc-1)); */
}
}
if (uz->redgeto && (uz->redgeto[lid]>=0)) {
for (ptr=adjID; ptr<nextID && *ptr!=uz->redgeto[lid]; ++ptr);
if (ptr>=nextID) {
r2 = getR(uz->redgeto[lid]);
c2 = getC(uz->redgeto[lid]);
*nextID++ = uz->redgeto[lid];
if (adjProc)
*nextProc++ = pID(r2/(uz->meshR/uz->procR), c2/(uz->meshC/uz->procC));
/* printf(" %d (%d, %d) [%d] ", *(nextID-1), r2, c2, *(nextProc-1)); */
}
}
if (xadj) {
for (j=xadj[lid]; j<xadj[lid+1]; ++j) {
for (ptr=adjID; ptr<nextID && *ptr!=uz->redgeto[lid]; ++ptr);
if (ptr>=nextID) {
*nextID++ = adj[j];
if (adjProc)
*nextProc++ = pIDfGID(adj[j]);
}
}
}
/* printf("\n"); */
return nextID-adjID;
}
static void get_num_edges_list(void *data, int sizeGID, int sizeLID,
int num_obj,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *numEdges, int *ierr)
{
UZData *uz = (UZData *) data;
int i, lid;
if ( (sizeGID != 1) || (sizeLID != 1)){
*ierr = ZOLTAN_FATAL;
return;
}
for (i=0; i < num_obj ; ++i){
lid = lIDfGID(globalID[i]);
numEdges[i] = filledges(lid, adjTemp, NULL, uz);
}
*ierr = ZOLTAN_OK;
}
static void get_edge_list(void *data, int sizeGID, int sizeLID,
int num_obj, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *num_edges,
ZOLTAN_ID_PTR nborGID, int *nborProc,
int wgt_dim, float *ewgts, int *ierr)
{
UZData *uz = (UZData *) data;
int i;
ZOLTAN_ID_PTR nextID;
int *nextProc;
if ( (sizeGID != 1) || (sizeLID != 1) ||
(wgt_dim != 0)) { /* we are not using edge weights */
*ierr = ZOLTAN_FATAL;
return;
}
nextID = nborGID;
nextProc = nborProc;
/* printf("querying %d vertices\n", num_obj); */
for (i=0; i < num_obj ; ++i) {
int lid = lIDfGID(globalID[i]), ne;
ne = filledges(lid, (int *) nextID, nextProc, uz);
nextID += ne;
nextProc += ne;
}
*ierr = ZOLTAN_OK;
}
void computeProcMesh(UZData *uz)
{
int i = (int) sqrt((double)uz->numProcs+0.1);
while (uz->numProcs % i)
--i;
uz->procR = i;
uz->procC = uz->numProcs / i;
}
void printStats(char *st, int val, int myRank, int nProc)
{
int *allval=NULL, minv, maxv, totv, i;
if (!myRank)
allval = (int *) malloc(sizeof(int)*nProc);
MPI_Gather(&val, 1, MPI_INT, allval, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (!myRank) {
minv = maxv = totv = allval[0];
for (i=1; i<nProc; ++i) {
if (allval[i]>maxv)
maxv = allval[i];
if (allval[i]<minv)
minv = allval[i];
totv += allval[i];
}
printf("%-15s Min: %10d Max: %10d Avg: %10.1lf Tot: %10d\n", st, minv, maxv, (double) totv/(double)nProc, totv);
free(allval);
}
}
#ifdef _DEBUG
void saveColor(char *exename, UZData *uz, int *gid_list, int *color, int ngids)
{
char fname[2048];
FILE *fp;
int i;
sprintf(fname, "%s.%dx%d.%d-point.%d.Of.%dx%d.txt", exename,
uz->meshR, uz->meshC, uz->stencil+1, uz->myRank, uz->procR, uz->procC);
if (!uz->myRank)
printf("Saving the colors in file '%s'\n", fname);
fp = fopen(fname, "w");
for (i=0; i<ngids; ++i)
fprintf(fp, "%d %d\n", gid_list[i], color[i]);
fclose(fp);
}
#endif
int main(int argc, char *argv[])
{
int rc, i, ngids, maxcol, ncolors;
float ver;
struct Zoltan_Struct *zz=NULL;
#ifdef ZOLTANV31
int numGidEntries, numLidEntries;
#else
ZOLTAN_GRAPH_EVAL graph;
#endif
int *color;
ZOLTAN_ID_PTR gid_list;
UZData guz, *uz=&guz;
int msg_tag = 9999;
int nlvtx, next, maxdeg=0;
double times[9]={0.,0.,0.,0.,0.,0.,0.,0.}; /* Used for timing measurements */
double gtimes[9]={0.,0.,0.,0.,0.,0.,0.,0.}; /* Used for timing measurements */
/******************************************************************
** Initialize MPI and Zoltan
******************************************************************/
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &uz->myRank);
MPI_Comm_size(MPI_COMM_WORLD, &uz->numProcs);
MPI_Barrier(MPI_COMM_WORLD);
times[0] = u_wseconds();
rc = Zoltan_Initialize(argc, argv, &ver);
if (rc != ZOLTAN_OK){
fprintf(stderr, "Sorry Zoltan initialize failed...\n");
goto End;
}
zz = Zoltan_Create(MPI_COMM_WORLD);
if (argc<3 && !uz->myRank) {
fprintf(stderr, "usage: %s [meshR] [meshC] [X-point stencil] [procR] [procC] [ws-beta] [<ZoltanParam>=<Val>] ...\n\n", argv[0]);
fprintf(stderr, "ws-beta: is the probablity of adding an edge to a vertex to generate Watts-Strogatz graphs\n");
fprintf(stderr, "Valid values for Stencil are 5, 7 and 9\n");
fprintf(stderr, "Zoltan Coloring Parameters and values are\n");
fprintf(stderr, "\tDISTANCE : 1 or 2\n");
fprintf(stderr, "\tSUPERSTEP_SIZE : suggested >= 100\n");
fprintf(stderr, "\tCOMM_PATTERN : S or A\n");
fprintf(stderr, "\tCOLOR_ORDER : I, B, U\n");
fprintf(stderr, "\tCOLORING_METHOD : F (for now)\n");
fprintf(stderr, "\n");
}
uz->procR = uz->procC = 0;
uz->meshR = uz->meshC = 1024;
uz->stencil = 9;
if (argc>1)
uz->meshR = atoi(argv[1]);
if (argc>2)
uz->meshC = atoi(argv[2]);
if (argc>3)
uz->stencil = atoi(argv[3]);
if (uz->stencil!=5 && uz->stencil!=7 && uz->stencil!=9) {
fprintf(stderr, "\t invalid stencil value. Valid values are 5, 7 and 9. Assumed 9.\n");
uz->stencil = 9;
}
--uz->stencil;
if (argc>4)
uz->procR = atoi(argv[4]);
if (argc>5)
uz->procC = atoi(argv[5]);
if (uz->procR <= 0 || uz->procC <= 0)
computeProcMesh(uz);
if (uz->procR*uz->procC!=uz->numProcs) {
fprintf(stderr, "#Procs=%d but requested %dx%d Proc Mesh Partitioning...\n", uz->numProcs, uz->procR, uz->procC);
goto End;
}
if (argc>6)
uz->beta = atof(argv[6]);
else
uz->beta = 0.0;
/* compute which part of mesh I will compute */
uz->myR = uz->myRank / uz->procC;
uz->myC = uz->myRank % uz->procC;
uz->_sr = uz->myR * (uz->meshR / uz->procR);
uz->_er = (uz->myR+1) * (uz->meshR / uz->procR);
if (uz->_er>uz->meshR)
uz->_er = uz->meshR;
uz->_sc = uz->myC * (uz->meshC / uz->procC);
uz->_ec = (uz->myC+1) * (uz->meshC / uz->procC);
if (uz->_ec>uz->meshC)
uz->_ec = uz->meshC;
if ( (uz->meshR % uz->procR) !=0 || (uz->meshC % uz->procC)!=0) {
printf("Mesh dimensions are not divisible with proc mesh.\nRequested mesh is %dx%d and proc mesh is %d x %d\n", uz->meshR, uz->meshC, uz->procR, uz->procC);
exit(1);
}
nlvtx= (uz->_er-uz->_sr) * (uz->_ec-uz->_sc);
if (uz->myRank==0)
printf("Running %s on %d x %d processor mesh, generating %d-point %d x %d mesh with beta=%.3lf\n", argv[0], uz->procR, uz->procC, uz->stencil+1, uz->meshR, uz->meshC, uz->beta);
times[1] = u_wseconds();
uz->numredge = 0;
uz->redgeto = NULL;
if (uz->beta>0) { /* create random edges for WS graph */
int ngvtx=uz->meshC*uz->meshR, trsh=(int) (uz->beta*100.0);
int ierr=0;
int *edges=NULL, *redges=NULL, *proclist=NULL, nedge;
ZOLTAN_COMM_OBJ *plan;
uz->redgeto = (int *) malloc(nlvtx*sizeof(int));
for (i=0; i<nlvtx; ++i) {
int rv = Zoltan_Rand_InRange(NULL, 100);
if ( rv < trsh) {
if ((uz->redgeto[i] = Zoltan_Rand_InRange(NULL, ngvtx))==gIDfLID(i)) /* is it a self edge */
uz->redgeto[i] = -1;
else
++uz->numredge;
} else
uz->redgeto[i] = -1;
}
edges = (int *) malloc(sizeof(int)*2*uz->numredge);
proclist = (int *) malloc(sizeof(int)*uz->numredge);
next = 0;
for (i=0; i<nlvtx; ++i)
if (uz->redgeto[i]>0) {
edges[2*next] = uz->redgeto[i];
edges[2*next+1] = gIDfLID(i);
proclist[next] = pIDfGID(uz->redgeto[i]);
++next;
}
ierr = Zoltan_Comm_Create(&plan, uz->numredge, proclist, MPI_COMM_WORLD,
msg_tag, &nedge);
redges = (int *) malloc(sizeof(int)*2*nedge);
--msg_tag;
ierr |= Zoltan_Comm_Do(plan, msg_tag, (char *) edges, 2*sizeof(int),
(char *) redges);
ierr |= Zoltan_Comm_Destroy(&plan);
free(proclist);
free(edges);
if (ierr) {
printf("error while communicating edges!\n");
exit(1);
}
xadj = (int *) calloc(1+nlvtx, sizeof(int));
adj = (int *) malloc(sizeof(int)*nedge);
for (i=0; i<nedge; ++i) {
if (redges[2*i] < gID(uz->_sr, uz->_sc) || redges[2*i] >= gID(uz->_er, uz->_ec)) {
printf("[%d/%d] received gid=%d doesn't blong to processor range [%d, %d) should go to proc %d\n", uz->myRank, uz->numProcs, redges[2*i], gID(uz->_sr, uz->_sc), gID(uz->_er, uz->_ec), pIDfGID(redges[2*i]));
}
++xadj[lIDfGID(redges[2*i])];
}
xadj[nlvtx] = nedge;
maxdeg = xadj[0];
for (i=1; i<nlvtx; ++i) {
maxdeg = xadj[i]>maxdeg ? xadj[i] : maxdeg;
xadj[i] += xadj[i-1];
}
for (i=0; i<nedge; ++i) {
int u = lIDfGID(redges[2*i]);
int v = redges[2*i+1];
adj[--xadj[u]] = v;
}
free(redges);
}
maxdeg += uz->stencil+1;
adjTemp = (int *) malloc(sizeof(int)*2*maxdeg);
times[2] = u_wseconds();
/*
printf("My rank %d/%d at proc-mesh loc (%d, %d) generating [%d, %d) x [%d, %d) + %d random edges TotEdge=%d\n", uz->myRank, uz->numProcs, uz->myR, uz->myC, uz->_sr, uz->_er, uz->_sc, uz->_ec, uz->numredge, xadj[nlvtx]); */
printStats("Number of Vertices ", nlvtx, uz->myRank, uz->numProcs);
if (xadj)
printStats("Number of Rand Edges", xadj[nlvtx], uz->myRank, uz->numProcs);
/* General parameters */
#ifndef ZOLTANV31
Zoltan_Set_Param(zz, "GRAPH_BUILD_TYPE", "FAST_NO_DUP");
#endif
/* General parameters */
Zoltan_Set_Param(zz, "DEBUG_LEVEL", "3");
Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");
Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0");
/* coloring parameters */
Zoltan_Set_Param(zz, "SUPERSTEP_SIZE", "500"); /* let's make S=500 default */
for (i=7; i<argc; ++i) {
char param[256], *eq;
if (!uz->myRank)
printf("processing argv[%d]='%s'\n", i, argv[i]);
strncpy(param, argv[i], sizeof(param));
eq = strchr(param, '=');
if (!eq) {
fprintf(stderr, "invalid argument '%s', Zoltan Paramters should be in the format <ZoltanParam>=<Val>\n", param);
goto End;
}
*eq = 0;
Zoltan_Set_Param(zz, param, eq+1);
}
#if 0
/* Graph parameters */
Zoltan_Set_Param(zz, "CHECK_GRAPH", "2");
#endif
/* set call backs */
Zoltan_Set_Num_Obj_Fn(zz, get_number_of_objects, uz);
Zoltan_Set_Obj_List_Fn(zz, get_object_list, uz);
Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, uz);
Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, uz);
#if 0
#ifndef ZOLTANV31
Zoltan_LB_Eval_Graph(zz, 0, &graph);
if (!uz->myRank) {
printf("EdgeCut Min=%8.0f Max=%8.0f Sum=%8.0f\n", graph.cuts[EVAL_GLOBAL_MIN], graph.cuts[EVAL_GLOBAL_MAX], graph.cuts[EVAL_GLOBAL_SUM]);
printf("#Vertices Min=%8.0f Max=%8.0f Sum=%8.0f imbal=%.2f\n", graph.nobj[EVAL_GLOBAL_MIN], graph.nobj[EVAL_GLOBAL_MAX], graph.nobj[EVAL_GLOBAL_SUM], graph.obj_imbalance);
}
#endif
#endif
/* now color */
ngids = get_number_of_objects(uz, &rc);
gid_list = (ZOLTAN_ID_PTR) malloc(sizeof(ZOLTAN_ID_TYPE) * ngids);
#ifndef ZOLTANV31
next = 0;
for (i=uz->_sr; i<uz->_er; ++i) {
int j;
for (j=uz->_sc; j<uz->_ec; ++j) {
gid_list[next++] = i*uz->meshC + j;
}
}
#endif
color = (int *) malloc(sizeof(int) * ngids);
MPI_Barrier(MPI_COMM_WORLD);
times[3] = u_wseconds();
#ifdef ZOLTANV31
rc = Zoltan_Color(zz, /* input (all remaining fields are output) */
&numGidEntries, /* Number of integers used for a global ID */
&numLidEntries, /* Number of integers used for a local ID */
ngids, /* #objects to color in this proc */
gid_list, /* global ids of colored vertices */
NULL, /* we ignore local ids */
color); /* result color */
#else
rc = Zoltan_Color(zz, /* input (all remaining fields are output) */
1, /* Number of integers used for a global ID */
ngids, /* #objects to color in this proc */
gid_list, /* global ids of colored vertices */
color); /* result color */
#endif
MPI_Barrier(MPI_COMM_WORLD);
times[4] = u_wseconds();
MPI_Reduce(times, gtimes, 5, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD);
if (rc != ZOLTAN_OK)
fprintf(stderr, "Zoltan_Color failed with return code %d...\n", rc);
for (maxcol=i=0; i<ngids; ++i)
if (color[i] > maxcol)
maxcol = color[i];
MPI_Reduce(&maxcol, &ncolors, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
if (uz->myRank==0) {
struct rusage usage;
printf("%s setup Proc-0: %8.2lf Max: %8.2lf\n", argv[0], times[1]-times[0], gtimes[1]-gtimes[0]);
printf("%s gen rand edges Proc-0: %8.2lf Max: %8.2lf\n", argv[0], times[2]-times[1], gtimes[2]-gtimes[1]);
printf("%s set gids Proc-0: %8.2lf Max: %8.2lf\n", argv[0], times[3]-times[2], gtimes[3]-gtimes[2]);
printf("%s Zoltan_Color call Proc-0: %8.2lf Max: %8.2lf\n", argv[0], times[4]-times[3], gtimes[4]-gtimes[3]);
printf("%s Coloring Time : %.2lf # Colors used : %d\n", argv[0], gtimes[4]-gtimes[0], ncolors);
getrusage(RUSAGE_SELF, &usage);
printf("%s maxrss=%ld minflt=%ld majflt=%ld nswap=%ld\n", argv[0], usage.ru_maxrss, usage.ru_minflt, usage.ru_majflt, usage.ru_nswap);
}
#ifdef _DEBUG
saveColor(argv[0], uz, (int *) gid_list, color, ngids);
#endif
/******************************************************************
** Clean up
******************************************************************/
if (gid_list)
free(gid_list);
if (color)
free(color);
if (xadj)
free(xadj);
if (adj)
free(adj);
if (adjTemp)
free(adjTemp);
if (uz->redgeto)
free(uz->redgeto);
End:
Zoltan_Destroy(&zz);
MPI_Finalize();
return 0;
}

View File

@ -0,0 +1,602 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "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 SANDIA CORPORATION OR THE
* CONTRIBUTORS 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.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
/***************************************************************
File : zcoldrive.c
Date :
Author : Umit V. Catalyurek
Descr : based on Zoltan simpleGraph example, a driver
for coloring codes that generates 5, 7 or 9
point stencil on the fly and colors them.
***************************************************************/
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "zoltan.h"
/*
#define _DEBUG
#define ZOLTANV31
*/
#define pID(i, j) ((i)*uz->procC + (j))
#define gID(i, j) ((i)*uz->meshC + (j))
#define lID(i, j) (((i)-uz->_sr)*(uz->_ec-uz->_sc) + ((j)-uz->_sc))
#define getR(id) ((id) / uz->meshC)
#define getC(id) ((id) % uz->meshC)
struct edge {
int c, r;
};
struct edge neig[8] = {
{0, -1}, {1, 0}, {0, 1}, {-1, 0},
{-1, -1}, {1, 1}, {1, -1}, {-1, 1}
};
typedef struct {
int stencil; /* for 5, 7 and 9-point, 4, 6 and 8 edges will be created, respectively,
hence stencil value will be 4, 6 or 8 */
int procR, procC; /* proc mesh is R x C */
int meshR, meshC; /* input mesh is R x C */
int _sr, _er, _sc, _ec; /* proc's start (inclusive) and end (exclusive) rows/cols of input mesh */
int myRank, myR, myC;
int numProcs;
double beta;
int numredge;
int *redgeto; /* if beta>0; contains end point of my random edges;
redgeto[lID(i,j)] = -1 means no random edge,
>= 0 points to end point */
} UZData;
extern unsigned int Zoltan_Rand_InRange(unsigned int *, unsigned int);
double u_wseconds(void)
{
struct timeval tp;
gettimeofday(&tp, NULL);
return (double) tp.tv_sec + (double) tp.tv_usec / 1000000.0;
}
static int get_number_of_objects(void *data, int *ierr)
{
UZData *uz = (UZData *) data;
*ierr = ZOLTAN_OK;
return (uz->_er-uz->_sr) * (uz->_ec-uz->_sc);
}
static void get_object_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr)
{
UZData *uz = (UZData *) data;
int i, j, next=0;
/* By setting parameters, I previously gave the Zoltan library
* the length of my global IDs, local IDs, and object weights.
*/
if (sizeGID != 1 || sizeLID !=1 ){ /* My global/local IDs are 1 integer */
*ierr = ZOLTAN_FATAL;
return;
}
for (i=uz->_sr; i<uz->_er; ++i)
for (j=uz->_sc; j<uz->_ec; ++j) {
globalID[next] = gID(i, j); /* application wide global ID */
localID[next] = lID(i, j); /* process specific local ID */
/* sanity check */
if (lID(i, j)!=next) {
fprintf(stderr, "umit something is wrong lID(%d, %d) is %d but next is %d\n", i, j, lID(i, j), next);
exit(1);
}
#if 0
if (wgt_dim>0)
obj_wgts[next] = uz->stencil; /* weight */
#endif
++next;
}
*ierr = ZOLTAN_OK;
}
/* let's keep this in the code for now; may be we'll use it later */
#if 0
/*
**************************************************************
* Prototype: ZOLTAN_NUM_GEOM_FN
* Return the dimension of a vertex, for geometric methods
**************************************************************
*/
static int get_num_geometry(void *data, int *ierr)
{
*ierr = ZOLTAN_OK;
return 2;
}
/*
**************************************************************
* Prototype: ZOLTAN_GEOM_MULTI_FN
* Return the coordinates of my objects (vertices), for
* geometric methods.
**************************************************************
*/
static void get_geometry_list(void *data, int sizeGID, int sizeLID,
int num_obj,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int num_dim, double *geom_vec, int *ierr)
{
UZData *uz = (UZData *) data;
int i, j, next=0;
if ( (sizeGID != 1) || (sizeLID != 1) || (num_dim != 2)){
*ierr = ZOLTAN_FATAL;
return;
}
for (i=uz->_sr; i<uz->_er; ++i)
for (j=uz->_sc; j<uz->_ec; ++j) {
geom_vec[next++] = (double) i;
geom_vec[next++] = (double) j;
}
*ierr = ZOLTAN_OK;
}
#endif
/*
**************************************************************
* Prototype: ZOLTAN_NUM_EDGES_MULTI_FN
* Return the number of edges for each vertex in the ID lists.
* For graph methods.
**************************************************************
*/
static void get_num_edges_list(void *data, int sizeGID, int sizeLID,
int num_obj,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *numEdges, int *ierr)
{
UZData *uz = (UZData *) data;
int i, id, r, c, r2, c2, edgecnt, e;
if ( (sizeGID != 1) || (sizeLID != 1)){
*ierr = ZOLTAN_FATAL;
return;
}
for (i=0; i < num_obj ; ++i){
id = globalID[i];
r = getR(id);
c = getC(id);
if (r==0 || c==0 || r==(uz->meshR-1) || c==(uz->meshC-1)) {
/* we can probably do much smarter thing bu since
we're not going to time graph generation time,
simply run through over edges and see how many edges
it will have. */
edgecnt = 0;
for (e=0; e<uz->stencil; ++e) {
r2 = r+neig[e].r;
c2 = c+neig[e].c;
if (r2>=0 && r2<uz->meshR &&
c2>=0 && c2<uz->meshC)
++edgecnt;
}
numEdges[i] = edgecnt;
} else /* internal vertices always have all the edges */
numEdges[i] = uz->stencil;
if (uz->redgeto && (uz->redgeto[i]>=0))
++numEdges[i];
}
*ierr = ZOLTAN_OK;
}
/*
**************************************************************
* Prototype: ZOLTAN_EDGE_LIST_MULTI_FN
* For every vertex in the ID list, return a list of all its
* adjacent vertices, and the processes on which they reside.
* Also include the edge weights if any.
* For graph methods.
**************************************************************
*/
static void get_edge_list(void *data, int sizeGID, int sizeLID,
int num_obj, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *num_edges,
ZOLTAN_ID_PTR nborGID, int *nborProc,
int wgt_dim, float *ewgts, int *ierr)
{
UZData *uz = (UZData *) data;
int i, id, r, c, r2, c2, e;
ZOLTAN_ID_PTR nextID;
int *nextProc;
if ( (sizeGID != 1) || (sizeLID != 1) ||
(wgt_dim != 0)){ /* we are not using edge weights */
*ierr = ZOLTAN_FATAL;
return;
}
nextID = nborGID;
nextProc = nborProc;
/* printf("querying %d vertices\n", num_obj); */
for (i=0; i < num_obj ; ++i) {
id = globalID[i];
r = getR(id);
c = getC(id);
/* printf(" %d (%d,%d) : ", id, r, c); */
for (e=0; e<uz->stencil; ++e) {
r2 = r+neig[e].r;
c2 = c+neig[e].c;
if (r2>=0 && r2<uz->meshR &&
c2>=0 && c2<uz->meshC) {
*nextID++ = gID(r2, c2);
*nextProc++ = pID(r2/(uz->meshR/uz->procR), c2/(uz->meshC/uz->procC));
/* printf(" %d (%d, %d) [%d] ", *(nextID-1), r2, c2, *(nextProc-1)); */
}
}
if (uz->redgeto && (uz->redgeto[i]>=0)) {
r2 = getR(uz->redgeto[i]);
c2 = getC(uz->redgeto[i]);
*nextID++ = gID(r2, c2);
*nextProc++ = pID(r2/(uz->meshR/uz->procR), c2/(uz->meshC/uz->procC));
/* printf(" %d (%d, %d) [%d] ", *(nextID-1), r2, c2, *(nextProc-1)); */
}
/* printf("\n"); */
*ierr = ZOLTAN_OK;
}
}
void computeProcMesh(UZData *uz)
{
int i = (int) sqrt((double)uz->numProcs+0.1);
while (uz->numProcs % i)
--i;
uz->procR = i;
uz->procC = uz->numProcs / i;
}
#ifdef _DEBUG
void saveColor(char *exename, UZData *uz, int *gid_list, int *color, int ngids)
{
char fname[2048];
FILE *fp;
int i;
sprintf(fname, "%s.%dx%d.%d-point.%d.Of.%dx%d.txt", exename,
uz->meshR, uz->meshC, uz->stencil+1, uz->myRank, uz->procR, uz->procC);
if (!uz->myRank)
printf("Saving the colors in file '%s'\n", fname);
fp = fopen(fname, "w");
for (i=0; i<ngids; ++i)
fprintf(fp, "%d %d\n", gid_list[i], color[i]);
fclose(fp);
}
#endif
int main(int argc, char *argv[])
{
int rc, i, ngids, maxcol, ncolors;
float ver;
struct Zoltan_Struct *zz=NULL;
#ifdef ZOLTANV31
int numGidEntries, numLidEntries;
#else
ZOLTAN_GRAPH_EVAL graph;
int next;
#endif
int *color;
ZOLTAN_ID_PTR gid_list;
UZData uz;
double times[9]={0.,0.,0.,0.,0.,0.,0.,0.}; /* Used for timing measurements */
double gtimes[9]={0.,0.,0.,0.,0.,0.,0.,0.}; /* Used for timing measurements */
/******************************************************************
** Initialize MPI and Zoltan
******************************************************************/
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &uz.myRank);
MPI_Comm_size(MPI_COMM_WORLD, &uz.numProcs);
MPI_Barrier(MPI_COMM_WORLD);
times[0] = u_wseconds();
rc = Zoltan_Initialize(argc, argv, &ver);
if (rc != ZOLTAN_OK){
fprintf(stderr, "Sorry Zoltan initialize failed...\n");
goto End;
}
zz = Zoltan_Create(MPI_COMM_WORLD);
if (argc<3 && !uz.myRank) {
fprintf(stderr, "usage: %s [meshR] [meshC] [X-point stencil] [procR] [procC] [ws-beta] [<ZoltanParam>=<Val>] ...\n\n", argv[0]);
fprintf(stderr, "ws-beta: is the probablity of adding an edge to a vertex to generate Watts-Strogatz graphs\n");
fprintf(stderr, "Valid values for Stencil are 5, 7 and 9\n");
fprintf(stderr, "Zoltan Coloring Parameters and values are\n");
fprintf(stderr, "\tDISTANCE : 1 or 2\n");
fprintf(stderr, "\tSUPERSTEP_SIZE : suggested >= 100\n");
fprintf(stderr, "\tCOMM_PATTERN : S or A\n");
fprintf(stderr, "\tCOLOR_ORDER : I, B, U\n");
fprintf(stderr, "\tCOLORING_METHOD : F (for now)\n");
fprintf(stderr, "\n");
}
uz.procR = uz.procC = 0;
uz.meshR = uz.meshC = 1024;
uz.stencil = 9;
if (argc>1)
uz.meshR = atoi(argv[1]);
if (argc>2)
uz.meshC = atoi(argv[2]);
if (argc>3)
uz.stencil = atoi(argv[3]);
if (uz.stencil!=5 && uz.stencil!=7 && uz.stencil!=9) {
fprintf(stderr, "\t invalid stencil value. Valid values are 5, 7 and 9. Assumed 9.\n");
uz.stencil = 9;
}
--uz.stencil;
if (argc>4)
uz.procR = atoi(argv[4]);
if (argc>5)
uz.procC = atoi(argv[5]);
if (uz.procR <= 0 || uz.procC <= 0)
computeProcMesh(&uz);
if (uz.procR*uz.procC!=uz.numProcs) {
fprintf(stderr, "#Procs=%d but requested %dx%d Proc Mesh Partitioning...\n", uz.numProcs, uz.procR, uz.procC);
goto End;
}
if (argc>6)
uz.beta = atof(argv[6]);
else
uz.beta = 0.0;
/* compute which part of mesh I will compute */
uz.myR = uz.myRank / uz.procC;
uz.myC = uz.myRank % uz.procC;
uz._sr = uz.myR * (uz.meshR / uz.procR);
uz._er = (uz.myR+1) * (uz.meshR / uz.procR);
if (uz._er>uz.meshR)
uz._er = uz.meshR;
uz._sc = uz.myC * (uz.meshC / uz.procC);
uz._ec = (uz.myC+1) * (uz.meshC / uz.procC);
if (uz._ec>uz.meshC)
uz._ec = uz.meshC;
if (uz.myRank==0)
printf("Running %s on %d x %d processor mesh, generating %d-point %d x %d mesh with beta=%.3lf\n", argv[0], uz.procR, uz.procC, uz.stencil+1, uz.meshR, uz.meshC, uz.beta);
times[1] = u_wseconds();
uz.numredge = 0;
uz.redgeto = NULL;
if (uz.beta>0) { /* create random edges for WS graph */
int nlvtx= (uz._er-uz._sr) * (uz._ec-uz._sc), ngvtx=uz.meshC*uz.meshR, trsh=(int) (uz.beta*100.0);
uz.redgeto = (int *) malloc(nlvtx*sizeof(int));
for (i=0; i<nlvtx; ++i) {
int rv = Zoltan_Rand_InRange(NULL, 100);
if ( rv < trsh) {
uz.redgeto[i] = Zoltan_Rand_InRange(NULL, ngvtx);
++uz.numredge;
} else
uz.redgeto[i] = -1;
}
}
times[2] = u_wseconds();
/* printf("My rank %d/%d at proc-mesh loc (%d, %d) generating [%d, %d) x [%d, %d) + %d random edges\n", uz.myRank, uz.numProcs, uz.myR, uz.myC, uz._sr, uz._er, uz._sc, uz._ec, uz.numredge); */
/* General parameters */
#ifndef ZOLTANV31
if (uz.numredge) {
#if 0
Zoltan_Set_Param(zz, "GRAPH_SYMMETRIZE", "TRANSPOSE");
Zoltan_Set_Param(zz, "GRAPH_SYM_WEIGHT", "MAX");
#endif
Zoltan_Set_Param(zz, "GRAPH_BUILD_TYPE", "FAST");
} else
Zoltan_Set_Param(zz, "GRAPH_BUILD_TYPE", "FAST_NO_DUP");
#endif
Zoltan_Set_Param(zz, "DEBUG_LEVEL", "3");
Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");
Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0");
/* coloring parameters */
Zoltan_Set_Param(zz, "SUPERSTEP_SIZE", "500"); /* let's make S=500 default */
for (i=7; i<argc; ++i) {
char param[256], *eq;
if (!uz.myRank)
printf("processing argv[%d]='%s'\n", i, argv[i]);
strncpy(param, argv[i], sizeof(param));
eq = strchr(param, '=');
if (!eq) {
fprintf(stderr, "invalid argument '%s', Zoltan Paramters should be in the format <ZoltanParam>=<Val>\n", param);
goto End;
}
*eq = 0;
Zoltan_Set_Param(zz, param, eq+1);
}
#if 0
/* Graph parameters */
Zoltan_Set_Param(zz, "CHECK_GRAPH", "2");
#endif
/* set call backs */
Zoltan_Set_Num_Obj_Fn(zz, get_number_of_objects, &uz);
Zoltan_Set_Obj_List_Fn(zz, get_object_list, &uz);
Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, &uz);
Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, &uz);
#if 0
#ifndef ZOLTANV31
Zoltan_LB_Eval_Graph(zz, 0, &graph);
if (!uz.myRank) {
printf("EdgeCut Min=%8.0f Max=%8.0f Sum=%8.0f\n", graph.cuts[EVAL_GLOBAL_MIN], graph.cuts[EVAL_GLOBAL_MAX], graph.cuts[EVAL_GLOBAL_SUM]);
printf("#Vertices Min=%8.0f Max=%8.0f Sum=%8.0f imbal=%.2f\n", graph.nobj[EVAL_GLOBAL_MIN], graph.nobj[EVAL_GLOBAL_MAX], graph.nobj[EVAL_GLOBAL_SUM], graph.obj_imbalance);
}
#endif
#endif
/* now color */
ngids = get_number_of_objects(&uz, &rc);
gid_list = (ZOLTAN_ID_PTR) malloc(sizeof(ZOLTAN_ID_TYPE) * ngids);
#ifndef ZOLTANV31
next = 0;
for (i=uz._sr; i<uz._er; ++i) {
int j;
for (j=uz._sc; j<uz._ec; ++j) {
gid_list[next++] = i*uz.meshC + j;
}
}
#endif
color = (int *) malloc(sizeof(int) * ngids);
MPI_Barrier(MPI_COMM_WORLD);
times[3] = u_wseconds();
#ifdef ZOLTANV31
rc = Zoltan_Color(zz, /* input (all remaining fields are output) */
&numGidEntries, /* Number of integers used for a global ID */
&numLidEntries, /* Number of integers used for a local ID */
ngids, /* #objects to color in this proc */
gid_list, /* global ids of colored vertices */
NULL, /* we ignore local ids */
color); /* result color */
#else
rc = Zoltan_Color(zz, /* input (all remaining fields are output) */
1, /* Number of integers used for a global ID */
ngids, /* #objects to color in this proc */
gid_list, /* global ids of colored vertices */
color); /* result color */
#endif
MPI_Barrier(MPI_COMM_WORLD);
times[4] = u_wseconds();
MPI_Reduce(times, gtimes, 5, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD);
if (rc != ZOLTAN_OK)
fprintf(stderr, "Zoltan_Color failed with return code %d...\n", rc);
for (maxcol=i=0; i<ngids; ++i)
if (color[i] > maxcol)
maxcol = color[i];
MPI_Reduce(&maxcol, &ncolors, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
if (uz.myRank==0) {
struct rusage usage;
printf("%s setup Proc-0: %8.2lf Max: %8.2lf\n", argv[0], times[1]-times[0], gtimes[1]-gtimes[0]);
printf("%s gen rand edges Proc-0: %8.2lf Max: %8.2lf\n", argv[0], times[2]-times[1], gtimes[2]-gtimes[1]);
printf("%s set gids Proc-0: %8.2lf Max: %8.2lf\n", argv[0], times[3]-times[2], gtimes[3]-gtimes[2]);
printf("%s Zoltan_Color call Proc-0: %8.2lf Max: %8.2lf\n", argv[0], times[4]-times[3], gtimes[4]-gtimes[3]);
printf("%s Coloring Time : %.2lf # Colors used : %d\n", argv[0], gtimes[4]-gtimes[0], ncolors);
getrusage(RUSAGE_SELF, &usage);
printf("%s maxrss=%ld minflt=%ld majflt=%ld nswap=%ld\n", argv[0], usage.ru_maxrss, usage.ru_minflt, usage.ru_majflt, usage.ru_nswap);
}
#ifdef _DEBUG
saveColor(argv[0], &uz, (int *) gid_list, color, ngids);
#endif
/******************************************************************
** Clean up
******************************************************************/
if (gid_list)
free(gid_list);
if (color)
free(color);
if (uz.redgeto)
free(uz.redgeto);
End:
Zoltan_Destroy(&zz);
MPI_Finalize();
return 0;
}

54
thirdParty/Zoltan/example/C/graph.txt vendored Normal file
View File

@ -0,0 +1,54 @@
##
## This simple structure is used by many of the nightly Zoltan tests.
## It can be interpreted as a mesh, a graph, a hypergraph, or simply
## as 25 objects to be partitioned.
##
## 21----22----23----24---25
## | | | | |
## 16----17----18----19---20
## | | | | |
## 11----12----13----14---15
## | | | | |
## 6-----7-----8-----9----10
## | | | | |
## 1-----2-----3-----4----5
##
## Regarded as a graph, there are 25 vertices with connectivity
## described by the arcs in the diagram.
##
## Number of vertices:
25
## Number of vertex neighbors:
80
## Here we list for each vertex, its global ID, its number of neighbors, and
## the global ID of each of its neighbors.
##
1 2 2 6
2 3 1 3 7
3 3 2 8 4
4 3 3 9 5
5 2 4 10
6 3 1 7 11
7 4 6 2 8 12
8 4 7 3 9 13
9 4 8 4 10 14
10 3 9 5 15
11 3 6 12 16
12 4 11 7 13 17
13 4 12 8 14 18
14 4 13 9 15 19
15 3 14 10 20
16 3 11 17 21
17 4 16 12 18 22
18 4 17 13 19 23
19 4 18 14 20 24
20 3 19 15 25
21 2 16 22
22 3 21 17 23
23 3 22 18 24
24 3 23 19 25
25 2 24 20

View File

@ -0,0 +1,86 @@
##
## This simple structure is used by many of the nightly Zoltan tests.
## It can be interpreted as a mesh, a graph, a hypergraph, or simply
## as 25 objects to be partitioned.
##
## 21----22----23----24---25
## | | | | |
## 16----17----18----19---20
## | | | | |
## 11----12----13----14---15
## | | | | |
## 6-----7-----8-----9----10
## | | | | |
## 1-----2-----3-----4----5
##
## Regarded as a hypergraph, we associate each of the 25 objects with a
## hyperedge. The hyperedge is composed of the object and its neighbors
## in the above structure. For example, hyperedge 1 contains vertices
## 1, 2 and 6. Hyperedge 13 contains vertices 13, 8, 12, 14 and 18.
##
## Number of vertices:
25
## Here we list the global ID of each vertex.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
## Number of hyperedges:
25
## Sum of the number of vertices in each hyperedge
105
## Here we list for each hyperedge, its global ID, the number of vertices it links,
## and the global ID of each vertex in the hyperedge.
1 3 1 2 6
2 4 1 2 3 7
3 4 2 3 4 8
4 4 3 4 5 9
5 3 4 5 10
6 4 1 6 7 11
7 5 2 6 7 8 12
8 5 3 7 8 9 13
9 5 4 8 9 10 14
10 4 5 9 10 15
11 4 6 11 12 16
12 5 7 11 12 13 17
13 5 8 12 13 14 18
14 5 9 13 14 15 19
15 4 10 14 15 20
16 4 11 16 17 21
17 5 12 16 17 18 22
18 5 13 17 18 19 23
19 5 14 18 19 20 24
20 4 15 19 20 25
21 3 16 21 22
22 4 17 21 22 23
23 4 18 22 23 24
24 4 19 23 24 25
25 3 20 24 25

49
thirdParty/Zoltan/example/C/mesh.txt vendored Normal file
View File

@ -0,0 +1,49 @@
##
## This simple structure is used by many of the nightly Zoltan tests.
## It can be interpreted as a mesh, a graph, a hypergraph, or simply
## as 25 objects to be partitioned.
##
## 21----22----23----24---25
## | | | | |
## 16----17----18----19---20
## | | | | |
## 11----12----13----14---15
## | | | | |
## 6-----7-----8-----9----10
## | | | | |
## 1-----2-----3-----4----5
##
## Regarded as a mesh, vertex 1 is at location (0,0)
## and vertex 25 is at location (4,4);
##
## Number of vertices:
25
## Here we list for each vertex, its global ID and location.
1 0 0
2 1 0
3 2 0
4 3 0
5 4 0
6 0 1
7 1 1
8 2 1
9 3 1
10 4 1
11 0 2
12 1 2
13 2 2
14 3 2
15 4 2
16 0 3
17 1 3
18 2 3
19 3 3
20 4 3
21 0 4
22 1 4
23 2 4
24 3 4
25 4 4

1026
thirdParty/Zoltan/example/C/migrateGRAPH.c vendored Normal file

File diff suppressed because it is too large Load Diff

48
thirdParty/Zoltan/example/C/objects.txt vendored Normal file
View File

@ -0,0 +1,48 @@
##
## This simple structure is used by many of the nightly Zoltan tests.
## It can be interpreted as a mesh, a graph, a hypergraph, or simply
## as 25 objects to be partitioned.
##
## 21----22----23----24---25
## | | | | |
## 16----17----18----19---20
## | | | | |
## 11----12----13----14---15
## | | | | |
## 6-----7-----8-----9----10
## | | | | |
## 1-----2-----3-----4----5
##
## Regarded as a collection of objects, we have objects 1 through 25.
##
## Number of objects:
25
## Global ID for each object
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

View File

@ -0,0 +1,795 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "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 SANDIA CORPORATION OR THE
* CONTRIBUTORS 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.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
/**************************************************************
* Basic example of using Zoltan to partition a graph.
***************************************************************/
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "zoltan.h"
/* Name of file containing graph to be partitioned */
static char *global_fname="graph.txt";
/* Structure to hold graph data */
typedef struct{
int numMyVertices; /* total vertices in in my partition */
int numAllNbors; /* total number of neighbors of my vertices */
ZOLTAN_ID_TYPE *vertexGID; /* global ID of each of my vertices */
int *nborIndex; /* nborIndex[i] is location of start of neighbors for vertex i */
ZOLTAN_ID_TYPE *nborGID; /* nborGIDs[nborIndex[i]] is first neighbor of vertex i */
int *nborProc; /* process owning each nbor in nborGID */
} GRAPH_DATA;
/* Application defined query functions */
static int get_number_of_vertices(void *data, int *ierr);
static void get_vertex_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr);
static void get_num_edges_list(void *data, int sizeGID, int sizeLID,
int num_obj,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *numEdges, int *ierr);
static void get_edge_list(void *data, int sizeGID, int sizeLID,
int num_obj, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *num_edges,
ZOLTAN_ID_PTR nborGID, int *nborProc,
int wgt_dim, float *ewgts, int *ierr);
/* Functions to read graph in from file, distribute it, view it, handle errors */
static int get_next_line(FILE *fp, char *buf, int bufsize);
static int get_line_ints(char *buf, int bufsize, int *vals);
static void input_file_error(int numProcs, int tag, int startProc);
static void showGraphPartitions(int myProc, int numIDs, ZOLTAN_ID_TYPE *GIDs, int *parts, int nparts);
static void read_input_file(int myRank, int numProcs, char *fname, GRAPH_DATA *myData);
static unsigned int simple_hash(unsigned int *key, unsigned int n);
int main(int argc, char *argv[])
{
int i, rc;
float ver;
struct Zoltan_Struct *zz;
int changes, numGidEntries, numLidEntries, numImport, numExport;
int myRank, numProcs;
ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
int *importProcs, *importToPart, *exportProcs, *exportToPart;
int *parts;
FILE *fp;
GRAPH_DATA myGraph;
/******************************************************************
** Initialize MPI and Zoltan
******************************************************************/
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
rc = Zoltan_Initialize(argc, argv, &ver);
if (rc != ZOLTAN_OK){
printf("sorry...\n");
MPI_Finalize();
exit(0);
}
/******************************************************************
** Read graph from input file and distribute it
******************************************************************/
fp = fopen(global_fname, "r");
if (!fp){
if (myRank == 0) fprintf(stderr,"ERROR: Can not open %s\n",global_fname);
MPI_Finalize();
exit(1);
}
fclose(fp);
read_input_file(myRank, numProcs, global_fname, &myGraph);
/******************************************************************
** Create a Zoltan library structure for this instance of load
** balancing. Set the parameters and query functions that will
** govern the library's calculation. See the Zoltan User's
** Guide for the definition of these and many other parameters.
******************************************************************/
zz = Zoltan_Create(MPI_COMM_WORLD);
/* General parameters */
/*
Zoltan_Set_Param(zz, "DEBUG_LEVEL", "0");
Zoltan_Set_Param(zz, "LB_METHOD", "GRAPH");
Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");
Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0");
Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL");
*/
Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");
Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
Zoltan_Set_Param(zz,"LB_METHOD","GRAPH");
#ifdef HAVE_PARMETIS
Zoltan_Set_Param(zz,"GRAPH_PACKAGE","PARMETIS");
Zoltan_Set_Param(zz,"PARMETIS_METHOD","PARTKWAY");
#else
#ifdef HAVE_SCOTCH
Zoltan_Set_Param(zz,"GRAPH_PACKAGE","SCOTCH");
#endif
#endif
Zoltan_Set_Param(zz,"EDGE_WEIGHT_DIM","1");
Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0");
Zoltan_Set_Param(zz, "LB_APPROACH","PARTITION");
/* Graph parameters */
Zoltan_Set_Param(zz, "CHECK_GRAPH", "2");
Zoltan_Set_Param(zz, "PHG_EDGE_SIZE_THRESHOLD", ".35"); /* 0-remove all, 1-remove none */
/* Query functions - defined in simpleQueries.h */
Zoltan_Set_Num_Obj_Fn(zz, get_number_of_vertices, &myGraph);
Zoltan_Set_Obj_List_Fn(zz, get_vertex_list, &myGraph);
Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, &myGraph);
Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, &myGraph);
/******************************************************************
** Zoltan can now partition the simple graph.
** In this simple example, we assume the number of partitions is
** equal to the number of processes. Process rank 0 will own
** partition 0, process rank 1 will own partition 1, and so on.
******************************************************************/
rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
&changes, /* 1 if partitioning was changed, 0 otherwise */
&numGidEntries, /* Number of integers used for a global ID */
&numLidEntries, /* Number of integers used for a local ID */
&numImport, /* Number of vertices to be sent to me */
&importGlobalGids, /* Global IDs of vertices to be sent to me */
&importLocalGids, /* Local IDs of vertices to be sent to me */
&importProcs, /* Process rank for source of each incoming vertex */
&importToPart, /* New partition for each incoming vertex */
&numExport, /* Number of vertices I must send to other processes*/
&exportGlobalGids, /* Global IDs of the vertices I must send */
&exportLocalGids, /* Local IDs of the vertices I must send */
&exportProcs, /* Process to which I send each of the vertices */
&exportToPart); /* Partition to which each vertex will belong */
if (rc != ZOLTAN_OK){
printf("sorry...\n");
MPI_Finalize();
Zoltan_Destroy(&zz);
exit(0);
}
/******************************************************************
** Visualize the graph partitioning before and after calling Zoltan.
******************************************************************/
parts = (int *)malloc(sizeof(int) * myGraph.numMyVertices);
for (i=0; i < myGraph.numMyVertices; i++){
parts[i] = myRank;
}
if (myRank== 0){
printf("\nGraph partition before calling Zoltan\n");
}
showGraphPartitions(myRank, myGraph.numMyVertices, myGraph.vertexGID, parts, numProcs);
for (i=0; i < numExport; i++){
parts[exportLocalGids[i]] = exportToPart[i];
}
if (myRank == 0){
printf("Graph partition after calling Zoltan\n");
}
showGraphPartitions(myRank, myGraph.numMyVertices, myGraph.vertexGID, parts, numProcs);
free(parts);
/******************************************************************
** Free the arrays allocated by Zoltan_LB_Partition, and free
** the storage allocated for the Zoltan structure.
******************************************************************/
Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids,
&importProcs, &importToPart);
Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids,
&exportProcs, &exportToPart);
Zoltan_Destroy(&zz);
/**********************
** all done ***********
**********************/
MPI_Finalize();
if (myGraph.numMyVertices > 0){
free(myGraph.vertexGID);
free(myGraph.nborIndex);
if (myGraph.numAllNbors > 0){
free(myGraph.nborGID);
free(myGraph.nborProc);
}
}
return 0;
}
/* Application defined query functions */
static int get_number_of_vertices(void *data, int *ierr)
{
GRAPH_DATA *graph = (GRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
return graph->numMyVertices;
}
static void get_vertex_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr)
{
int i;
GRAPH_DATA *graph = (GRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
/* In this example, return the IDs of our vertices, but no weights.
* Zoltan will assume equally weighted vertices.
*/
for (i=0; i<graph->numMyVertices; i++){
globalID[i] = graph->vertexGID[i];
localID[i] = i;
}
}
static void get_num_edges_list(void *data, int sizeGID, int sizeLID,
int num_obj,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *numEdges, int *ierr)
{
int i, idx;
GRAPH_DATA *graph = (GRAPH_DATA *)data;
if ( (sizeGID != 1) || (sizeLID != 1) || (num_obj != graph->numMyVertices)){
*ierr = ZOLTAN_FATAL;
return;
}
for (i=0; i < num_obj ; i++){
idx = localID[i];
numEdges[i] = graph->nborIndex[idx+1] - graph->nborIndex[idx];
}
*ierr = ZOLTAN_OK;
return;
}
static void get_edge_list(void *data, int sizeGID, int sizeLID,
int num_obj, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *num_edges,
ZOLTAN_ID_PTR nborGID, int *nborProc,
int wgt_dim, float *ewgts, int *ierr)
{
int i, j, from, to;
int *nextProc;
ZOLTAN_ID_TYPE *nextNbor;
float *nextWgt;
GRAPH_DATA *graph = (GRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
if ( (sizeGID != 1) || (sizeLID != 1) ||
(num_obj != graph->numMyVertices)) {
*ierr = ZOLTAN_FATAL;
return;
}
nextNbor = nborGID;
nextProc = nborProc;
nextWgt = ewgts;
for (i=0; i < num_obj; i++){
to = graph->nborIndex[localID[i]+1];
from = graph->nborIndex[localID[i]];
if ((to - from) != num_edges[i]){
*ierr = ZOLTAN_FATAL;
return;
}
for (j=from; j < to; j++){
*nextNbor++ = graph->nborGID[j];
*nextProc++ = graph->nborProc[j];
if (wgt_dim)
*nextWgt++ = (float)((graph->nborGID[j]<globalID[i]) ? graph->nborGID[j]
: globalID[i]);
}
}
return;
}
/* Function to find next line of information in input file */
static int get_next_line(FILE *fp, char *buf, int bufsize)
{
int i, cval, len;
char *c;
while (1){
c = fgets(buf, bufsize, fp);
if (c == NULL)
return 0; /* end of file */
len = strlen(c);
for (i=0, c=buf; i < len; i++, c++){
cval = (int)*c;
if (isspace(cval) == 0) break;
}
if (i == len) continue; /* blank line */
if (*c == '#') continue; /* comment */
if (c != buf){
strcpy(buf, c);
}
break;
}
return strlen(buf); /* number of characters */
}
/* Function to return the list of non-negative integers in a line */
static int get_line_ints(char *buf, int bufsize, int *vals)
{
char *c = buf;
int count=0;
while (1){
while (!(isdigit(*c))){
if ((c - buf) >= bufsize) break;
c++;
}
if ( (c-buf) >= bufsize) break;
vals[count++] = atoi(c);
while (isdigit(*c)){
if ((c - buf) >= bufsize) break;
c++;
}
if ( (c-buf) >= bufsize) break;
}
return count;
}
/* Proc 0 notifies others of error and exits */
static void input_file_error(int numProcs, int tag, int startProc)
{
int i, val[2];
val[0] = -1; /* error flag */
fprintf(stderr,"ERROR in input file.\n");
for (i=startProc; i < numProcs; i++){
/* these procs have posted a receive for "tag" expecting counts */
MPI_Send(val, 2, MPI_INT, i, tag, MPI_COMM_WORLD);
}
for (i=1; i < startProc; i++){
/* these procs are done and waiting for ok-to-go */
MPI_Send(val, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
exit(1);
}
/* Draw the partition assignments of the objects */
static void showGraphPartitions(int myProc, int numIDs, ZOLTAN_ID_TYPE *GIDs, int *parts, int nparts)
{
int partAssign[25], allPartAssign[25];
int i, j, part, cuts, prevPart=-1;
float imbal, localImbal, sum;
int *partCount=NULL;
partCount = (int *)calloc(sizeof(int), nparts);
memset(partAssign, 0, sizeof(int) * 25);
for (i=0; i < numIDs; i++){
partAssign[GIDs[i]-1] = parts[i];
}
MPI_Reduce(partAssign, allPartAssign, 25, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
if (myProc == 0){
cuts = 0;
for (i=20; i >= 0; i-=5){
for (j=0; j < 5; j++){
part = allPartAssign[i + j];
partCount[part]++;
if (j > 0){
if (part == prevPart){
printf("-----%d",part);
}
else{
printf("--x--%d",part);
cuts++;
prevPart = part;
}
}
else{
printf("%d",part);
prevPart = part;
}
}
printf("\n");
if (i > 0){
for (j=0; j < 5; j++){
if (allPartAssign[i+j] != allPartAssign[i+j-5]){
printf("x ");
cuts++;
}
else{
printf("| ");
}
}
printf("\n");
}
}
printf("\n");
for (sum=0, i=0; i < nparts; i++){
sum += partCount[i];
}
imbal = 0;
for (i=0; i < nparts; i++){
/* An imbalance measure. 1.0 is perfect balance, larger is worse */
localImbal = (nparts * partCount[i]) / sum;
if (localImbal > imbal) imbal = localImbal;
}
printf("Object imbalance (1.0 perfect, larger numbers are worse): %f\n",imbal);
printf("Total number of edge cuts: %d\n\n",cuts);
}
if (partCount) free(partCount);
}
/*
* Read the graph in the input file and distribute the vertices.
*/
void read_input_file(int myRank, int numProcs, char *fname, GRAPH_DATA *graph)
{
char buf[512];
int bufsize;
int numGlobalVertices, numGlobalNeighbors;
int num, nnbors, ack=0;
int vGID;
int i, j, procID;
int vals[128], send_count[2];
int *idx;
unsigned int id;
FILE *fp;
MPI_Status status;
int ack_tag = 5, count_tag = 10, id_tag = 15;
GRAPH_DATA *send_graph;
if (myRank == 0){
bufsize = 512;
fp = fopen(fname, "r");
/* Get the number of vertices */
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalVertices);
if (num != 1) input_file_error(numProcs, count_tag, 1);
/* Get the number of vertex neighbors */
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalNeighbors);
if (num != 1) input_file_error(numProcs, count_tag, 1);
/* Allocate arrays to read in entire graph */
graph->vertexGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * numGlobalVertices);
graph->nborIndex = (int *)malloc(sizeof(int) * (numGlobalVertices + 1));
graph->nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * numGlobalNeighbors);
graph->nborProc = (int *)malloc(sizeof(int) * numGlobalNeighbors);
graph->nborIndex[0] = 0;
for (i=0; i < numGlobalVertices; i++){
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = get_line_ints(buf, bufsize, vals);
if (num < 2) input_file_error(numProcs, count_tag, 1);
vGID = vals[0];
nnbors = vals[1];
if (num < (nnbors + 2)) input_file_error(numProcs, count_tag, 1);
graph->vertexGID[i] = (ZOLTAN_ID_TYPE)vGID;
for (j=0; j < nnbors; j++){
graph->nborGID[graph->nborIndex[i] + j] = (ZOLTAN_ID_TYPE)vals[2 + j];
}
graph->nborIndex[i+1] = graph->nborIndex[i] + nnbors;
}
fclose(fp);
/* Assign each vertex to a process using a hash function */
for (i=0; i <numGlobalNeighbors; i++){
id = graph->nborGID[i];
graph->nborProc[i] = simple_hash(&id, numProcs);
}
/* Create a sub graph for each process */
send_graph = (GRAPH_DATA *)calloc(sizeof(GRAPH_DATA) , numProcs);
for (i=0; i < numGlobalVertices; i++){
id = graph->vertexGID[i];
procID = simple_hash(&id, numProcs);
send_graph[procID].numMyVertices++;
}
for (i=0; i < numProcs; i++){
num = send_graph[i].numMyVertices;
send_graph[i].vertexGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * num);
send_graph[i].nborIndex = (int *)calloc(sizeof(int) , (num + 1));
}
idx = (int *)calloc(sizeof(int), numProcs);
for (i=0; i < numGlobalVertices; i++){
id = graph->vertexGID[i];
nnbors = graph->nborIndex[i+1] - graph->nborIndex[i];
procID = simple_hash(&id, numProcs);
j = idx[procID];
send_graph[procID].vertexGID[j] = id;
send_graph[procID].nborIndex[j+1] = send_graph[procID].nborIndex[j] + nnbors;
idx[procID] = j+1;
}
for (i=0; i < numProcs; i++){
num = send_graph[i].nborIndex[send_graph[i].numMyVertices];
send_graph[i].nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * num);
send_graph[i].nborProc= (int *)malloc(sizeof(int) * num);
send_graph[i].numAllNbors = num;
}
memset(idx, 0, sizeof(int) * numProcs);
for (i=0; i < numGlobalVertices; i++){
id = graph->vertexGID[i];
nnbors = graph->nborIndex[i+1] - graph->nborIndex[i];
procID = simple_hash(&id, numProcs);
j = idx[procID];
if (nnbors > 0){
memcpy(send_graph[procID].nborGID + j, graph->nborGID + graph->nborIndex[i],
nnbors * sizeof(ZOLTAN_ID_TYPE));
memcpy(send_graph[procID].nborProc + j, graph->nborProc + graph->nborIndex[i],
nnbors * sizeof(int));
idx[procID] = j + nnbors;
}
}
free(idx);
/* Process zero sub-graph */
free(graph->vertexGID);
free(graph->nborIndex);
free(graph->nborGID);
free(graph->nborProc);
*graph = send_graph[0];
/* Send other processes their subgraph */
for (i=1; i < numProcs; i++){
send_count[0] = send_graph[i].numMyVertices;
send_count[1] = send_graph[i].numAllNbors;
MPI_Send(send_count, 2, MPI_INT, i, count_tag, MPI_COMM_WORLD);
MPI_Recv(&ack, 1, MPI_INT, i, ack_tag, MPI_COMM_WORLD, &status);
if (send_count[0] > 0){
MPI_Send(send_graph[i].vertexGID, send_count[0], ZOLTAN_ID_MPI_TYPE, i, id_tag, MPI_COMM_WORLD);
free(send_graph[i].vertexGID);
MPI_Send(send_graph[i].nborIndex, send_count[0] + 1, MPI_INT, i, id_tag + 1, MPI_COMM_WORLD);
free(send_graph[i].nborIndex);
if (send_count[1] > 0){
MPI_Send(send_graph[i].nborGID, send_count[1], ZOLTAN_ID_MPI_TYPE, i, id_tag + 2, MPI_COMM_WORLD);
free(send_graph[i].nborGID);
MPI_Send(send_graph[i].nborProc, send_count[1], MPI_INT, i, id_tag + 3, MPI_COMM_WORLD);
free(send_graph[i].nborProc);
}
}
}
free(send_graph);
/* signal all procs it is OK to go on */
ack = 0;
for (i=1; i < numProcs; i++){
MPI_Send(&ack, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
}
else{
MPI_Recv(send_count, 2, MPI_INT, 0, count_tag, MPI_COMM_WORLD, &status);
if (send_count[0] < 0){
MPI_Finalize();
exit(1);
}
ack = 0;
graph->numMyVertices = send_count[0];
graph->numAllNbors = send_count[1];
if (send_count[0] > 0){
graph->vertexGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * send_count[0]);
graph->nborIndex = (int *)malloc(sizeof(int) * (send_count[0] + 1));
if (send_count[1] > 0){
graph->nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * send_count[1]);
graph->nborProc = (int *)malloc(sizeof(int) * send_count[1]);
}
}
MPI_Send(&ack, 1, MPI_INT, 0, ack_tag, MPI_COMM_WORLD);
if (send_count[0] > 0){
MPI_Recv(graph->vertexGID,send_count[0], ZOLTAN_ID_MPI_TYPE, 0, id_tag, MPI_COMM_WORLD, &status);
MPI_Recv(graph->nborIndex,send_count[0] + 1, MPI_INT, 0, id_tag + 1, MPI_COMM_WORLD, &status);
if (send_count[1] > 0){
MPI_Recv(graph->nborGID,send_count[1], ZOLTAN_ID_MPI_TYPE, 0, id_tag + 2, MPI_COMM_WORLD, &status);
MPI_Recv(graph->nborProc,send_count[1], MPI_INT, 0, id_tag + 3, MPI_COMM_WORLD, &status);
}
}
/* ok to go on? */
MPI_Recv(&ack, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
if (ack < 0){
MPI_Finalize();
exit(1);
}
}
}
unsigned int simple_hash(unsigned int *key, unsigned int n)
{
unsigned int h, rest, *p, bytes, num_bytes;
char *byteptr;
num_bytes = (unsigned int) sizeof(int);
/* First hash the int-sized portions of the key */
h = 0;
for (p = (unsigned int *)key, bytes=num_bytes;
bytes >= (unsigned int) sizeof(int);
bytes-=sizeof(int), p++){
h = (h*2654435761U) ^ (*p);
}
/* Then take care of the remaining bytes, if any */
rest = 0;
for (byteptr = (char *)p; bytes > 0; bytes--, byteptr++){
rest = (rest<<8) | (*byteptr);
}
/* Merge the two parts */
if (rest)
h = (h*2654435761U) ^ rest;
/* Return h mod n */
return (h%n);
}

View File

@ -0,0 +1,448 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "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 SANDIA CORPORATION OR THE
* CONTRIBUTORS 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.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
/* Basic example of using Zoltan to compute a quick partitioning
** of a set of objects.
***************************************************************/
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "zoltan.h"
/* Name of file containing objects to be partitioned */
static char *global_fname="objects.txt";
/* Structure to hold object data */
typedef struct{
int numGlobalObjects;
int numMyObjects;
ZOLTAN_ID_TYPE *myGlobalIDs;
} OBJECT_DATA;
static int get_number_of_objects(void *data, int *ierr);
static void get_object_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr);
static int get_next_line(FILE *fp, char *buf, int bufsize);
static void input_file_error(int numProcs, int tag, int startProc);
static void showSimpleMeshPartitions(int myProc, int numIDs, ZOLTAN_ID_TYPE *GIDs, int *parts);
static void read_input_objects(int myRank, int numProcs, char *fname, OBJECT_DATA *myData);
int main(int argc, char *argv[])
{
int rc, i;
int myRank, numProcs;
float ver;
struct Zoltan_Struct *zz;
int changes, numGidEntries, numLidEntries, numImport, numExport;
ZOLTAN_ID_PTR importGlobalGids, importLocalGids;
ZOLTAN_ID_PTR exportGlobalGids, exportLocalGids;
int *importProcs, *importToPart, *exportProcs, *exportToPart;
int *parts = NULL;
FILE *fp;
OBJECT_DATA myData;
/******************************************************************
** Initialize MPI and Zoltan
******************************************************************/
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
rc = Zoltan_Initialize(argc, argv, &ver);
if (rc != ZOLTAN_OK){
printf("Error initializing Zoltan\n");
MPI_Finalize();
exit(0);
}
/******************************************************************
** Read objects from input file and distribute them unevenly
******************************************************************/
fp = fopen(global_fname, "r");
if (!fp){
if (myRank == 0) fprintf(stderr,"ERROR: Can not open %s\n",global_fname);
MPI_Finalize();
exit(1);
}
fclose(fp);
read_input_objects(myRank, numProcs, global_fname, &myData);
/******************************************************************
** Create a Zoltan library structure for this instance of load
** balancing. Set the parameters and query functions.
******************************************************************/
zz = Zoltan_Create(MPI_COMM_WORLD);
/* General parameters */
Zoltan_Set_Param(zz, "LB_METHOD", "BLOCK"); /* Zoltan method: "BLOCK" */
Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1"); /* global ID is 1 integer */
Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1"); /* local ID is 1 integer */
Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0"); /* we omit object weights */
/* Query functions */
Zoltan_Set_Num_Obj_Fn(zz, get_number_of_objects, &myData);
Zoltan_Set_Obj_List_Fn(zz, get_object_list, &myData);
/******************************************************************
** Call Zoltan to partition the objects.
******************************************************************/
rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
&changes, /* 1 if partitioning was changed, 0 otherwise */
&numGidEntries, /* Number of integers used for a global ID */
&numLidEntries, /* Number of integers used for a local ID */
&numImport, /* Number of objects to be sent to me */
&importGlobalGids, /* Global IDs of objects to be sent to me */
&importLocalGids, /* Local IDs of objects to be sent to me */
&importProcs, /* Process rank for source of each incoming object */
&importToPart, /* New partition for each incoming object */
&numExport, /* Number of objects I must send to other processes*/
&exportGlobalGids, /* Global IDs of the objects I must send */
&exportLocalGids, /* Local IDs of the objects I must send */
&exportProcs, /* Process to which I send each of the objects */
&exportToPart); /* Partition to which each object will belong */
if (rc != ZOLTAN_OK){
printf("Error in Zoltan library\n");
MPI_Finalize();
Zoltan_Destroy(&zz);
exit(0);
}
/******************************************************************
** Visualize the object partitioning before and after calling Zoltan.
**
** In this example, partition number equals process rank.
******************************************************************/
parts = (int *)malloc(sizeof(int) * myData.numMyObjects);
for (i=0; i < myData.numMyObjects; i++){
parts[i] = myRank;
}
if (myRank== 0){
printf("\nObject partition assignments before calling Zoltan\n");
}
showSimpleMeshPartitions(myRank, myData.numMyObjects, myData.myGlobalIDs, parts);
for (i=0; i < numExport; i++){
parts[exportLocalGids[i]] = exportToPart[i];
}
if (myRank == 0){
printf("Object partition assignments after calling Zoltan\n");
}
showSimpleMeshPartitions(myRank, myData.numMyObjects, myData.myGlobalIDs, parts);
/******************************************************************
** Free the arrays allocated by Zoltan_LB_Partition, and free
** the storage allocated for the Zoltan structure.
******************************************************************/
Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids,
&importProcs, &importToPart);
Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids,
&exportProcs, &exportToPart);
Zoltan_Destroy(&zz);
if (myData.numMyObjects) {
free(parts);
free(myData.myGlobalIDs);
}
MPI_Finalize();
return 0;
}
/* Application defined query functions */
static int get_number_of_objects(void *data, int *ierr)
{
OBJECT_DATA *objects = (OBJECT_DATA *)data;
*ierr = ZOLTAN_OK;
return objects->numMyObjects;
}
static void get_object_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr)
{
int i;
OBJECT_DATA *objects = (OBJECT_DATA *)data;
*ierr = ZOLTAN_OK;
/* In this example, return the IDs of our objects, but no weights.
* Zoltan will assume equally weighted objects.
*/
for (i=0; i<objects->numMyObjects; i++){
globalID[i] = objects->myGlobalIDs[i];
localID[i] = i;
}
}
/* Function to find next line of information in input file */
static int get_next_line(FILE *fp, char *buf, int bufsize)
{
int i, cval, len;
char *c;
while (1){
c = fgets(buf, bufsize, fp);
if (c == NULL)
return 0; /* end of file */
len = strlen(c);
for (i=0, c=buf; i < len; i++, c++){
cval = (int)*c;
if (isspace(cval) == 0) break;
}
if (i == len) continue; /* blank line */
if (*c == '#') continue; /* comment */
if (c != buf){
strcpy(buf, c);
}
break;
}
return strlen(buf); /* number of characters */
}
/* Proc 0 notifies others of error and exits */
static void input_file_error(int numProcs, int tag, int startProc)
{
int i, val;
val = -1;
fprintf(stderr,"ERROR in input file.\n");
for (i=startProc; i < numProcs; i++){
/* these procs have posted receive for "tag" */
MPI_Send(&val, 1, MPI_INT, i, tag, MPI_COMM_WORLD);
}
for (i=1; i < startProc; i++){
/* these procs are done */
MPI_Send(&val, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
exit(1);
}
/* Draw the partition assignments of the objects */
void showSimpleMeshPartitions(int myProc, int numIDs, ZOLTAN_ID_TYPE *GIDs, int *parts)
{
int partAssign[25], allPartAssign[25];
int i, j, part;
memset(partAssign, 0, sizeof(int) * 25);
for (i=0; i < numIDs; i++){
partAssign[GIDs[i]-1] = parts[i];
}
MPI_Reduce(partAssign, allPartAssign, 25, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
if (myProc == 0){
for (i=20; i >= 0; i-=5){
for (j=0; j < 5; j++){
part = allPartAssign[i + j];
if (j < 4)
printf("%d-----",part);
else
printf("%d\n",part);
}
if (i > 0)
printf("| | | | |\n");
}
printf("\n");
}
}
/* Proc 0 reads the objects in the input file and divides them across processes */
void read_input_objects(int myRank, int numProcs, char *fname, OBJECT_DATA *myData)
{
char *buf;
int bufsize = 512;
int num, nobj, remainingObj, ack=0;
int i, j;
ZOLTAN_ID_TYPE *gids;
FILE *fp;
MPI_Status status;
int obj_ack_tag = 5, obj_count_tag = 10, obj_id_tag = 15;
if (myRank == 0){
buf = (char *)malloc(sizeof(char) * bufsize);
fp = fopen(fname, "r");
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, obj_count_tag, 1);
num = sscanf(buf, "%d", &myData->numGlobalObjects);
if (num != 1) input_file_error(numProcs, obj_count_tag, 1);
if (numProcs > 1){
nobj = myData->numGlobalObjects / 2;
remainingObj = myData->numGlobalObjects - nobj;
}
else{
nobj = myData->numGlobalObjects;
remainingObj = 0;
}
myData->myGlobalIDs = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * nobj);
myData->numMyObjects = nobj;
for (i=0; i < nobj; i++){
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, obj_count_tag, 1);
num = sscanf(buf, ZOLTAN_ID_SPEC , myData->myGlobalIDs + i);
if (num != 1) input_file_error(numProcs, obj_count_tag, 1);
}
gids = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * (nobj + 1));
for (i=1; i < numProcs; i++){
if (remainingObj > 1){
nobj = remainingObj / 2;
remainingObj -= nobj;
}
else if (remainingObj == 1){
nobj = 1;
remainingObj = 0;
}
else{
nobj = 0;
}
if ((i == numProcs - 1) && (remainingObj > 0))
nobj += remainingObj;
if (nobj > 0){
for (j=0; j < nobj; j++){
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, obj_count_tag, i);
num = sscanf(buf, ZOLTAN_ID_SPEC, gids + j);
if (num != 1) input_file_error(numProcs, obj_count_tag, i);
}
}
MPI_Send(&nobj, 1, MPI_INT, i, obj_count_tag, MPI_COMM_WORLD);
MPI_Recv(&ack, 1, MPI_INT, i, obj_ack_tag, MPI_COMM_WORLD, &status);
if (nobj > 0)
MPI_Send(gids, nobj, ZOLTAN_ID_MPI_TYPE, i, obj_id_tag, MPI_COMM_WORLD);
}
free(gids);
fclose(fp);
free(buf);
/* signal all procs it is OK to go on */
ack = 0;
for (i=1; i < numProcs; i++){
MPI_Send(&ack, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
}
else{
MPI_Recv(&myData->numMyObjects, 1, MPI_INT, 0, obj_count_tag, MPI_COMM_WORLD, &status);
ack = 0;
if (myData->numMyObjects > 0){
myData->myGlobalIDs = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * myData->numMyObjects);
MPI_Send(&ack, 1, MPI_INT, 0, obj_ack_tag, MPI_COMM_WORLD);
MPI_Recv(myData->myGlobalIDs, myData->numMyObjects, ZOLTAN_ID_MPI_TYPE, 0,
obj_id_tag, MPI_COMM_WORLD, &status);
}
else if (myData->numMyObjects == 0){
MPI_Send(&ack, 1, MPI_INT, 0, obj_ack_tag, MPI_COMM_WORLD);
}
else{
MPI_Finalize();
exit(1);
}
MPI_Recv(&ack, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
if (ack < 0){
MPI_Finalize();
exit(1);
}
}
}

View File

@ -0,0 +1,782 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "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 SANDIA CORPORATION OR THE
* CONTRIBUTORS 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.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
/**************************************************************
* Basic example of using Zoltan to partition a graph.
***************************************************************/
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "zoltan.h"
/* Name of file containing graph to be partitioned */
static char *global_fname="graph.txt";
/* Structure to hold graph data
ZOLTAN_ID_TYPE is defined when Zoltan is compiled. It's size can
be obtained at runtime by a library call. (See zoltan_types.h).
*/
typedef struct{
int numMyVertices; /* total vertices in in my partition */
int numAllNbors; /* total number of neighbors of my vertices */
ZOLTAN_ID_TYPE *vertexGID; /* global ID of each of my vertices */
int *nborIndex; /* nborIndex[i] is location of start of neighbors for vertex i */
ZOLTAN_ID_TYPE *nborGID; /* nborGIDs[nborIndex[i]] is first neighbor of vertex i */
int *nborProc; /* process owning each nbor in nborGID */
} GRAPH_DATA;
/* Application defined query functions */
static int get_number_of_vertices(void *data, int *ierr);
static void get_vertex_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr);
static void get_num_edges_list(void *data, int sizeGID, int sizeLID,
int num_obj,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *numEdges, int *ierr);
static void get_edge_list(void *data, int sizeGID, int sizeLID,
int num_obj, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *num_edges,
ZOLTAN_ID_PTR nborGID, int *nborProc,
int wgt_dim, float *ewgts, int *ierr);
/* Functions to read graph in from file, distribute it, view it, handle errors */
static int get_next_line(FILE *fp, char *buf, int bufsize);
static int get_line_ints(char *buf, int bufsize, int *vals);
static void input_file_error(int numProcs, int tag, int startProc);
static void showGraphPartitions(int myProc, int numIDs, ZOLTAN_ID_TYPE *GIDs, int *parts, int nparts);
static void read_input_file(int myRank, int numProcs, char *fname, GRAPH_DATA *myData);
static unsigned int simple_hash(unsigned int *key, unsigned int n);
int main(int argc, char *argv[])
{
int i, rc;
float ver;
struct Zoltan_Struct *zz;
int changes, numGidEntries, numLidEntries, numImport, numExport;
int myRank, numProcs;
ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
int *importProcs, *importToPart, *exportProcs, *exportToPart;
int *parts = NULL;
FILE *fp;
GRAPH_DATA myGraph;
/******************************************************************
** Initialize MPI and Zoltan
******************************************************************/
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
rc = Zoltan_Initialize(argc, argv, &ver);
if (rc != ZOLTAN_OK){
printf("sorry...\n");
MPI_Finalize();
exit(0);
}
/******************************************************************
** Read graph from input file and distribute it
******************************************************************/
fp = fopen(global_fname, "r");
if (!fp){
if (myRank == 0) fprintf(stderr,"ERROR: Can not open %s\n",global_fname);
MPI_Finalize();
exit(1);
}
fclose(fp);
read_input_file(myRank, numProcs, global_fname, &myGraph);
/******************************************************************
** Create a Zoltan library structure for this instance of load
** balancing. Set the parameters and query functions that will
** govern the library's calculation. See the Zoltan User's
** Guide for the definition of these and many other parameters.
******************************************************************/
zz = Zoltan_Create(MPI_COMM_WORLD);
/* General parameters */
Zoltan_Set_Param(zz, "DEBUG_LEVEL", "0");
Zoltan_Set_Param(zz, "LB_METHOD", "GRAPH");
Zoltan_Set_Param(zz, "LB_APPROACH", "PARTITION");
Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");
Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL");
/* Graph parameters */
Zoltan_Set_Param(zz, "CHECK_GRAPH", "2");
Zoltan_Set_Param(zz, "PHG_EDGE_SIZE_THRESHOLD", ".35"); /* 0-remove all, 1-remove none */
/* Query functions - defined in simpleQueries.h */
Zoltan_Set_Num_Obj_Fn(zz, get_number_of_vertices, &myGraph);
Zoltan_Set_Obj_List_Fn(zz, get_vertex_list, &myGraph);
Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, &myGraph);
Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, &myGraph);
/******************************************************************
** Zoltan can now partition the simple graph.
** In this simple example, we assume the number of partitions is
** equal to the number of processes. Process rank 0 will own
** partition 0, process rank 1 will own partition 1, and so on.
******************************************************************/
rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
&changes, /* 1 if partitioning was changed, 0 otherwise */
&numGidEntries, /* Number of integers used for a global ID */
&numLidEntries, /* Number of integers used for a local ID */
&numImport, /* Number of vertices to be sent to me */
&importGlobalGids, /* Global IDs of vertices to be sent to me */
&importLocalGids, /* Local IDs of vertices to be sent to me */
&importProcs, /* Process rank for source of each incoming vertex */
&importToPart, /* New partition for each incoming vertex */
&numExport, /* Number of vertices I must send to other processes*/
&exportGlobalGids, /* Global IDs of the vertices I must send */
&exportLocalGids, /* Local IDs of the vertices I must send */
&exportProcs, /* Process to which I send each of the vertices */
&exportToPart); /* Partition to which each vertex will belong */
if (rc != ZOLTAN_OK){
printf("sorry...\n");
MPI_Finalize();
Zoltan_Destroy(&zz);
exit(0);
}
/******************************************************************
** Visualize the graph partitioning before and after calling Zoltan.
******************************************************************/
parts = (int *)malloc(sizeof(int) * myGraph.numMyVertices);
for (i=0; i < myGraph.numMyVertices; i++){
parts[i] = myRank;
}
if (myRank== 0){
printf("\nGraph partition before calling Zoltan\n");
}
showGraphPartitions(myRank, myGraph.numMyVertices, myGraph.vertexGID, parts, numProcs);
for (i=0; i < numExport; i++){
parts[exportLocalGids[i]] = exportToPart[i];
}
if (myRank == 0){
printf("Graph partition after calling Zoltan\n");
}
showGraphPartitions(myRank, myGraph.numMyVertices, myGraph.vertexGID, parts, numProcs);
if (parts) free(parts);
/******************************************************************
** Free the arrays allocated by Zoltan_LB_Partition, and free
** the storage allocated for the Zoltan structure.
******************************************************************/
Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids,
&importProcs, &importToPart);
Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids,
&exportProcs, &exportToPart);
Zoltan_Destroy(&zz);
/**********************
** all done ***********
**********************/
MPI_Finalize();
if (myGraph.numMyVertices > 0){
free(myGraph.vertexGID);
free(myGraph.nborIndex);
if (myGraph.numAllNbors > 0){
free(myGraph.nborGID);
free(myGraph.nborProc);
}
}
return 0;
}
/* Application defined query functions */
static int get_number_of_vertices(void *data, int *ierr)
{
GRAPH_DATA *graph = (GRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
return graph->numMyVertices;
}
static void get_vertex_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr)
{
int i;
GRAPH_DATA *graph = (GRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
/* In this example, return the IDs of our vertices, but no weights.
* Zoltan will assume equally weighted vertices.
*/
for (i=0; i<graph->numMyVertices; i++){
globalID[i] = graph->vertexGID[i];
localID[i] = i;
}
}
static void get_num_edges_list(void *data, int sizeGID, int sizeLID,
int num_obj,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *numEdges, int *ierr)
{
int i, idx;
GRAPH_DATA *graph = (GRAPH_DATA *)data;
if ( (sizeGID != 1) || (sizeLID != 1) || (num_obj != graph->numMyVertices)){
*ierr = ZOLTAN_FATAL;
return;
}
for (i=0; i < num_obj ; i++){
idx = localID[i];
numEdges[i] = graph->nborIndex[idx+1] - graph->nborIndex[idx];
}
*ierr = ZOLTAN_OK;
return;
}
static void get_edge_list(void *data, int sizeGID, int sizeLID,
int num_obj, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *num_edges,
ZOLTAN_ID_PTR nborGID, int *nborProc,
int wgt_dim, float *ewgts, int *ierr)
{
int i, j, from, to;
int *nextProc;
ZOLTAN_ID_TYPE *nextNbor;
GRAPH_DATA *graph = (GRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
if ( (sizeGID != 1) || (sizeLID != 1) ||
(num_obj != graph->numMyVertices)||
(wgt_dim != 0)){
*ierr = ZOLTAN_FATAL;
return;
}
nextNbor = nborGID;
nextProc = nborProc;
for (i=0; i < num_obj; i++){
/*
* In this example, we are not setting edge weights. Zoltan will
* set each edge to weight 1.0.
*/
to = graph->nborIndex[localID[i]+1];
from = graph->nborIndex[localID[i]];
if ((to - from) != num_edges[i]){
*ierr = ZOLTAN_FATAL;
return;
}
for (j=from; j < to; j++){
*nextNbor++ = graph->nborGID[j];
*nextProc++ = graph->nborProc[j];
}
}
return;
}
/* Function to find next line of information in input file */
static int get_next_line(FILE *fp, char *buf, int bufsize)
{
int i, cval, len;
char *c;
while (1){
c = fgets(buf, bufsize, fp);
if (c == NULL)
return 0; /* end of file */
len = strlen(c);
for (i=0, c=buf; i < len; i++, c++){
cval = (int)*c;
if (isspace(cval) == 0) break;
}
if (i == len) continue; /* blank line */
if (*c == '#') continue; /* comment */
if (c != buf){
strcpy(buf, c);
}
break;
}
return strlen(buf); /* number of characters */
}
/* Function to return the list of non-negative integers in a line */
static int get_line_ints(char *buf, int bufsize, int *vals)
{
char *c = buf;
int count=0;
while (1){
if ( (c-buf) >= bufsize) break;
while (!(isdigit(*c))){
if ((c - buf) >= bufsize) break;
c++;
}
if ( (c-buf) >= bufsize) break;
vals[count++] = atoi(c);
while (isdigit(*c)){
if ((c - buf) >= bufsize) break;
c++;
}
if ( (c-buf) >= bufsize) break;
}
return count;
}
/* Proc 0 notifies others of error and exits */
static void input_file_error(int numProcs, int tag, int startProc)
{
int i, val[2];
val[0] = -1; /* error flag */
fprintf(stderr,"ERROR in input file.\n");
for (i=startProc; i < numProcs; i++){
/* these procs have posted a receive for "tag" expecting counts */
MPI_Send(val, 2, MPI_INT, i, tag, MPI_COMM_WORLD);
}
for (i=1; i < startProc; i++){
/* these procs are done and waiting for ok-to-go */
MPI_Send(val, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
exit(1);
}
/* Draw the partition assignments of the objects */
static void showGraphPartitions(int myProc, int numIDs, ZOLTAN_ID_TYPE *GIDs, int *parts, int nparts)
{
int partAssign[25], allPartAssign[25];
int i, j, part, cuts, prevPart=-1;
float imbal, localImbal, sum;
int *partCount;
memset(partAssign, 0, sizeof(int) * 25);
for (i=0; i < numIDs; i++){
partAssign[GIDs[i]-1] = parts[i];
}
MPI_Reduce(partAssign, allPartAssign, 25, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
if (myProc == 0){
partCount = (int *)calloc(sizeof(int), nparts);
cuts = 0;
for (i=20; i >= 0; i-=5){
for (j=0; j < 5; j++){
part = allPartAssign[i + j];
partCount[part]++;
if (j > 0){
if (part == prevPart){
printf("-----%d",part);
}
else{
printf("--x--%d",part);
cuts++;
prevPart = part;
}
}
else{
printf("%d",part);
prevPart = part;
}
}
printf("\n");
if (i > 0){
for (j=0; j < 5; j++){
if (allPartAssign[i+j] != allPartAssign[i+j-5]){
printf("x ");
cuts++;
}
else{
printf("| ");
}
}
printf("\n");
}
}
printf("\n");
for (sum=0, i=0; i < nparts; i++){
sum += partCount[i];
}
imbal = 0;
for (i=0; i < nparts; i++){
/* An imbalance measure. 1.0 is perfect balance, larger is worse */
localImbal = (nparts * partCount[i]) / sum;
if (localImbal > imbal) imbal = localImbal;
}
printf("Object imbalance (1.0 perfect, larger numbers are worse): %f\n",imbal);
printf("Total number of edge cuts: %d\n\n",cuts);
if (nparts) free(partCount);
}
}
/*
* Read the graph in the input file and distribute the vertices.
*/
void read_input_file(int myRank, int numProcs, char *fname, GRAPH_DATA *graph)
{
char buf[512];
int bufsize;
int numGlobalVertices, numGlobalNeighbors;
int num, nnbors, ack=0;
int vGID;
int i, j, procID;
int vals[128], send_count[2];
int *idx;
unsigned int id;
FILE *fp;
MPI_Status status;
int ack_tag = 5, count_tag = 10, id_tag = 15;
GRAPH_DATA *send_graph;
if (myRank == 0){
bufsize = 512;
fp = fopen(fname, "r");
/* Get the number of vertices */
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalVertices);
if (num != 1) input_file_error(numProcs, count_tag, 1);
/* Get the number of vertex neighbors */
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalNeighbors);
if (num != 1) input_file_error(numProcs, count_tag, 1);
/* Allocate arrays to read in entire graph */
graph->vertexGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * numGlobalVertices);
graph->nborIndex = (int *)malloc(sizeof(int) * (numGlobalVertices + 1));
graph->nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * numGlobalNeighbors);
graph->nborProc = (int *)malloc(sizeof(int) * numGlobalNeighbors);
graph->nborIndex[0] = 0;
for (i=0; i < numGlobalVertices; i++){
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = get_line_ints(buf, strlen(buf), vals);
if (num < 2) input_file_error(numProcs, count_tag, 1);
vGID = vals[0];
nnbors = vals[1];
if (num < (nnbors + 2)) input_file_error(numProcs, count_tag, 1);
graph->vertexGID[i] = (ZOLTAN_ID_TYPE)vGID;
for (j=0; j < nnbors; j++){
graph->nborGID[graph->nborIndex[i] + j] = (ZOLTAN_ID_TYPE)vals[2 + j];
}
graph->nborIndex[i+1] = graph->nborIndex[i] + nnbors;
}
fclose(fp);
/* Assign each vertex to a process using a hash function */
for (i=0; i <numGlobalNeighbors; i++){
id = (unsigned int)graph->nborGID[i];
graph->nborProc[i] = simple_hash(&id, numProcs);
}
/* Create a sub graph for each process */
send_graph = (GRAPH_DATA *)calloc(sizeof(GRAPH_DATA) , numProcs);
for (i=0; i < numGlobalVertices; i++){
id = (unsigned int)graph->vertexGID[i];
procID = simple_hash(&id, numProcs);
send_graph[procID].numMyVertices++;
}
for (i=0; i < numProcs; i++){
num = send_graph[i].numMyVertices;
send_graph[i].vertexGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * num);
send_graph[i].nborIndex = (int *)calloc(sizeof(int) , (num + 1));
}
idx = (int *)calloc(sizeof(int), numProcs);
for (i=0; i < numGlobalVertices; i++){
id = (unsigned int)graph->vertexGID[i];
nnbors = graph->nborIndex[i+1] - graph->nborIndex[i];
procID = simple_hash(&id, numProcs);
j = idx[procID];
send_graph[procID].vertexGID[j] = (ZOLTAN_ID_TYPE)id;
send_graph[procID].nborIndex[j+1] = send_graph[procID].nborIndex[j] + nnbors;
idx[procID] = j+1;
}
for (i=0; i < numProcs; i++){
num = send_graph[i].nborIndex[send_graph[i].numMyVertices];
send_graph[i].nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * num);
send_graph[i].nborProc= (int *)malloc(sizeof(int) * num);
send_graph[i].numAllNbors = num;
}
memset(idx, 0, sizeof(int) * numProcs);
for (i=0; i < numGlobalVertices; i++){
id = (unsigned int)graph->vertexGID[i];
nnbors = graph->nborIndex[i+1] - graph->nborIndex[i];
procID = simple_hash(&id, numProcs);
j = idx[procID];
if (nnbors > 0){
memcpy(send_graph[procID].nborGID + j, graph->nborGID + graph->nborIndex[i],
nnbors * sizeof(ZOLTAN_ID_TYPE));
memcpy(send_graph[procID].nborProc + j, graph->nborProc + graph->nborIndex[i],
nnbors * sizeof(int));
idx[procID] = j + nnbors;
}
}
free(idx);
/* Process zero sub-graph */
free(graph->vertexGID);
free(graph->nborIndex);
free(graph->nborGID);
free(graph->nborProc);
*graph = send_graph[0];
/* Send other processes their subgraph */
for (i=1; i < numProcs; i++){
send_count[0] = send_graph[i].numMyVertices;
send_count[1] = send_graph[i].numAllNbors;
MPI_Send(send_count, 2, MPI_INT, i, count_tag, MPI_COMM_WORLD);
MPI_Recv(&ack, 1, MPI_INT, i, ack_tag, MPI_COMM_WORLD, &status);
if (send_count[0] > 0){
MPI_Send(send_graph[i].vertexGID, send_count[0], ZOLTAN_ID_MPI_TYPE, i, id_tag, MPI_COMM_WORLD);
free(send_graph[i].vertexGID);
MPI_Send(send_graph[i].nborIndex, send_count[0] + 1, MPI_INT, i, id_tag + 1, MPI_COMM_WORLD);
free(send_graph[i].nborIndex);
if (send_count[1] > 0){
MPI_Send(send_graph[i].nborGID, send_count[1], ZOLTAN_ID_MPI_TYPE, i, id_tag + 2, MPI_COMM_WORLD);
free(send_graph[i].nborGID);
MPI_Send(send_graph[i].nborProc, send_count[1], MPI_INT, i, id_tag + 3, MPI_COMM_WORLD);
free(send_graph[i].nborProc);
}
}
}
free(send_graph);
/* signal all procs it is OK to go on */
ack = 0;
for (i=1; i < numProcs; i++){
MPI_Send(&ack, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
}
else{
MPI_Recv(send_count, 2, MPI_INT, 0, count_tag, MPI_COMM_WORLD, &status);
if (send_count[0] < 0){
MPI_Finalize();
exit(1);
}
ack = 0;
graph->numMyVertices = send_count[0];
graph->numAllNbors = send_count[1];
if (send_count[0] > 0){
graph->vertexGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * send_count[0]);
graph->nborIndex = (int *)malloc(sizeof(int) * (send_count[0] + 1));
if (send_count[1] > 0){
graph->nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * send_count[1]);
graph->nborProc = (int *)malloc(sizeof(int) * send_count[1]);
}
}
MPI_Send(&ack, 1, MPI_INT, 0, ack_tag, MPI_COMM_WORLD);
if (send_count[0] > 0){
MPI_Recv(graph->vertexGID,send_count[0],ZOLTAN_ID_MPI_TYPE, 0, id_tag, MPI_COMM_WORLD, &status);
MPI_Recv(graph->nborIndex,send_count[0] + 1, MPI_INT, 0, id_tag + 1, MPI_COMM_WORLD, &status);
if (send_count[1] > 0){
MPI_Recv(graph->nborGID,send_count[1], ZOLTAN_ID_MPI_TYPE, 0, id_tag + 2, MPI_COMM_WORLD, &status);
MPI_Recv(graph->nborProc,send_count[1], MPI_INT, 0, id_tag + 3, MPI_COMM_WORLD, &status);
}
}
/* ok to go on? */
MPI_Recv(&ack, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
if (ack < 0){
MPI_Finalize();
exit(1);
}
}
}
unsigned int simple_hash(unsigned int *key, unsigned int n)
{
unsigned int h, rest, *p, bytes, num_bytes;
char *byteptr;
num_bytes = (unsigned int) sizeof(int);
/* First hash the int-sized portions of the key */
h = 0;
for (p = (unsigned int *)key, bytes=num_bytes;
bytes >= (unsigned int) sizeof(int);
bytes-=sizeof(int), p++){
h = (h*2654435761U) ^ (*p);
}
/* Then take care of the remaining bytes, if any */
rest = 0;
for (byteptr = (char *)p; bytes > 0; bytes--, byteptr++){
rest = (rest<<8) | (*byteptr);
}
/* Merge the two parts */
if (rest)
h = (h*2654435761U) ^ rest;
/* Return h mod n */
return (h%n);
}

788
thirdParty/Zoltan/example/C/simpleHIER.c vendored Normal file
View File

@ -0,0 +1,788 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "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 SANDIA CORPORATION OR THE
* CONTRIBUTORS 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.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
/**************************************************************
* Basic example of using Zoltan to partition a graph.
***************************************************************/
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "zoltan.h"
/* Name of file containing graph to be partitioned */
static char *global_fname="graph.txt";
/* Structure to hold graph data */
typedef struct{
int numMyVertices; /* total vertices in in my partition */
int numAllNbors; /* total number of neighbors of my vertices */
int *vertexGID; /* global ID of each of my vertices */
int *nborIndex; /* nborIndex[i] is location of start of neighbors for vertex i */
int *nborGID; /* nborGIDs[nborIndex[i]] is first neighbor of vertex i */
int *nborProc; /* process owning each nbor in nborGID */
} GRAPH_DATA;
/* Application defined query functions */
static int get_number_of_vertices(void *data, int *ierr);
static void get_vertex_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr);
static void get_num_edges_list(void *data, int sizeGID, int sizeLID,
int num_obj,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *numEdges, int *ierr);
static void get_edge_list(void *data, int sizeGID, int sizeLID,
int num_obj, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *num_edges,
ZOLTAN_ID_PTR nborGID, int *nborProc,
int wgt_dim, float *ewgts, int *ierr);
/* Functions to read graph in from file, distribute it, view it, handle errors */
static int get_next_line(FILE *fp, char *buf, int bufsize);
static int get_line_ints(char *buf, int bufsize, int *vals);
static void input_file_error(int numProcs, int tag, int startProc);
static void showGraphPartitions(int myProc, int numIDs, int *GIDs, int *parts, int nparts);
static void read_input_file(int myRank, int numProcs, char *fname, GRAPH_DATA *myData);
static unsigned int simple_hash(unsigned int *key, unsigned int n);
int main(int argc, char *argv[])
{
int i, rc;
float ver;
struct Zoltan_Struct *zz;
int changes, numGidEntries, numLidEntries, numImport, numExport;
int myRank, numProcs;
ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
int *importProcs, *importToPart, *exportProcs, *exportToPart;
int *parts;
FILE *fp;
GRAPH_DATA myGraph;
/******************************************************************
** Initialize MPI and Zoltan
******************************************************************/
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
if (numProcs < 4){
if (myRank == 0) fprintf(stderr,
"ERROR: This test requires at least 4 processes\n");
MPI_Finalize();
exit(1);
}
rc = Zoltan_Initialize(argc, argv, &ver);
if (rc != ZOLTAN_OK){
printf("sorry...\n");
MPI_Finalize();
exit(0);
}
/******************************************************************
** Read graph from input file and distribute it
******************************************************************/
fp = fopen(global_fname, "r");
if (!fp){
if (myRank == 0) fprintf(stderr,"ERROR: Can not open %s\n",global_fname);
MPI_Finalize();
exit(1);
}
fclose(fp);
read_input_file(myRank, numProcs, global_fname, &myGraph);
/******************************************************************
** Create a Zoltan library structure for this instance of load
** balancing. Set the parameters and query functions that will
** govern the library's calculation. See the Zoltan User's
** Guide for the definition of these and many other parameters.
******************************************************************/
zz = Zoltan_Create(MPI_COMM_WORLD);
/* General parameters */
Zoltan_Set_Param(zz, "DEBUG_LEVEL", "0");
Zoltan_Set_Param(zz, "HIER_DEBUG_LEVEL", "1");
Zoltan_Set_Param(zz, "LB_METHOD", "HIER");
Zoltan_Set_Param(zz, "HIER_ASSIST", "1");
Zoltan_Set_Param(zz, "TOPOLOGY", "2,2");
Zoltan_Set_Param(zz, "PHG_EDGE_SIZE_THRESHOLD", ".8");
Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");
Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL");
/* Query functions - defined in simpleQueries.h */
Zoltan_Set_Num_Obj_Fn(zz, get_number_of_vertices, &myGraph);
Zoltan_Set_Obj_List_Fn(zz, get_vertex_list, &myGraph);
Zoltan_Set_Num_Edges_Multi_Fn(zz, get_num_edges_list, &myGraph);
Zoltan_Set_Edge_List_Multi_Fn(zz, get_edge_list, &myGraph);
/******************************************************************
** Zoltan can now partition the simple graph.
** In this simple example, we assume the number of partitions is
** equal to the number of processes. Process rank 0 will own
** partition 0, process rank 1 will own partition 1, and so on.
******************************************************************/
MPI_Barrier(MPI_COMM_WORLD);
if (myRank==0) fprintf(stderr,"GO Zoltan_LB_Partition\n");
MPI_Barrier(MPI_COMM_WORLD);
rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
&changes, /* 1 if partitioning was changed, 0 otherwise */
&numGidEntries, /* Number of integers used for a global ID */
&numLidEntries, /* Number of integers used for a local ID */
&numImport, /* Number of vertices to be sent to me */
&importGlobalGids, /* Global IDs of vertices to be sent to me */
&importLocalGids, /* Local IDs of vertices to be sent to me */
&importProcs, /* Process rank for source of each incoming vertex */
&importToPart, /* New partition for each incoming vertex */
&numExport, /* Number of vertices I must send to other processes*/
&exportGlobalGids, /* Global IDs of the vertices I must send */
&exportLocalGids, /* Local IDs of the vertices I must send */
&exportProcs, /* Process to which I send each of the vertices */
&exportToPart); /* Partition to which each vertex will belong */
if (rc != ZOLTAN_OK){
printf("sorry...\n");
MPI_Finalize();
Zoltan_Destroy(&zz);
exit(0);
}
MPI_Barrier(MPI_COMM_WORLD);
if (myRank==0) fprintf(stderr,"DONE Zoltan_LB_Partition\n");
MPI_Barrier(MPI_COMM_WORLD);
/******************************************************************
** Visualize the graph partitioning before and after calling Zoltan.
******************************************************************/
parts = (int *)malloc(sizeof(int) * myGraph.numMyVertices);
for (i=0; i < myGraph.numMyVertices; i++){
parts[i] = myRank;
}
if (myRank== 0){
printf("\nGraph partition before calling Zoltan\n");
}
showGraphPartitions(myRank, myGraph.numMyVertices, myGraph.vertexGID, parts, numProcs);
for (i=0; i < numExport; i++){
parts[exportLocalGids[i]] = exportToPart[i];
}
if (myRank == 0){
printf("Graph partition after calling Zoltan\n");
}
showGraphPartitions(myRank, myGraph.numMyVertices, myGraph.vertexGID, parts, numProcs);
/******************************************************************
** Free the arrays allocated by Zoltan_LB_Partition, and free
** the storage allocated for the Zoltan structure.
******************************************************************/
Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids,
&importProcs, &importToPart);
Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids,
&exportProcs, &exportToPart);
Zoltan_Destroy(&zz);
/**********************
** all done ***********
**********************/
MPI_Finalize();
if (myGraph.numMyVertices > 0){
free(myGraph.vertexGID);
free(myGraph.nborIndex);
if (myGraph.numAllNbors > 0){
free(myGraph.nborGID);
free(myGraph.nborProc);
}
}
if (myGraph.numMyVertices) free(parts);
return 0;
}
/* Application defined query functions */
static int get_number_of_vertices(void *data, int *ierr)
{
GRAPH_DATA *graph = (GRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
return graph->numMyVertices;
}
static void get_vertex_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr)
{
int i;
GRAPH_DATA *graph = (GRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
/* In this example, return the IDs of our vertices, but no weights.
* Zoltan will assume equally weighted vertices.
*/
for (i=0; i<graph->numMyVertices; i++){
globalID[i] = graph->vertexGID[i];
localID[i] = i;
}
}
static void get_num_edges_list(void *data, int sizeGID, int sizeLID,
int num_obj,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *numEdges, int *ierr)
{
int i, idx;
GRAPH_DATA *graph = (GRAPH_DATA *)data;
if ( (sizeGID != 1) || (sizeLID != 1) || (num_obj != graph->numMyVertices)){
*ierr = ZOLTAN_FATAL;
return;
}
for (i=0; i < num_obj ; i++){
idx = localID[i];
numEdges[i] = graph->nborIndex[idx+1] - graph->nborIndex[idx];
}
*ierr = ZOLTAN_OK;
return;
}
static void get_edge_list(void *data, int sizeGID, int sizeLID,
int num_obj, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int *num_edges,
ZOLTAN_ID_PTR nborGID, int *nborProc,
int wgt_dim, float *ewgts, int *ierr)
{
int i, j, from, to;
ZOLTAN_ID_PTR nextNbor;
int *nextProc;
GRAPH_DATA *graph = (GRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
if ( (sizeGID != 1) || (sizeLID != 1) ||
(num_obj != graph->numMyVertices)||
(wgt_dim != 0)){
*ierr = ZOLTAN_FATAL;
return;
}
nextNbor = nborGID;
nextProc = nborProc;
for (i=0; i < num_obj; i++){
/*
* In this example, we are not setting edge weights. Zoltan will
* set each edge to weight 1.0.
*/
to = graph->nborIndex[localID[i]+1];
from = graph->nborIndex[localID[i]];
if ((to - from) != num_edges[i]){
*ierr = ZOLTAN_FATAL;
return;
}
for (j=from; j < to; j++){
*nextNbor++ = graph->nborGID[j];
*nextProc++ = graph->nborProc[j];
}
}
return;
}
/* Function to find next line of information in input file */
static int get_next_line(FILE *fp, char *buf, int bufsize)
{
int i, cval, len;
char *c;
while (1){
c = fgets(buf, bufsize, fp);
if (c == NULL)
return 0; /* end of file */
len = strlen(c);
for (i=0, c=buf; i < len; i++, c++){
cval = (int)*c;
if (isspace(cval) == 0) break;
}
if (i == len) continue; /* blank line */
if (*c == '#') continue; /* comment */
if (c != buf){
strcpy(buf, c);
}
break;
}
return strlen(buf); /* number of characters */
}
/* Function to return the list of non-negative integers in a line */
static int get_line_ints(char *buf, int bufsize, int *vals)
{
char *c = buf;
int count=0;
while (1){
while (!(isdigit(*c))){
if ((c - buf) >= bufsize) break;
c++;
}
if ( (c-buf) >= bufsize) break;
vals[count++] = atoi(c);
while (isdigit(*c)){
if ((c - buf) >= bufsize) break;
c++;
}
if ( (c-buf) >= bufsize) break;
}
return count;
}
/* Proc 0 notifies others of error and exits */
static void input_file_error(int numProcs, int tag, int startProc)
{
int i, val[2];
val[0] = -1; /* error flag */
fprintf(stderr,"ERROR in input file.\n");
for (i=startProc; i < numProcs; i++){
/* these procs have posted a receive for "tag" expecting counts */
MPI_Send(val, 2, MPI_INT, i, tag, MPI_COMM_WORLD);
}
for (i=1; i < startProc; i++){
/* these procs are done and waiting for ok-to-go */
MPI_Send(val, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
exit(1);
}
/* Draw the partition assignments of the objects */
static void showGraphPartitions(int myProc, int numIDs, int *GIDs, int *parts, int nparts)
{
int partAssign[25], allPartAssign[25];
int i, j, part, cuts, prevPart=-1;
float imbal, localImbal, sum;
memset(partAssign, 0, sizeof(int) * 25);
for (i=0; i < numIDs; i++){
partAssign[GIDs[i]-1] = parts[i];
}
MPI_Reduce(partAssign, allPartAssign, 25, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
if (myProc == 0){
int *partCount;
partCount = (int *)calloc(sizeof(int), nparts);
cuts = 0;
for (i=20; i >= 0; i-=5){
for (j=0; j < 5; j++){
part = allPartAssign[i + j];
partCount[part]++;
if (j > 0){
if (part == prevPart){
printf("-----%d",part);
}
else{
printf("--x--%d",part);
cuts++;
prevPart = part;
}
}
else{
printf("%d",part);
prevPart = part;
}
}
printf("\n");
if (i > 0){
for (j=0; j < 5; j++){
if (allPartAssign[i+j] != allPartAssign[i+j-5]){
printf("x ");
cuts++;
}
else{
printf("| ");
}
}
printf("\n");
}
}
printf("\n");
for (sum=0, i=0; i < nparts; i++){
sum += partCount[i];
}
imbal = 0;
for (i=0; i < nparts; i++){
/* An imbalance measure. 1.0 is perfect balance, larger is worse */
localImbal = (nparts * partCount[i]) / sum;
if (localImbal > imbal) imbal = localImbal;
}
printf("Object imbalance (1.0 perfect, larger numbers are worse): %f\n",imbal);
printf("Total number of edge cuts: %d\n\n",cuts);
if (nparts) free(partCount);
}
}
/*
* Read the graph in the input file and distribute the vertices.
*/
void read_input_file(int myRank, int numProcs, char *fname, GRAPH_DATA *graph)
{
char buf[512];
int bufsize;
int numGlobalVertices, numGlobalNeighbors;
int num, nnbors, ack=0;
int vGID;
int i, j, procID;
int vals[128], send_count[2];
int *idx;
unsigned int id;
FILE *fp;
MPI_Status status;
int ack_tag = 5, count_tag = 10, id_tag = 15;
GRAPH_DATA *send_graph;
if (myRank == 0){
bufsize = 512;
fp = fopen(fname, "r");
/* Get the number of vertices */
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalVertices);
if (num != 1) input_file_error(numProcs, count_tag, 1);
/* Get the number of vertex neighbors */
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalNeighbors);
if (num != 1) input_file_error(numProcs, count_tag, 1);
/* Allocate arrays to read in entire graph */
graph->vertexGID = (int *)malloc(sizeof(int) * numGlobalVertices);
graph->nborIndex = (int *)malloc(sizeof(int) * (numGlobalVertices + 1));
graph->nborGID = (int *)malloc(sizeof(int) * numGlobalNeighbors);
graph->nborProc = (int *)malloc(sizeof(int) * numGlobalNeighbors);
graph->nborIndex[0] = 0;
for (i=0; i < numGlobalVertices; i++){
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = get_line_ints(buf, num, vals);
if (num < 2) input_file_error(numProcs, count_tag, 1);
vGID = vals[0];
nnbors = vals[1];
if (num < (nnbors + 2)) input_file_error(numProcs, count_tag, 1);
graph->vertexGID[i] = vGID;
for (j=0; j < nnbors; j++){
graph->nborGID[graph->nborIndex[i] + j] = vals[2 + j];
}
graph->nborIndex[i+1] = graph->nborIndex[i] + nnbors;
}
fclose(fp);
/* Assign each vertex to a process using a hash function */
for (i=0; i <numGlobalNeighbors; i++){
id = (unsigned int)graph->nborGID[i];
graph->nborProc[i] = simple_hash(&id, numProcs);
}
/* Create a sub graph for each process */
send_graph = (GRAPH_DATA *)calloc(sizeof(GRAPH_DATA) , numProcs);
for (i=0; i < numGlobalVertices; i++){
id = (unsigned int)graph->vertexGID[i];
procID = simple_hash(&id, numProcs);
send_graph[procID].numMyVertices++;
}
for (i=0; i < numProcs; i++){
num = send_graph[i].numMyVertices;
send_graph[i].vertexGID = (int *)malloc(sizeof(int) * num);
send_graph[i].nborIndex = (int *)calloc(sizeof(int) , (num + 1));
}
idx = (int *)calloc(sizeof(int), numProcs);
for (i=0; i < numGlobalVertices; i++){
id = (unsigned int)graph->vertexGID[i];
nnbors = graph->nborIndex[i+1] - graph->nborIndex[i];
procID = simple_hash(&id, numProcs);
j = idx[procID];
send_graph[procID].vertexGID[j] = id;
send_graph[procID].nborIndex[j+1] = send_graph[procID].nborIndex[j] + nnbors;
idx[procID] = j+1;
}
for (i=0; i < numProcs; i++){
num = send_graph[i].nborIndex[send_graph[i].numMyVertices];
send_graph[i].nborGID = (int *)malloc(sizeof(int) * num);
send_graph[i].nborProc= (int *)malloc(sizeof(int) * num);
send_graph[i].numAllNbors = num;
}
memset(idx, 0, sizeof(int) * numProcs);
for (i=0; i < numGlobalVertices; i++){
id = (unsigned int)graph->vertexGID[i];
nnbors = graph->nborIndex[i+1] - graph->nborIndex[i];
procID = simple_hash(&id, numProcs);
j = idx[procID];
if (nnbors > 0){
memcpy(send_graph[procID].nborGID + j, graph->nborGID + graph->nborIndex[i],
nnbors * sizeof(int));
memcpy(send_graph[procID].nborProc + j, graph->nborProc + graph->nborIndex[i],
nnbors * sizeof(int));
idx[procID] = j + nnbors;
}
}
free(idx);
/* Process zero sub-graph */
free(graph->vertexGID);
free(graph->nborIndex);
free(graph->nborGID);
free(graph->nborProc);
*graph = send_graph[0];
/* Send other processes their subgraph */
for (i=1; i < numProcs; i++){
send_count[0] = send_graph[i].numMyVertices;
send_count[1] = send_graph[i].numAllNbors;
MPI_Send(send_count, 2, MPI_INT, i, count_tag, MPI_COMM_WORLD);
MPI_Recv(&ack, 1, MPI_INT, i, ack_tag, MPI_COMM_WORLD, &status);
if (send_count[0] > 0){
MPI_Send(send_graph[i].vertexGID, send_count[0], MPI_INT, i, id_tag, MPI_COMM_WORLD);
free(send_graph[i].vertexGID);
MPI_Send(send_graph[i].nborIndex, send_count[0] + 1, MPI_INT, i, id_tag + 1, MPI_COMM_WORLD);
free(send_graph[i].nborIndex);
if (send_count[1] > 0){
MPI_Send(send_graph[i].nborGID, send_count[1], MPI_INT, i, id_tag + 2, MPI_COMM_WORLD);
free(send_graph[i].nborGID);
MPI_Send(send_graph[i].nborProc, send_count[1], MPI_INT, i, id_tag + 3, MPI_COMM_WORLD);
free(send_graph[i].nborProc);
}
}
}
free(send_graph);
/* signal all procs it is OK to go on */
ack = 0;
for (i=1; i < numProcs; i++){
MPI_Send(&ack, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
}
else{
MPI_Recv(send_count, 2, MPI_INT, 0, count_tag, MPI_COMM_WORLD, &status);
if (send_count[0] < 0){
MPI_Finalize();
exit(1);
}
ack = 0;
graph->numMyVertices = send_count[0];
graph->numAllNbors = send_count[1];
if (send_count[0] > 0){
graph->vertexGID = (int *)malloc(sizeof(int) * send_count[0]);
graph->nborIndex = (int *)malloc(sizeof(int) * (send_count[0] + 1));
if (send_count[1] > 0){
graph->nborGID = (int *)malloc(sizeof(int) * send_count[1]);
graph->nborProc = (int *)malloc(sizeof(int) * send_count[1]);
}
}
MPI_Send(&ack, 1, MPI_INT, 0, ack_tag, MPI_COMM_WORLD);
if (send_count[0] > 0){
MPI_Recv(graph->vertexGID,send_count[0], MPI_INT, 0, id_tag, MPI_COMM_WORLD, &status);
MPI_Recv(graph->nborIndex,send_count[0] + 1, MPI_INT, 0, id_tag + 1, MPI_COMM_WORLD, &status);
if (send_count[1] > 0){
MPI_Recv(graph->nborGID,send_count[1], MPI_INT, 0, id_tag + 2, MPI_COMM_WORLD, &status);
MPI_Recv(graph->nborProc,send_count[1], MPI_INT, 0, id_tag + 3, MPI_COMM_WORLD, &status);
}
}
/* ok to go on? */
MPI_Recv(&ack, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
if (ack < 0){
MPI_Finalize();
exit(1);
}
}
}
unsigned int simple_hash(unsigned int *key, unsigned int n)
{
unsigned int h, rest, *p, bytes, num_bytes;
char *byteptr;
num_bytes = (unsigned int) sizeof(int);
/* First hash the int-sized portions of the key */
h = 0;
for (p = (unsigned int *)key, bytes=num_bytes;
bytes >= (unsigned int) sizeof(int);
bytes-=sizeof(int), p++){
h = (h*2654435761U) ^ (*p);
}
/* Then take care of the remaining bytes, if any */
rest = 0;
for (byteptr = (char *)p; bytes > 0; bytes--, byteptr++){
rest = (rest<<8) | (*byteptr);
}
/* Merge the two parts */
if (rest)
h = (h*2654435761U) ^ rest;
/* Return h mod n */
return (h%n);
}

870
thirdParty/Zoltan/example/C/simplePHG.c vendored Normal file
View File

@ -0,0 +1,870 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "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 SANDIA CORPORATION OR THE
* CONTRIBUTORS 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.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
/**************************************************************
* Basic example of using Zoltan to partition a hypergraph.
*
* We think a hypergraph as a matrix, where the hyperedges are
* the rows, and the vertices are the columns. If (i,j) is
* non-zero, this indicates that vertex j is in hyperedge i.
*
* In some Zoltan documentation, the non-zeroes in hypergraph
* matrices are called "pins".
*
***************************************************************/
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "zoltan.h"
/* Name of file containing hypergraph to be partitioned */
static char *global_fname="hypergraph.txt";
/* Structure to hold distributed hypergraph */
typedef struct{
/* Zoltan will partition vertices, while minimizing edge cuts */
int numGlobalVertices; /* number of vertices in global hypergraph */
int numMyVertices; /* number of vertices that I own initially */
ZOLTAN_ID_TYPE *vtxGID; /* global ID of these vertices */
int numGlobalEdges; /* number of edges in global hypergraph */
int numMyHEdges; /* number of my hyperedges */
int numAllNbors; /* number of vertices in my hyperedges */
ZOLTAN_ID_TYPE *edgeGID; /* global ID of each of my hyperedges */
int *nborIndex; /* index into nborGID array of edge's vertices */
ZOLTAN_ID_TYPE *nborGID; /* Vertices of edge edgeGID[i] begin at nborGID[nborIndex[i]] */
} HGRAPH_DATA;
/* 4 application defined query functions. If we were going to define
* a weight for each hyperedge, we would need to define 2 more query functions.
*/
static int get_number_of_vertices(void *data, int *ierr);
static void get_vertex_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr);
static void get_hypergraph_size(void *data, int *num_lists, int *num_nonzeroes,
int *format, int *ierr);
static void get_hypergraph(void *data, int sizeGID, int num_edges, int num_nonzeroes,
int format, ZOLTAN_ID_PTR edgeGID, int *vtxPtr,
ZOLTAN_ID_PTR vtxGID, int *ierr);
/* Functions to read hypergraph in from file, distribute it, view it, handle errors */
static int get_next_line(FILE *fp, char *buf, int bufsize);
static int get_line_ints(char *buf, int bufsize, int *vals);
static void input_file_error(int numProcs, int tag, int startProc);
static void showHypergraph(int myProc, int numProc, int numIDs, ZOLTAN_ID_TYPE *GIDs, int *parts);
static void read_input_file(int myRank, int numProcs, char *fname, HGRAPH_DATA *data);
static HGRAPH_DATA global_hg;
int main(int argc, char *argv[])
{
int i, rc;
float ver;
struct Zoltan_Struct *zz;
int changes, numGidEntries, numLidEntries, numImport, numExport;
int myRank, numProcs;
ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
int *importProcs, *importToPart, *exportProcs, *exportToPart;
int *parts;
FILE *fp;
HGRAPH_DATA hg;
/******************************************************************
** Initialize MPI and Zoltan
******************************************************************/
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
rc = Zoltan_Initialize(argc, argv, &ver);
if (rc != ZOLTAN_OK){
printf("sorry...\n");
MPI_Finalize();
exit(0);
}
/******************************************************************
** Read hypergraph from input file and distribute it
******************************************************************/
fp = fopen(global_fname, "r");
if (!fp){
if (myRank == 0) fprintf(stderr,"ERROR: Can not open %s\n",global_fname);
MPI_Finalize();
exit(1);
}
fclose(fp);
read_input_file(myRank, numProcs, global_fname, &hg);
/******************************************************************
** Create a Zoltan library structure for this instance of load
** balancing. Set the parameters and query functions that will
** govern the library's calculation. See the Zoltan User's
** Guide for the definition of these and many other parameters.
******************************************************************/
zz = Zoltan_Create(MPI_COMM_WORLD);
/* General parameters */
Zoltan_Set_Param(zz, "DEBUG_LEVEL", "0");
Zoltan_Set_Param(zz, "LB_METHOD", "HYPERGRAPH"); /* partitioning method */
Zoltan_Set_Param(zz, "HYPERGRAPH_PACKAGE", "PHG"); /* version of method */
Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");/* global IDs are integers */
Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");/* local IDs are integers */
Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL"); /* export AND import lists */
Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0"); /* use Zoltan default vertex weights */
Zoltan_Set_Param(zz, "EDGE_WEIGHT_DIM", "0");/* use Zoltan default hyperedge weights */
/* PHG parameters - see the Zoltan User's Guide for many more
* (The "REPARTITION" approach asks Zoltan to create a partitioning that is
* better but is not too far from the current partitioning, rather than partitioning
* from scratch. It may be faster but of lower quality that LB_APPROACH=PARTITION.)
*/
Zoltan_Set_Param(zz, "LB_APPROACH", "REPARTITION");
/* Application defined query functions */
Zoltan_Set_Num_Obj_Fn(zz, get_number_of_vertices, &hg);
Zoltan_Set_Obj_List_Fn(zz, get_vertex_list, &hg);
Zoltan_Set_HG_Size_CS_Fn(zz, get_hypergraph_size, &hg);
Zoltan_Set_HG_CS_Fn(zz, get_hypergraph, &hg);
/******************************************************************
** Zoltan can now partition the vertices of hypergraph.
** In this simple example, we assume the number of partitions is
** equal to the number of processes. Process rank 0 will own
** partition 0, process rank 1 will own partition 1, and so on.
******************************************************************/
rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
&changes, /* 1 if partitioning was changed, 0 otherwise */
&numGidEntries, /* Number of integers used for a global ID */
&numLidEntries, /* Number of integers used for a local ID */
&numImport, /* Number of vertices to be sent to me */
&importGlobalGids, /* Global IDs of vertices to be sent to me */
&importLocalGids, /* Local IDs of vertices to be sent to me */
&importProcs, /* Process rank for source of each incoming vertex */
&importToPart, /* New partition for each incoming vertex */
&numExport, /* Number of vertices I must send to other processes*/
&exportGlobalGids, /* Global IDs of the vertices I must send */
&exportLocalGids, /* Local IDs of the vertices I must send */
&exportProcs, /* Process to which I send each of the vertices */
&exportToPart); /* Partition to which each vertex will belong */
if (rc != ZOLTAN_OK){
printf("sorry...\n");
MPI_Finalize();
Zoltan_Destroy(&zz);
exit(0);
}
/******************************************************************
** Visualize the hypergraph partitioning before and after calling Zoltan.
******************************************************************/
parts = (int *)malloc(sizeof(int) * hg.numMyVertices);
for (i=0; i < hg.numMyVertices; i++){
parts[i] = myRank;
}
if (myRank== 0){
printf("\nHypergraph partition before calling Zoltan\n");
}
showHypergraph(myRank, numProcs, hg.numMyVertices, hg.vtxGID, parts);
for (i=0; i < numExport; i++){
parts[exportLocalGids[i]] = exportToPart[i];
}
if (myRank == 0){
printf("Graph partition after calling Zoltan\n");
}
showHypergraph(myRank, numProcs, hg.numMyVertices, hg.vtxGID, parts);
/******************************************************************
** Free the arrays allocated by Zoltan_LB_Partition, and free
** the storage allocated for the Zoltan structure.
******************************************************************/
Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids,
&importProcs, &importToPart);
Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids,
&exportProcs, &exportToPart);
Zoltan_Destroy(&zz);
/**********************
** all done ***********
**********************/
MPI_Finalize();
if (hg.numMyVertices > 0){
free(parts);
free(hg.vtxGID);
}
if (hg.numMyHEdges > 0){
free(hg.edgeGID);
free(hg.nborIndex);
if (hg.numAllNbors > 0){
free(hg.nborGID);
}
}
return 0;
}
/* Application defined query functions */
static int get_number_of_vertices(void *data, int *ierr)
{
HGRAPH_DATA *hg = (HGRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
return hg->numMyVertices;
}
static void get_vertex_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr)
{
int i;
HGRAPH_DATA *hg= (HGRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
/* In this example, return the IDs of our vertices, but no weights.
* Zoltan will assume equally weighted vertices.
*/
for (i=0; i<hg->numMyVertices; i++){
globalID[i] = hg->vtxGID[i];
localID[i] = i;
}
}
static void get_hypergraph_size(void *data, int *num_lists, int *num_nonzeroes,
int *format, int *ierr)
{
HGRAPH_DATA *hg = (HGRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
*num_lists = hg->numMyHEdges;
*num_nonzeroes = hg->numAllNbors;
/* We will provide compressed hyperedge (row) format. The alternative is
* is compressed vertex (column) format: ZOLTAN_COMPRESSED_VERTEX.
*/
*format = ZOLTAN_COMPRESSED_EDGE;
return;
}
static void get_hypergraph(void *data, int sizeGID, int num_edges, int num_nonzeroes,
int format, ZOLTAN_ID_PTR edgeGID, int *vtxPtr,
ZOLTAN_ID_PTR vtxGID, int *ierr)
{
int i;
HGRAPH_DATA *hg = (HGRAPH_DATA *)data;
*ierr = ZOLTAN_OK;
if ( (num_edges != hg->numMyHEdges) || (num_nonzeroes != hg->numAllNbors) ||
(format != ZOLTAN_COMPRESSED_EDGE)) {
*ierr = ZOLTAN_FATAL;
return;
}
for (i=0; i < num_edges; i++){
edgeGID[i] = hg->edgeGID[i];
vtxPtr[i] = hg->nborIndex[i];
}
for (i=0; i < num_nonzeroes; i++){
vtxGID[i] = hg->nborGID[i];
}
return;
}
/* Function to find next line of information in input file */
static int get_next_line(FILE *fp, char *buf, int bufsize)
{
int i, cval, len;
char *c;
while (1){
c = fgets(buf, bufsize, fp);
if (c == NULL)
return 0; /* end of file */
len = strlen(c);
for (i=0, c=buf; i < len; i++, c++){
cval = (int)*c;
if (isspace(cval) == 0) break;
}
if (i == len) continue; /* blank line */
if (*c == '#') continue; /* comment */
if (c != buf){
strcpy(buf, c);
}
break;
}
return strlen(buf); /* number of characters */
}
/* Function to return the list of non-negative integers in a line */
static int get_line_ints(char *buf, int bufsize, int *vals)
{
char *c = buf;
int count=0;
while (1){
while (!(isdigit(*c))){
if ((c - buf) >= bufsize) break;
c++;
}
if ( (c-buf) >= bufsize) break;
vals[count++] = atoi(c);
while (isdigit(*c)){
if ((c - buf) >= bufsize) break;
c++;
}
if ( (c-buf) >= bufsize) break;
}
return count;
}
/* Proc 0 notifies others of error and exits */
static void input_file_error(int numProcs, int tag, int startProc)
{
int i, val[3];
val[0] = -1; /* error flag */
fprintf(stderr,"ERROR in input file.\n");
for (i=startProc; i < numProcs; i++){
/* these procs have posted a receive for "tag" expecting counts */
MPI_Send(val, 3, MPI_INT, i, tag, MPI_COMM_WORLD);
}
for (i=1; i < startProc; i++){
/* these procs are done and waiting for ok-to-go */
MPI_Send(val, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
exit(1);
}
/* Draw the partition assignments of the objects */
static void showHypergraph(int myProc, int numProcs, int numIDs, ZOLTAN_ID_TYPE *GIDs, int *parts)
{
int *partAssign, *allPartAssign;
int i, j, part, count, numVtx, numEdges;
int edgeIdx, vtxIdx;
int maxPart, nPart, partIdx;
int **M;
int *partNums, *partCount;
ZOLTAN_ID_TYPE *nextID;
ZOLTAN_ID_TYPE edgeID, vtxID;
int cutn, cutl;
float imbal, localImbal;
numVtx = global_hg.numGlobalVertices;
numEdges = global_hg.numGlobalEdges;
partAssign = (int *)calloc(sizeof(int), numVtx);
allPartAssign = (int *)calloc(sizeof(int), numVtx);
for (i=0; i < numIDs; i++){
partAssign[GIDs[i]-1] = parts[i];
}
MPI_Reduce(partAssign, allPartAssign, numVtx, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
free(partAssign);
if (myProc > 0){
free(allPartAssign);
return;
}
/* Creating a dense matrix containing hyperedges, because this is small
* example problem, and it is simpler.
*/
M = (int **)calloc(sizeof(int *) , numEdges);
for (i=0; i < numEdges; i++){
M[i] = (int *)calloc(sizeof(int) , numVtx);
}
nextID = global_hg.nborGID;
maxPart = 0;
for (i=0; i < numEdges; i++){
edgeID = global_hg.edgeGID[i];
edgeIdx = (int)edgeID - 1;
count = global_hg.nborIndex[i+1] - global_hg.nborIndex[i];
for (j=0; j < count; j++){
vtxID = *nextID++;
vtxIdx = (int)vtxID - 1;
part = allPartAssign[vtxIdx];
if (part > maxPart) maxPart = part;
M[edgeIdx][vtxIdx] = part+1;
}
}
/* Calculate vertex balance measure 1.0 is perfect, higher is worse */
imbal = 0;
partCount = (int *)calloc(sizeof(int), maxPart+1);
for (i=0; i < numVtx; i++){
partCount[allPartAssign[i]]++;
}
imbal = 0.0;
for (part=0; part <= maxPart; part++){
localImbal = (float)(numProcs * partCount[part]) / (float)numVtx;
if (localImbal > imbal) imbal = localImbal;
}
free(partCount);
free(allPartAssign);
/* Print the hypergraph as a matrix */
printf("\n VERTICES\n ");
for (j=0; j < numVtx; j++){
if (j < 9)
printf("%d ",j+1);
else
printf("%d ",j+1);
}
printf(" NPARTS-1");
printf("\n ");
for (j=0; j < numVtx; j++){
printf("---");
}
printf("\n");
partNums = (int *)calloc(sizeof(int), maxPart + 1);
cutn = 0;
cutl = 0;
for (i=0; i < numEdges; i++){
nPart = 0;
if (i < 9)
printf("%d ",i+1);
else
printf("%d ",i+1);
for (j=0; j < numVtx; j++){
part = M[i][j];
partIdx = part - 1;
if (part > 0){
printf("%d ",partIdx);
if (partNums[partIdx] < i+1){
nPart++;
partNums[partIdx] = i+1;
}
}
else{
printf(" ");
}
}
if (nPart >= 2){
printf(" %d\n",nPart - 1);
cutn++;
cutl += (nPart - 1);
}
else{
printf("\n");
}
}
printf("Total number of cut edges: %d\n",cutn);
printf("Sum of NPARTS-1: %d\n",cutl);
printf("Balance of vertices across partitions: %f\n",imbal);
printf("\n");
for (i=0; i < numEdges; i++){
free(M[i]);
}
free(M);
free(partNums);
}
/*
* Read the hypergraph in the input file and distribute the non-zeroes. (See the
* matrix analogy at the top of the source file.)
*
* We will distribute the hyperedges (rows) to the processes. However, we could
* distribute the vertices (columns), or we could distribute the non-zeroes
* instead.
*
* Zoltan partitions the vertices, so we also create an initial partitioning of the vertices.
*/
void read_input_file(int myRank, int numProcs, char *fname, HGRAPH_DATA *hg)
{
char buf[512];
int bufsize;
int numGlobalVertices, numGlobalEdges, numGlobalNZ;
int num, count, nnbors, ack=0;
int to=-1, from, remaining;
int vGID;
int i, j;
int vals[128], send_count[3];
ZOLTAN_ID_TYPE *idx;
unsigned int id;
FILE *fp;
MPI_Status status;
int ack_tag = 5, count_tag = 10, id_tag = 15;
HGRAPH_DATA *send_hg;
if (myRank == 0){
bufsize = 512;
fp = fopen(fname, "r");
/* Get the number of vertices */
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalVertices);
if (num != 1) input_file_error(numProcs, count_tag, 1);
global_hg.numGlobalVertices = numGlobalVertices;
global_hg.numMyVertices = numGlobalVertices;
global_hg.vtxGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * numGlobalVertices);
/* Get the vertex global IDs */
for (i=0; i < numGlobalVertices; i++){
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &vGID);
if (num != 1) input_file_error(numProcs, count_tag, 1);
global_hg.vtxGID[i] = (ZOLTAN_ID_TYPE)vGID;
}
/* Get the number hyperedges which contain those vertices */
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalEdges);
if (num != 1) input_file_error(numProcs, count_tag, 1);
global_hg.numGlobalEdges = numGlobalEdges;
global_hg.numMyHEdges = numGlobalEdges;
global_hg.edgeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * numGlobalEdges);
global_hg.nborIndex = (int *)malloc(sizeof(int) * (numGlobalEdges + 1));
/* Get the total number of vertices or neighbors in all the hyperedges of
* the hypergraph. Or get the number of non-zeroes in the matrix representing
* the hypergraph.
*/
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &numGlobalNZ);
if (num != 1) input_file_error(numProcs, count_tag, 1);
global_hg.nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * numGlobalNZ);
/* Get the list of vertices in each hyperedge */
global_hg.nborIndex[0] = 0;
for (i=0; i < numGlobalEdges; i++){
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = get_line_ints(buf, bufsize, vals);
if (num < 2) input_file_error(numProcs, count_tag, 1);
id = vals[0];
nnbors = vals[1];
if (num < (nnbors + 2)) input_file_error(numProcs, count_tag, 1);
global_hg.edgeGID[i] = (ZOLTAN_ID_TYPE)id;
for (j=0; j < nnbors; j++){
global_hg.nborGID[global_hg.nborIndex[i] + j] = (ZOLTAN_ID_TYPE)vals[2 + j];
}
global_hg.nborIndex[i+1] = global_hg.nborIndex[i] + nnbors;
}
fclose(fp);
/* Create a sub graph for each process */
send_hg = (HGRAPH_DATA *)calloc(sizeof(HGRAPH_DATA) , numProcs);
/*
* Divide the vertices across the processes
*/
remaining = numGlobalVertices;
count = (numGlobalVertices / numProcs) + 1;
idx = global_hg.vtxGID;
for (i=0; i < numProcs; i++){
if (remaining == 0) count = 0;
if (count > remaining) count = remaining;
send_hg[i].numMyVertices = count;
if (count){
send_hg[i].vtxGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * count);
for (j=0; j < count; j++){
send_hg[i].vtxGID[j] = *idx++;
}
}
remaining -= count;
}
/*
* Assign hyperedges to processes, and create a sub-hypergraph for each process.
*/
remaining = numGlobalEdges;
count = (numGlobalEdges / numProcs) + 1;
from = 0;
for (i=0; i < numProcs; i++){
if (remaining == 0) count = 0;
if (count > remaining) count = remaining;
send_hg[i].numMyHEdges = count;
send_hg[i].numAllNbors = 0;
if (count > 0){
to = from + count;
nnbors = global_hg.nborIndex[to] - global_hg.nborIndex[from];
send_hg[i].numAllNbors = nnbors;
send_hg[i].edgeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * count);
memcpy(send_hg[i].edgeGID, global_hg.edgeGID + from, sizeof(ZOLTAN_ID_TYPE) * count);
send_hg[i].nborIndex = (int *)malloc(sizeof(int) * (count + 1));
send_hg[i].nborIndex[0] = 0;
if (nnbors > 0){
num = global_hg.nborIndex[from];
for (j=1; j <= count; j++){
send_hg[i].nborIndex[j] = global_hg.nborIndex[from+j] - num;
}
send_hg[i].nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * nnbors);
memcpy(send_hg[i].nborGID,
global_hg.nborGID + global_hg.nborIndex[from],
sizeof(ZOLTAN_ID_TYPE) * nnbors);
}
}
remaining -= count;
from = to;
}
/* Send each process its hyperedges and the vertices in its partition */
*hg = send_hg[0];
for (i=1; i < numProcs; i++){
send_count[0] = send_hg[i].numMyVertices;
send_count[1] = send_hg[i].numMyHEdges;
send_count[2] = send_hg[i].numAllNbors;
MPI_Send(send_count, 3, MPI_INT, i, count_tag, MPI_COMM_WORLD);
MPI_Recv(&ack, 1, MPI_INT, i, ack_tag, MPI_COMM_WORLD, &status);
if (send_count[0] > 0){
MPI_Send(send_hg[i].vtxGID, send_count[0], ZOLTAN_ID_MPI_TYPE, i, id_tag, MPI_COMM_WORLD);
free(send_hg[i].vtxGID);
}
if (send_count[1] > 0){
MPI_Send(send_hg[i].edgeGID, send_count[1], ZOLTAN_ID_MPI_TYPE, i, id_tag + 1, MPI_COMM_WORLD);
free(send_hg[i].edgeGID);
MPI_Send(send_hg[i].nborIndex, send_count[1] + 1, MPI_INT, i, id_tag + 2, MPI_COMM_WORLD);
free(send_hg[i].nborIndex);
if (send_count[2] > 0){
MPI_Send(send_hg[i].nborGID, send_count[2], ZOLTAN_ID_MPI_TYPE, i, id_tag + 3, MPI_COMM_WORLD);
free(send_hg[i].nborGID);
}
}
}
free(send_hg);
/* signal all procs it is OK to go on */
ack = 0;
for (i=1; i < numProcs; i++){
MPI_Send(&ack, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
}
else{
MPI_Recv(send_count, 3, MPI_INT, 0, count_tag, MPI_COMM_WORLD, &status);
if (send_count[0] < 0){
MPI_Finalize();
exit(1);
}
ack = 0;
memset(hg, 0, sizeof(HGRAPH_DATA));
hg->numMyVertices = send_count[0];
hg->numMyHEdges = send_count[1];
hg->numAllNbors = send_count[2];
if (send_count[0] > 0){
hg->vtxGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * send_count[0]);
}
if (send_count[1] > 0){
hg->edgeGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * send_count[1]);
hg->nborIndex = (int *)malloc(sizeof(int) * (send_count[1] + 1));
if (send_count[2] > 0){
hg->nborGID = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * send_count[2]);
}
}
MPI_Send(&ack, 1, MPI_INT, 0, ack_tag, MPI_COMM_WORLD);
if (send_count[0] > 0){
MPI_Recv(hg->vtxGID,send_count[0], ZOLTAN_ID_MPI_TYPE, 0, id_tag, MPI_COMM_WORLD, &status);
if (send_count[1] > 0){
MPI_Recv(hg->edgeGID,send_count[1], ZOLTAN_ID_MPI_TYPE, 0, id_tag + 1, MPI_COMM_WORLD, &status);
MPI_Recv(hg->nborIndex,send_count[1] + 1, MPI_INT, 0, id_tag + 2, MPI_COMM_WORLD, &status);
if (send_count[2] > 0){
MPI_Recv(hg->nborGID,send_count[2], ZOLTAN_ID_MPI_TYPE, 0, id_tag + 3, MPI_COMM_WORLD, &status);
}
}
}
/* ok to go on? */
MPI_Recv(&ack, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
if (ack < 0){
MPI_Finalize();
exit(1);
}
}
MPI_Bcast(&(global_hg.numGlobalVertices), 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&(global_hg.numGlobalEdges), 1, MPI_INT, 0, MPI_COMM_WORLD);
}

521
thirdParty/Zoltan/example/C/simpleRCB.c vendored Normal file
View File

@ -0,0 +1,521 @@
/*
* @HEADER
*
* ***********************************************************************
*
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
* Copyright 2012 Sandia Corporation
*
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
* the U.S. Government retains certain rights in this software.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Corporation nor the names of the
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "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 SANDIA CORPORATION OR THE
* CONTRIBUTORS 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.
*
* Questions? Contact Karen Devine kddevin@sandia.gov
* Erik Boman egboman@sandia.gov
*
* ***********************************************************************
*
* @HEADER
*/
/***************************************************************
** Basic example of using Zoltan to compute an RCB partitioning
** of a very simple mesh or graph.
***************************************************************/
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "zoltan.h"
/* Name of file containing the mesh to be partitioned */
static char *global_fname="mesh.txt";
/* Structure to hold mesh data */
typedef struct{
int numGlobalPoints;
int numMyPoints;
ZOLTAN_ID_PTR myGlobalIDs;
float *x;
float *y;
} MESH_DATA;
/* Application defined query functions */
static int get_number_of_objects(void *data, int *ierr);
static void get_object_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr);
static int get_num_geometry(void *data, int *ierr);
static void get_geometry_list(void *data, int sizeGID, int sizeLID,
int num_obj, ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int num_dim, double *geom_vec, int *ierr);
/* read in and display input mesh, handle errors */
static int get_next_line(FILE *fp, char *buf, int bufsize);
static void input_file_error(int numProcs, int tag, int startProc);
void read_input_objects(int myRank, int numProcs, char *fname, MESH_DATA *myData);
void showSimpleMeshPartitions(int myProc, int numIDs, ZOLTAN_ID_PTR IDs, int *parts);
int main(int argc, char *argv[])
{
int rc, i, myRank, numProcs;
float ver;
struct Zoltan_Struct *zz;
int changes, numGidEntries, numLidEntries, numImport, numExport;
ZOLTAN_ID_PTR importGlobalGids, importLocalGids, exportGlobalGids, exportLocalGids;
int *importProcs, *importToPart, *exportProcs, *exportToPart;
int *parts;
FILE *fp;
MESH_DATA myMesh;
/******************************************************************
** Initialize MPI and Zoltan
******************************************************************/
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
rc = Zoltan_Initialize(argc, argv, &ver);
if (rc != ZOLTAN_OK){
printf("sorry...\n");
MPI_Finalize();
exit(0);
}
/******************************************************************
** Read geometry from input file and distribute it unevenly
******************************************************************/
fp = fopen(global_fname, "r");
if (!fp){
if (myRank == 0) fprintf(stderr,"ERROR: Can not open %s\n",global_fname);
MPI_Finalize();
exit(1);
}
fclose(fp);
read_input_objects(myRank, numProcs, global_fname, &myMesh);
/******************************************************************
** Create a Zoltan library structure for this instance of load
** balancing. Set the parameters and query functions that will
** govern the library's calculation. See the Zoltan User's
** Guide for the definition of these and many other parameters.
******************************************************************/
zz = Zoltan_Create(MPI_COMM_WORLD);
/* General parameters */
Zoltan_Set_Param(zz, "DEBUG_LEVEL", "1");
Zoltan_Set_Param(zz, "LB_METHOD", "RCB");
Zoltan_Set_Param(zz, "NUM_GID_ENTRIES", "1");
Zoltan_Set_Param(zz, "NUM_LID_ENTRIES", "1");
Zoltan_Set_Param(zz, "OBJ_WEIGHT_DIM", "0");
Zoltan_Set_Param(zz, "RETURN_LISTS", "ALL");
/* RCB parameters */
Zoltan_Set_Param(zz, "RCB_OUTPUT_LEVEL", "0");
Zoltan_Set_Param(zz, "RCB_RECTILINEAR_BLOCKS", "1");
/*Zoltan_Set_Param(zz, "RCB_RECTILINEAR_BLOCKS", "0"); */
/* Query functions, to provide geometry to Zoltan */
Zoltan_Set_Num_Obj_Fn(zz, get_number_of_objects, &myMesh);
Zoltan_Set_Obj_List_Fn(zz, get_object_list, &myMesh);
Zoltan_Set_Num_Geom_Fn(zz, get_num_geometry, &myMesh);
Zoltan_Set_Geom_Multi_Fn(zz, get_geometry_list, &myMesh);
/******************************************************************
** Zoltan can now partition the vertices in the simple mesh.
** In this simple example, we assume the number of partitions is
** equal to the number of processes. Process rank 0 will own
** partition 0, process rank 1 will own partition 1, and so on.
******************************************************************/
rc = Zoltan_LB_Partition(zz, /* input (all remaining fields are output) */
&changes, /* 1 if partitioning was changed, 0 otherwise */
&numGidEntries, /* Number of integers used for a global ID */
&numLidEntries, /* Number of integers used for a local ID */
&numImport, /* Number of vertices to be sent to me */
&importGlobalGids, /* Global IDs of vertices to be sent to me */
&importLocalGids, /* Local IDs of vertices to be sent to me */
&importProcs, /* Process rank for source of each incoming vertex */
&importToPart, /* New partition for each incoming vertex */
&numExport, /* Number of vertices I must send to other processes*/
&exportGlobalGids, /* Global IDs of the vertices I must send */
&exportLocalGids, /* Local IDs of the vertices I must send */
&exportProcs, /* Process to which I send each of the vertices */
&exportToPart); /* Partition to which each vertex will belong */
if (rc != ZOLTAN_OK){
printf("sorry...\n");
MPI_Finalize();
Zoltan_Destroy(&zz);
exit(0);
}
/******************************************************************
** Visualize the mesh partitioning before and after calling Zoltan.
******************************************************************/
parts = (int *)malloc(sizeof(int) * myMesh.numMyPoints);
for (i=0; i < myMesh.numMyPoints; i++){
parts[i] = myRank;
}
if (myRank== 0){
printf("\nMesh partition assignments before calling Zoltan\n");
}
showSimpleMeshPartitions(myRank, myMesh.numMyPoints, myMesh.myGlobalIDs, parts);
for (i=0; i < numExport; i++){
parts[exportLocalGids[i]] = exportToPart[i];
}
if (myRank == 0){
printf("Mesh partition assignments after calling Zoltan\n");
}
showSimpleMeshPartitions(myRank, myMesh.numMyPoints, myMesh.myGlobalIDs, parts);
free(parts);
/******************************************************************
** Free the arrays allocated by Zoltan_LB_Partition, and free
** the storage allocated for the Zoltan structure.
******************************************************************/
Zoltan_LB_Free_Part(&importGlobalGids, &importLocalGids,
&importProcs, &importToPart);
Zoltan_LB_Free_Part(&exportGlobalGids, &exportLocalGids,
&exportProcs, &exportToPart);
Zoltan_Destroy(&zz);
/**********************
** all done ***********
**********************/
MPI_Finalize();
if (myMesh.numMyPoints > 0){
free(myMesh.myGlobalIDs);
free(myMesh.x);
free(myMesh.y);
}
return 0;
}
/* Application defined query functions */
static int get_number_of_objects(void *data, int *ierr)
{
MESH_DATA *mesh= (MESH_DATA *)data;
*ierr = ZOLTAN_OK;
return mesh->numMyPoints;
}
static void get_object_list(void *data, int sizeGID, int sizeLID,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int wgt_dim, float *obj_wgts, int *ierr)
{
int i;
MESH_DATA *mesh= (MESH_DATA *)data;
*ierr = ZOLTAN_OK;
/* In this example, return the IDs of our objects, but no weights.
* Zoltan will assume equally weighted objects.
*/
for (i=0; i<mesh->numMyPoints; i++){
globalID[i] = mesh->myGlobalIDs[i];
localID[i] = i;
}
}
static int get_num_geometry(void *data, int *ierr)
{
*ierr = ZOLTAN_OK;
return 2;
}
static void get_geometry_list(void *data, int sizeGID, int sizeLID,
int num_obj,
ZOLTAN_ID_PTR globalID, ZOLTAN_ID_PTR localID,
int num_dim, double *geom_vec, int *ierr)
{
int i;
MESH_DATA *mesh= (MESH_DATA *)data;
if ( (sizeGID != 1) || (sizeLID != 1) || (num_dim != 2)){
*ierr = ZOLTAN_FATAL;
return;
}
*ierr = ZOLTAN_OK;
for (i=0; i < num_obj ; i++){
geom_vec[2*i] = (double)mesh->x[i];
geom_vec[2*i + 1] = (double)mesh->y[i];
}
return;
}
static int get_next_line(FILE *fp, char *buf, int bufsize)
{
int i, cval, len;
char *c;
while (1){
c = fgets(buf, bufsize, fp);
if (c == NULL)
return 0; /* end of file */
len = strlen(c);
for (i=0, c=buf; i < len; i++, c++){
cval = (int)*c;
if (isspace(cval) == 0) break;
}
if (i == len) continue; /* blank line */
if (*c == '#') continue; /* comment */
if (c != buf){
strcpy(buf, c);
}
break;
}
return strlen(buf); /* number of characters */
}
/* Proc 0 notifies others of error and exits */
static void input_file_error(int numProcs, int tag, int startProc)
{
int i, val;
val = -1;
fprintf(stderr,"ERROR in input file.\n");
for (i=startProc; i < numProcs; i++){
/* these procs have posted receive for "tag" */
MPI_Send(&val, 1, MPI_INT, i, tag, MPI_COMM_WORLD);
}
for (i=1; i < startProc; i++){
/* these procs are done */
MPI_Send(&val, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
exit(1);
}
/* Proc 0 reads the points in the input file and divides them across processes */
void read_input_objects(int myRank, int numProcs, char *fname, MESH_DATA *myMesh)
{
char *buf;
int bufsize = 512;
int num, nobj, remaining, ack=0;
int i, j;
ZOLTAN_ID_PTR gids;
float *xcoord, *ycoord;
FILE *fp;
MPI_Status status;
int ack_tag = 5, count_tag = 10, id_tag = 15;
int x_tag = 20, y_tag = 25;
if (myRank == 0){
buf = (char *)malloc(sizeof(char) * bufsize);
fp = fopen(fname, "r");
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, "%d", &myMesh->numGlobalPoints);
if (num != 1) input_file_error(numProcs, count_tag, 1);
if (numProcs > 1){
nobj = myMesh->numGlobalPoints / 2;
remaining = myMesh->numGlobalPoints - nobj;
}
else{
nobj = myMesh->numGlobalPoints;
remaining = 0;
}
myMesh->myGlobalIDs = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * nobj);
myMesh->x = (float *)malloc(sizeof(float) * nobj);
myMesh->y = (float *)malloc(sizeof(float) * nobj);
myMesh->numMyPoints= nobj;
for (i=0; i < nobj; i++){
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, 1);
num = sscanf(buf, ZOLTAN_ID_SPEC "%f %f", myMesh->myGlobalIDs + i,
myMesh->x + i, myMesh->y + i);
if (num != 3) input_file_error(numProcs, count_tag, 1);
}
gids = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * (nobj + 1));
xcoord = (float *)malloc(sizeof(float) * (nobj + 1));
ycoord = (float *)malloc(sizeof(float) * (nobj + 1));
for (i=1; i < numProcs; i++){
if (remaining > 1){
nobj = remaining / 2;
remaining -= nobj;
}
else if (remaining == 1){
nobj = 1;
remaining = 0;
}
else{
nobj = 0;
}
if ((i == numProcs - 1) && (remaining > 0))
nobj += remaining;
if (nobj > 0){
for (j=0; j < nobj; j++){
num = get_next_line(fp, buf, bufsize);
if (num == 0) input_file_error(numProcs, count_tag, i);
num = sscanf(buf, ZOLTAN_ID_SPEC "%f %f", gids+j, xcoord+j, ycoord+j);
if (num != 3) input_file_error(numProcs, count_tag, i);
}
}
MPI_Send(&nobj, 1, MPI_INT, i, count_tag, MPI_COMM_WORLD);
MPI_Recv(&ack, 1, MPI_INT, i, ack_tag, MPI_COMM_WORLD, &status);
if (nobj > 0){
MPI_Send(gids, nobj, ZOLTAN_ID_MPI_TYPE, i, id_tag, MPI_COMM_WORLD);
MPI_Send(xcoord, nobj, MPI_FLOAT, i, x_tag, MPI_COMM_WORLD);
MPI_Send(ycoord, nobj, MPI_FLOAT, i, y_tag, MPI_COMM_WORLD);
}
}
free(gids);
free(xcoord);
free(ycoord);
fclose(fp);
free(buf);
/* signal all procs it is OK to go on */
ack = 0;
for (i=1; i < numProcs; i++){
MPI_Send(&ack, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
}
else{
MPI_Recv(&myMesh->numMyPoints, 1, MPI_INT, 0, count_tag, MPI_COMM_WORLD, &status);
ack = 0;
if (myMesh->numMyPoints > 0){
myMesh->myGlobalIDs = (ZOLTAN_ID_TYPE *)malloc(sizeof(ZOLTAN_ID_TYPE) * myMesh->numMyPoints);
myMesh->x = (float *)malloc(sizeof(float) * myMesh->numMyPoints);
myMesh->y = (float *)malloc(sizeof(float) * myMesh->numMyPoints);
MPI_Send(&ack, 1, MPI_INT, 0, ack_tag, MPI_COMM_WORLD);
MPI_Recv(myMesh->myGlobalIDs, myMesh->numMyPoints, ZOLTAN_ID_MPI_TYPE, 0,
id_tag, MPI_COMM_WORLD, &status);
MPI_Recv(myMesh->x, myMesh->numMyPoints, MPI_FLOAT, 0,
x_tag, MPI_COMM_WORLD, &status);
MPI_Recv(myMesh->y, myMesh->numMyPoints, MPI_FLOAT, 0,
y_tag, MPI_COMM_WORLD, &status);
}
else if (myMesh->numMyPoints == 0){
MPI_Send(&ack, 1, MPI_INT, 0, ack_tag, MPI_COMM_WORLD);
}
else{
MPI_Finalize();
exit(1);
}
MPI_Recv(&ack, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
if (ack < 0){
MPI_Finalize();
exit(1);
}
}
}
void showSimpleMeshPartitions(int myProc, int numIDs, ZOLTAN_ID_PTR GIDs, int *parts)
{
int partAssign[25], allPartAssign[25];
int i, j, part;
memset(partAssign, 0, sizeof(int) * 25);
for (i=0; i < numIDs; i++){
partAssign[GIDs[i]-1] = parts[i];
}
MPI_Reduce(partAssign, allPartAssign, 25, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
if (myProc == 0){
for (i=20; i >= 0; i-=5){
for (j=0; j < 5; j++){
part = allPartAssign[i + j];
if (j < 4)
printf("%d-----",part);
else
printf("%d\n",part);
}
if (i > 0)
printf("| | | | |\n");
}
printf("\n");
}
}