summaryrefslogtreecommitdiff
path: root/var/spack/repos/builtin/packages/sprng/package.py
blob: 4c014a3b8ad10e5489d2641720330b69066b5f1c (plain) (blame)
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# Copyright 2013-2024 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)


from spack.package import *


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"

    license("GPL-2.0-only")

    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)