Newer
Older
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
#
# This file is part of EasyBuild,
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
# with support of Ghent University (http://ugent.be/hpc),
# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
#
# https://github.com/easybuilders/easybuild
#
# EasyBuild is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation v2.
#
# EasyBuild is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
##
"""
EasyBuild support for building and installing WIEN2k, implemented as an easyblock
@author: Stijn De Weirdt (Ghent University)
@author: Dries Verdegem (Ghent University)
@author: Kenneth Hoste (Ghent University)
@author: Pieter De Baets (Ghent University)
@author: Jens Timmerman (Ghent University)
@author: Michael Sluydts (Ghent University)
"""
import fileinput
import os
import re
import shutil
import sys
import tempfile
from distutils.version import LooseVersion
import easybuild.tools.environment as env
import easybuild.tools.toolchain as toolchain
from easybuild.framework.easyblock import EasyBlock
from easybuild.framework.easyconfig import CUSTOM
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.filetools import apply_regex_substitutions, change_dir, extract_file, mkdir, read_file
from easybuild.tools.filetools import remove_dir, write_file
from easybuild.tools.modules import get_software_root, get_software_version
from easybuild.tools.run import run_cmd, run_cmd_qa
class EB_WIEN2k(EasyBlock):
"""Support for building/installing WIEN2k."""
def __init__(self, *args, **kwargs):
"""Enable building in install dir."""
super(EB_WIEN2k, self).__init__(*args, **kwargs)
self.build_in_installdir = True
@staticmethod
def extra_options():
testdata_urls = ["http://www.wien2k.at/reg_user/benchmark/test_case.tar.gz",
"http://www.wien2k.at/reg_user/benchmark/mpi-benchmark.tar.gz"]
extra_vars = {
'runtest': [True, "Run WIEN2k tests", CUSTOM],
'testdata': [testdata_urls, "test data URL for WIEN2k benchmark test", CUSTOM],
'wien_mpirun': [None, "MPI wrapper command to use", CUSTOM],
'remote': [None, "Remote command to use (e.g. pbsssh, ...)", CUSTOM],
'use_remote': [True, "Whether to remotely login to initiate the k-point parallellization calls", CUSTOM],
'mpi_remote': [False, "Whether to initiate MPI calls locally or remotely", CUSTOM],
'wien_granularity': [True, "Granularity for parallel execution (see manual)", CUSTOM],
'taskset': [None, "Specifies an optional command for binding a process to a specific core", CUSTOM],
'nmatmax': [19000, "Specifies the maximum matrix size", CUSTOM],
'nume': [6000, "Specifies the number of states to output.", CUSTOM],
}
return EasyBlock.extra_options(extra_vars)
def extract_step(self):
"""Unpack WIEN2k sources using gunzip and provided expand_lapw script."""
super(EB_WIEN2k, self).extract_step()
cmd = "gunzip *gz"
run_cmd(cmd, log_all=True, simple=True)
cmd = "./expand_lapw"
qanda = {'continue (y/n)': 'y'}
no_qa = [
run_cmd_qa(cmd, qanda, no_qa=no_qa, log_all=True, simple=True)
def configure_step(self):
"""Configure WIEN2k build by patching siteconfig_lapw script and running it."""
self.cfgscript = "siteconfig_lapw"
# patch config file first
# toolchain-dependent values
comp_answer = None
if self.toolchain.comp_family() == toolchain.INTELCOMP: # @UndefinedVariable
if get_software_root('icc'):
intelver = get_software_version('icc')
elif get_software_root('intel-compilers'):
intelver = get_software_version('intel-compilers')
if LooseVersion(intelver) >= LooseVersion("2011"):
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
if LooseVersion(self.version) < LooseVersion("17"):
comp_answer = 'I' # Linux (Intel ifort 12.0 compiler + mkl )
else:
comp_answer = 'LI' # Linux (Intel ifort compiler (12.0 or later)+mkl+intelmpi))
else:
comp_answer = "K1" # Linux (Intel ifort 11.1 compiler + mkl )
elif self.toolchain.comp_family() == toolchain.GCC: # @UndefinedVariable
if LooseVersion(self.version) < LooseVersion("17"):
comp_answer = 'V' # Linux (gfortran compiler + gotolib)
else:
comp_answer = 'LG' # Linux (gfortran compiler + OpenBlas)
else:
raise EasyBuildError("Failed to determine toolchain-dependent answers.")
# libraries
liblapack = os.getenv('LIBLAPACK_MT').replace('static', 'dynamic')
libscalapack = os.getenv('LIBSCALAPACK_MT').replace('static', 'dynamic')
rlibs = "%s %s" % (liblapack, self.toolchain.get_flag('openmp'))
rplibs = [libscalapack, liblapack]
fftwver = get_software_version('FFTW')
if fftwver:
suff = ''
if LooseVersion(fftwver) >= LooseVersion("3"):
suff = '3'
rplibs.insert(0, "-lfftw%(suff)s_mpi -lfftw%(suff)s" % {'suff': suff})
else:
rplibs.append(os.getenv('LIBFFT'))
rplibs = ' '.join(rplibs)
vars = {
'FC': '%s' % os.getenv('F90'),
'FOPT': '%s' % os.getenv('FFLAGS'),
'MPF': '%s' % os.getenv('MPIF90'),
'FPOPT': '%s' % os.getenv('FFLAGS'),
'CC': os.getenv('CC'),
'LDFLAGS': '$(FOPT) %s ' % os.getenv('LDFLAGS'),
'R_LIBS': rlibs, # libraries for 'real' (not 'complex') binary
'RP_LIBS': rplibs, # libraries for 'real' parallel binary
'MPIRUN': '',
}
for line in fileinput.input(self.cfgscript, inplace=1, backup='.orig'):
# set config parameters
for (key, val) in vars.items():
regexp = re.compile('^([a-z0-9]+):%s:(.*)' % key)
res = regexp.search(line)
if res:
# we need to exclude the lines with 'current', otherwise we break the script
if not res.group(1) == "current":
if 'OPT' in key:
# append instead of replace
line = regexp.sub('\\1:%s:%s %s' % (key, res.group(2), val), line)
else:
line = regexp.sub('\\1:%s:%s' % (key, val), line)
# avoid exit code > 0 at end of configuration
sys.stdout.write(line)
# set correct compilers
env.setvar('bin', os.getcwd())
dc = {
'COMPILERC': os.getenv('CC'),
'COMPILER': os.getenv('F90'),
'COMPILERP': os.getenv('MPIF90'),
}
if LooseVersion(self.version) < LooseVersion("17"):
for (key, val) in dc.items():
write_file(key, val)
else:
dc['cc'] = dc.pop('COMPILERC')
dc['fortran'] = dc.pop('COMPILER')
dc['parallel'] = dc.pop('COMPILERP')
write_file('WIEN2k_COMPILER', '\n'.join(['%s:%s' % (k, v) for k, v in dc.items()]))
# configure with patched configure script
self.log.debug('%s part I (configure)' % self.cfgscript)
if LooseVersion(self.version) >= LooseVersion('21'):
perlroot = get_software_root('Perl')
if perlroot is None:
raise EasyBuildError("Perl is a required dependency of WIEN2k as of version 21")
self.perlbin = os.path.join(perlroot, 'bin', 'perl')
else:
self.perlbin = ''
cmd = "./%s" % self.cfgscript
qanda = {
'Press RETURN to continue': '',
'Your compiler:': '',
'Hit Enter to continue': '',
'Remote shell (default is ssh) =': '',
'Remote copy (default is scp) =': '',
'and you need to know details about your installed mpi ..) (y/n)': 'y',
'Q to quit Selection:': 'Q',
'A Compile all programs (suggested) Q Quit Selection:': 'Q',
'Please enter the full path of the perl program: ': self.perlbin,
'continue or stop (c/s)': 'c',
'(like taskset -c). Enter N / your_specific_command:': 'N',
}
if LooseVersion(self.version) >= LooseVersion("13"):
fftw_root = get_software_root('FFTW')
if fftw_root:
fftw_maj = get_software_version('FFTW').split('.')[0]
fftw_spec = 'FFTW%s' % fftw_maj
else:
raise EasyBuildError("Required FFTW dependency is missing")
qanda.update({
') Selection:': comp_answer,
'Shared Memory Architecture? (y/N):': 'N',
'Set MPI_REMOTE to 0 / 1:': '0',
'You need to KNOW details about your installed MPI and FFTW ) (y/n)': 'y',
'Do you want to use FFTW (recommended, but for sequential code not required)? (Y,n):': 'y',
'Please specify whether you want to use FFTW3 (default) or FFTW2 (FFTW3 / FFTW2):': fftw_spec,
'Please specify the ROOT-path of your FFTW installation (like /opt/fftw3):': fftw_root,
'is this correct? enter Y (default) or n:': 'Y',
})
libxcroot = get_software_root('libxc')
if LooseVersion(self.version) < LooseVersion("17"):
libxcstr1 = ' before'
libxcstr3 = ''
elif LooseVersion(self.version) > LooseVersion("19"):
libxcstr1 = ' - usually not needed'
libxcstr3 = 'root-'
else:
libxcstr1 = ''
libxcstr3 = ''
if LooseVersion(self.version) > LooseVersion("23"):
libxcquestion1 = 'Would you like to use LIBXC (needed ONLY for self-consistent gKS mGGA calculations, for the stress tensor and experts who want to play with different DFT options. It must have been installed before)? (y,N): '
else:
libxcquestion1 = 'LIBXC (that you have installed%s)? (y,N):' % libxcstr1
libxcquestion2 = 'Do you want to automatically search for LIBXC installations? (Y,n):'
libxcquestion3 = 'Please enter the %sdirectory of your LIBXC-installation!:' % libxcstr3
libxcquestion4 = 'Please enter the lib-directory of your LIBXC-installation (usually lib or lib64)!:'
libxcquestion5 = 'LIBXC (usually not needed, ONLY for experts who want to play with different DFT options. '
libxcquestion5 += 'It must have been installed before)? (y,N):'
libxcquestion1: 'y',
libxcquestion2: 'n',
libxcquestion3: libxcroot,
libxcquestion4: 'lib',
libxcquestion5: 'y',
if LooseVersion(self.version) >= LooseVersion("17"):
scalapack_libs = os.getenv('LIBSCALAPACK').split()
scalapack = next((lib[2:] for lib in scalapack_libs if 'scalapack' in lib), 'scalapack')
blacs = next((lib[2:] for lib in scalapack_libs if 'blacs' in lib), 'openblas')
qanda.update({
'You need to KNOW details about your installed MPI, ELPA, and FFTW ) (y/N)': 'y',
'Do you want to use a present ScaLAPACK installation? (Y,n):': 'y',
'Do you want to use the MKL version of ScaLAPACK? (Y,n):': 'n', # we set it ourselves below
'Do you use Intel MPI? (Y,n):': 'y',
'Is this correct? (Y,n):': 'y',
'Please specify the target architecture of your ScaLAPACK libraries (e.g. intel64)!:': '',
'ScaLAPACK root:': os.getenv('MKLROOT') or os.getenv('EBROOTSCALAPACK'),
'ScaLAPACK library:': scalapack,
'BLACS root:': os.getenv('MKLROOT') or os.getenv('EBROOTOPENBLAS'),
'BLACS library:': blacs,
'Please enter your choice of additional libraries!:': '',
'Do you want to use a present FFTW installation? (Y,n):': 'y',
'Please specify the path of your FFTW installation (like /opt/fftw3/) '
'or accept present choice (enter):': fftw_root,
'Please specify the target achitecture of your FFTW library (e.g. lib64) '
'or accept present choice (enter):': '',
'Do you want to automatically search for FFTW installations? (Y,n):': 'n',
'Please specify the ROOT-path of your FFTW installation (like /opt/fftw3/) '
'or accept present choice (enter):': fftw_root,
'Is this correct? enter Y (default) or n:': 'Y',
'Please specify the name of your FFTW library or accept present choice (enter):': '',
'or accept the recommendations (Enter - default)!:': '',
# the temporary directory is hardcoded into execution scripts and must exist at runtime
'Please enter the full path to your temporary directory:': '/tmp',
})
elparoot = get_software_root('ELPA')
if elparoot:
apply_regex_substitutions(self.cfgscript, [(r'cat elpahelp2$', 'cat -n elpahelp2')])
elpa_dict = {
'root': elparoot,
'version': get_software_version('ELPA'),
'variant': 'elpa_openmp' if self.toolchain.get_flag('openmp') else 'elpa'}
elpa_dir = "%(root)s/include/%(variant)s-%(version)s" % elpa_dict
std_qa.update({
r".*(?P<number>[0-9]+)\t%s\n(.*\n)*" % elpa_dir: "%(number)s",
})
qanda.update({
'Do you want to use ELPA? (y,N):': 'y',
'Do you want to automatically search for ELPA installations? (Y,n):': 'n',
'Please specify the ROOT-path of your ELPA installation (like /usr/local/elpa/) '
'or accept present path (Enter):': elparoot,
'Please specify the lib-directory of your ELPA installation (e.g. lib or lib64)!:': 'lib',
'Please specify the lib-directory of your ELPA installation (e.g. lib or lib64):': 'lib',
'Please specify the name of your installed ELPA library (e.g. elpa or elpa_openmp)!:':
elpa_dict['variant'],
'Please specify the name of your installed ELPA library (e.g. elpa or elpa_openmp):':
elpa_dict['variant'],
})
else:
qanda.update({'Do you want to use ELPA? (y,N):': 'n'})
else:
qanda.update({
'compiler) Selection:': comp_answer,
'Shared Memory Architecture? (y/n):': 'n',
'If you are using mpi2 set MPI_REMOTE to 0 Set MPI_REMOTE to 0 / 1:': '0',
'Do you have MPI and Scalapack installed and intend to run '
'finegrained parallel? (This is usefull only for BIG cases '
'(50 atoms and more / unit cell) and you need to know details '
'about your installed mpi and fftw ) (y/n)': 'y',
})
no_qa = [
'You have the following mkl libraries in %s :' % os.getenv('MKLROOT'),
"%s[ \t]*.*" % os.getenv('MPIF90'),
"%s[ \t]*.*" % os.getenv('F90'),
"%s[ \t]*.*" % os.getenv('CC'),
".*SRC_.*",
]
r'S\s+Save and Quit[\s\n]+To change an item select option.[\s\n]+Selection:': 'S',
'Recommended setting for parallel f90 compiler: .* Current selection: Your compiler:': os.getenv('MPIF90'),
r'process or you can change single items in "Compiling Options".[\s\n]+Selection:': 'S',
r'A\s+Compile all programs (suggested)[\s\n]+Q\s*Quit[\s\n]+Selection:': 'Q',
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
run_cmd_qa(cmd, qanda, no_qa=no_qa, std_qa=std_qa, log_all=True, simple=True)
# post-configure patches
parallel_options = {}
parallel_options_fp = os.path.join(self.cfg['start_dir'], 'parallel_options')
if self.cfg['wien_mpirun']:
parallel_options.update({'WIEN_MPIRUN': self.cfg['wien_mpirun']})
if self.cfg['taskset'] is None:
self.cfg['taskset'] = 'no'
parallel_options.update({'TASKSET': self.cfg['taskset']})
for opt in ['use_remote', 'mpi_remote', 'wien_granularity']:
parallel_options.update({opt.upper(): int(self.cfg[opt])})
write_file(parallel_options_fp, '\n'.join(['setenv %s "%s"' % tup for tup in parallel_options.items()]))
if self.cfg['remote']:
if self.cfg['remote'] == 'pbsssh':
extratxt = '\n'.join([
'',
"set remote = pbsssh",
"setenv PBSSSHENV 'LD_LIBRARY_PATH PATH'",
'',
])
write_file(parallel_options_fp, extratxt, append=True)
else:
raise EasyBuildError("Don't know how to handle remote %s", self.cfg['remote'])
self.log.debug("Patched file %s: %s", parallel_options_fp, read_file(parallel_options_fp))
# Set configurable parameters for size of problems.
param_subs = [
(r'\s+PARAMETER\s+\(\s*NMATMAX\s*=\s*\d+\)', r' PARAMETER (NMATMAX=%s)' % self.cfg['nmatmax']),
(r'\s+PARAMETER\s+\(\s*NUME\s*=\s*\d+\)', r' PARAMETER (NUME=%s)' % self.cfg['nume']),
]
self.log.debug("param_subs = %s" % param_subs)
apply_regex_substitutions('SRC_lapw1/param.inc', param_subs)
self.log.debug("Patched file %s: %s", 'SRC_lapw1/param.inc', read_file('SRC_lapw1/param.inc'))
def build_step(self):
"""Build WIEN2k by running siteconfig_lapw script again."""
self.log.debug('%s part II (build_step)' % self.cfgscript)
cmd = "./%s" % self.cfgscript
qanda = {
'Press RETURN to continue': '\nQ', # also answer on first qanda pattern with 'Q' to quit
if LooseVersion(self.version) < LooseVersion("17"):
qanda.update({
'L Perl path (if not in /usr/bin/perl) Q Quit Selection:': 'R',
'A Compile all programs S Select program Q Quit Selection:': 'A',
"%s[ \t]*.*" % os.getenv('MPIF90'),
"%s[ \t]*.*" % os.getenv('F90'),
"%s[ \t]*.*" % os.getenv('CC'),
"mv[ \t]*.*",
".*SRC_.*",
".*: warning .*",
".*Stop.",
"Compile time errors (if any) were:",
]
self.log.debug("no_qa for %s: %s" % (cmd, no_qa))
run_cmd_qa(cmd, qanda, no_qa=no_qa, log_all=True, simple=True)
def test_step(self):
"""Run WIEN2k test benchmarks. """
def run_wien2k_test(cmd_arg):
"""Run a WPS command, and check for success."""
cmd = "x_lapw lapw1 %s" % cmd_arg
(out, _) = run_cmd(cmd, log_all=True, simple=False)
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
if not re_success.search(out):
raise EasyBuildError("Test '%s' in %s failed (pattern '%s' not found)?",
cmd, os.getcwd(), re_success.pattern)
else:
self.log.info("Test '%s' seems to have run successfully: %s" % (cmd, out))
if self.cfg['runtest']:
if not self.cfg['testdata']:
raise EasyBuildError("List of URLs for testdata not provided.")
# prepend $PATH with install directory, define $SCRATCH which is used by the tests
env.setvar('PATH', "%s:%s" % (self.installdir, os.environ['PATH']))
try:
cwd = os.getcwd()
# create temporary directory
tmpdir = tempfile.mkdtemp()
os.chdir(tmpdir)
self.log.info("Running tests in %s" % tmpdir)
scratch = os.path.join(tmpdir, 'scratch')
mkdir(scratch)
env.setvar('SCRATCH', scratch)
# download data
testdata_paths = {}
for testdata in self.cfg['testdata']:
td_path = self.obtain_file(testdata)
if not td_path:
raise EasyBuildError("Downloading file from %s failed?", testdata)
testdata_paths.update({os.path.basename(testdata): td_path})
self.log.debug('testdata_paths: %s' % testdata_paths)
# unpack serial benchmark
serial_test_name = "test_case"
srcdir = extract_file(testdata_paths['%s.tar.gz' % serial_test_name], tmpdir, change_into_dir=False)
change_dir(srcdir)
# run serial benchmark
os.chdir(os.path.join(tmpdir, serial_test_name))
run_wien2k_test("-c")
# unpack parallel benchmark (in serial benchmark dir)
parallel_test_name = "mpi-benchmark"
srcdir = extract_file(testdata_paths['%s.tar.gz' % parallel_test_name], tmpdir, change_into_dir=False)
change_dir(srcdir)
# run parallel benchmark
os.chdir(os.path.join(tmpdir, serial_test_name))
run_wien2k_test("-p")
os.chdir(cwd)
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
except OSError as err:
raise EasyBuildError("Failed to run WIEN2k benchmark tests: %s", err)
self.log.debug("Current dir: %s" % os.getcwd())
def test_cases_step(self):
"""Run test cases, if specified."""
for test in self.cfg['tests']:
# check expected format
if not len(test) == 4:
raise EasyBuildError("WIEN2k test case not specified in expected format: "
"(testcase_name, init_lapw_args, run_lapw_args, [scf_regexp_pattern])")
test_name = test[0]
init_args = test[1]
run_args = test[2]
scf_regexp_patterns = test[3]
try:
cwd = os.getcwd()
# WIEN2k enforces that working dir has same name as test case
tmpdir = os.path.join(tempfile.mkdtemp(), test_name)
scratch = os.path.join(tmpdir, 'scratch')
mkdir(scratch, parents=True)
env.setvar('SCRATCH', scratch)
os.chdir(tmpdir)
self.log.info("Running test case %s in %s" % (test_name, tmpdir))
except OSError as err:
raise EasyBuildError("Failed to create temporary directory for test %s: %s", test_name, err)
# try and find struct file for test
test_fp = self.obtain_file("%s.struct" % test_name)
try:
shutil.copy2(test_fp, tmpdir)
except OSError as err:
raise EasyBuildError("Failed to copy %s: %s", test_fp, err)
# run test
cmd = "init_lapw %s" % init_args
run_cmd(cmd, log_all=True, simple=True)
cmd = "run_lapw %s" % run_args
run_cmd(cmd, log_all=True, simple=True)
# check output
scf_fn = "%s.scf" % test_name
self.log.debug("Checking output of test %s in %s" % (str(test), scf_fn))
scftxt = read_file(scf_fn)
for regexp_pat in scf_regexp_patterns:
regexp = re.compile(regexp_pat, re.M)
if not regexp.search(scftxt):
raise EasyBuildError("Failed to find pattern %s in %s", regexp.pattern, scf_fn)
else:
self.log.debug("Found pattern %s in %s" % (regexp.pattern, scf_fn))
# cleanup
try:
os.chdir(cwd)
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
except OSError as err:
raise EasyBuildError("Failed to clean up temporary test dir: %s", err)
def install_step(self):
"""Fix broken symlinks after build/installation."""
# fix broken symlink
os.remove(os.path.join(self.installdir, "SRC_w2web", "htdocs", "usersguide"))
os.symlink(os.path.join(self.installdir, "SRC_usersguide_html"),
os.path.join(self.installdir, "SRC_w2web", "htdocs", "usersguide"))
def sanity_check_step(self):
"""Custom sanity check for WIEN2k."""
lapwfiles = []
for suffix in ['0', '0_mpi', '1', '1_mpi', '1c', '1c_mpi', '2', '2_mpi', '2c', '2c_mpi',
'3', '3c', '5', '5c', '7', '7c', 'dm', 'dmc', 'so']:
p = os.path.join(self.installdir, "lapw%s" % suffix)
lapwfiles.append(p)
custom_paths = {
'files': lapwfiles,
'dirs': [],
}
super(EB_WIEN2k, self).sanity_check_step(custom_paths=custom_paths)
def make_module_extra(self):
"""Set WIENROOT environment variable, and correctly prepend PATH."""
txt = super(EB_WIEN2k, self).make_module_extra()
txt += self.module_generator.set_environment("WIENROOT", self.installdir)
txt += self.module_generator.prepend_paths("PATH", [""])
return txt