Repository: spack/spack

Issue:
Adding sprng package
Sprng is a distributed process-aware random number generator that avoids correlations in random number sequences across processes.

http://www.sprng.org/


Discussion:

Resolving patch:
diff --git a/var/spack/repos/builtin/packages/sprng/package.py b/var/spack/repos/builtin/packages/sprng/package.py
new file mode 100644
--- /dev/null
+++ b/var/spack/repos/builtin/packages/sprng/package.py
@@ -0,0 +1,132 @@
+# Copyright 2013-2019 Lawrence Livermore National Security, LLC and other
+# Spack Project Developers. See the top-level COPYRIGHT file for details.
+#
+# SPDX-License-Identifier: (Apache-2.0 OR MIT)
+
+
+class Sprng(AutotoolsPackage):
+    """SPRNG: A Scalable Library For Pseudorandom Number Generation
+       Sprng is a distributed process-aware random number generator that
+       avoids correlations in random number sequences across processes.
+    """
+
+    maintainers = ['kayarre']
+
+    homepage = "http://www.sprng.org"
+    url      = "http://www.sprng.org/Version5.0/sprng5.tar.bz2"
+
+    version('5.0', sha256='9172a495472cc24893e7489ce9b5654300dc60cba4430e436ce50d28eb749a66')
+
+    variant('mpi', default=True, description='Enable MPI support')
+    variant('fortran', default=False, description='Enable Fortran support')
+
+    depends_on('mpi', when='+mpi')
+
+    def url_for_version(self, version):
+        url = "http://www.sprng.org/Version{0}/sprng{1}.tar.bz2"
+        return url.format(version, version.up_to(1))
+
+    def configure_args(self):
+        configure_args = []
+        configure_args += self.with_or_without('mpi')
+        configure_args += self.with_or_without('fortran')
+
+        if '+mpi' in self.spec:
+            mpi_link_flags = self.spec['mpi:cxx'].libs.link_flags
+            configure_args.append('LIBS={0}'.format(mpi_link_flags))
+            configure_args.append('CC={0}'.format(self.spec['mpi'].mpicc))
+            configure_args.append('CXX={0}'.format(self.spec['mpi'].mpicxx))
+            if '+fortran' in self.spec:
+                configure_args.append('FC={0}'.format(self.spec['mpi'].mpifc))
+        return configure_args
+
+    # TODO: update after solution for virtual depedencies
+    @run_before('configure')
+    def mpicxx_check(self):
+        # print(self.spec['mpi:fortran'].libs.names)
+        if '+mpi' in self.spec:
+            if 'mpi_cxx' not in self.spec['mpi:cxx'].libs.names:
+                msg = 'SPRNG requires a mpi Cxx bindings to build'
+                raise RuntimeError(msg)
+            if '+fortran' in self.spec:
+                if 'fmpi' not in self.spec['fortran'].libs.names:
+                    msg = ('SPRNG requires fortran mpi '
+                           'libraries with mpi enabled')
+                    raise RuntimeError(msg)
+        # raise RuntimeError("test")
+
+    # FIXME: update after features in #15702 are enabled
+    @run_after('build')
+    @on_package_attributes(run_tests=True)
+    def check_build(self):
+
+        def listisclose(a, b, rel_tol=1e-09, abs_tol=1.0e-20):
+            for ai, bi in zip(a, b):
+                if (not abs(ai - bi) <=
+                    max(rel_tol * max(abs(ai), abs(bi)), abs_tol)):
+                    return False
+            return True
+        # Build and run a small program to test the installed sprng library
+        spec = self.spec
+        print("Checking sprng installation...")
+        checkdir = "spack-check"
+        with working_dir(checkdir, create=True):
+            source = r"""
+#include <cstdio>
+#define SIMPLE_SPRNG   /* simple interface                        */
+#include "sprng_cpp.h" /* SPRNG header file                       */
+
+#define SEED 985456376
+
+int main() {
+  int seed = SEED;
+  int i, j;
+  double rn;
+  for(j=0; j < 5; ++j) {
+    init_sprng(seed, SPRNG_DEFAULT, j);
+    for (i=0; i<3; ++i) {
+        rn = sprng();
+        printf("%f ", rn);
+    }
+  }
+  printf("\n");
+  return 0;
+}
+"""
+            expected = [0.504272, 0.558437, 0.000848,
+                        0.707488, 0.664048, 0.005616,
+                        0.060190, 0.415195, 0.933915,
+                        0.085215, 0.456461, 0.244497,
+                        0.626037, 0.917948, 0.135160
+                        ]
+            with open("check.c", 'w') as f:
+                f.write(source)
+            if '+mpi' in spec:
+                cc = Executable(spec['mpi'].mpicxx)
+            else:
+                cc = Executable(self.compiler.cxx)
+            cc(*(['-c', "check.c"] + spec['sprng'].headers.cpp_flags.split()))
+            cc(*(['-o', "check",
+                  "check.o"] + spec['sprng'].libs.ld_flags.split()))
+            try:
+                check = Executable('./check')
+                output = check(output=str)
+            except ProcessError:
+                output = ""
+            out2float = [float(num) for num in output.split(' ')]
+
+            success = listisclose(expected, out2float)
+            if not success:
+                print("Produced output does not match expected output.")
+                print("Expected output:")
+                print('-' * 80)
+                print(expected)
+                print('-' * 80)
+                print("Produced output:")
+                print('-' * 80)
+                print(output)
+                print('-' * 80)
+                raise RuntimeError("sprng install check failed")
+            else:
+                print("test passed")
+        shutil.rmtree(checkdir)


Test patch: