1import config.package 2 3class Configure(config.package.Package): 4 def __init__(self, framework): 5 config.package.Package.__init__(self, framework) 6 self.version = '5.8.2' 7 self.minversion = '5.2.1' 8 self.versionname = 'MUMPS_VERSION' 9 self.requiresversion = 1 10 self.gitcommit = 'v'+self.version 11 self.download = ['https://mumps-solver.org/MUMPS_'+self.version+'.tar.gz', 12 'https://web.cels.anl.gov/projects/petsc/download/externalpackages/MUMPS_'+self.version+'.tar.gz'] 13 self.downloaddirnames = ['petsc-pkg-mumps','MUMPS'] 14 self.buildLanguages = ['C','FC'] 15 self.downloadonWindows= 1 16 self.hastests = 1 17 self.hastestsdatafiles= 1 18 self.license = 'https://mumps-solver.org/index.php?page=dwnld#form' 19 return 20 21 def setupHelp(self, help): 22 import nargs 23 config.package.Package.setupHelp(self, help) 24 help.addArgument('MUMPS', '-download-mumps-openmp', nargs.ArgBool(None, 1, 'Let MUMPS use OpenMP if available')) 25 help.addArgument('MUMPS', '-download-mumps-avoid-mpi-in-place', nargs.ArgBool(None, 0, 'Let MUMPS not use MPI_IN_PLACE. Since MUMPS-5.6.2, it can be used to avoid a bug in MPICH older than 4.0b1')) 26 return 27 28 def setupDependencies(self, framework): 29 config.package.Package.setupDependencies(self, framework) 30 self.flibs = framework.require('config.packages.flibs',self) 31 self.blasLapack = framework.require('config.packages.BlasLapack',self) 32 self.mpi = framework.require('config.packages.MPI',self) 33 self.metis = framework.require('config.packages.METIS',self) 34 self.parmetis = framework.require('config.packages.ParMETIS',self) 35 self.ptscotch = framework.require('config.packages.PTSCOTCH',self) 36 self.scalapack = framework.require('config.packages.ScaLAPACK',self) 37 self.hwloc = framework.require('config.packages.hwloc',self) 38 self.openmp = framework.require('config.packages.OpenMP',self) 39 self.scalartypes = framework.require('PETSc.options.scalarTypes',self) 40 if not self.argDB['with-mpi']: 41 self.deps = [self.blasLapack,self.flibs] 42 self.odeps = [self.metis,self.openmp] 43 else: 44 self.deps = [self.scalapack,self.mpi,self.blasLapack,self.flibs] 45 self.odeps = [self.metis,self.parmetis,self.ptscotch,self.hwloc,self.openmp] 46 return 47 48 def configureLibrary(self): 49 for arg in ['with-64-bit-blas-indices','known-64-bit-blas-indices']: 50 if self.argDB.get(arg): 51 raise RuntimeError('MUMPS cannot be used with %s' % arg) 52 liblist_common = [['libmumps_common.a','libpord.a','libpthread.a'], 53 ['libmumps_common.a','libpord.a'], 54 ['libmumps_common.a','libpord.a','libmpiseq.a'], 55 ['libmumps_common.a','libpord.a','libpthread.a','libmpiseq.a']] 56 try: # Check if the MUMPS installation supports all precisions with either complex or real, in other words, it is a full installation. 57 self.functions = ['smumps_c', 'dmumps_c', 'cmumps_c', 'zmumps_c',] 58 self.includes = ['smumps_c.h', 'dmumps_c.h', 'cmumps_c.h', 'zmumps_c.h'] 59 self.liblist = [] 60 for libc in liblist_common: 61 self.liblist.append(['libsmumps.a', 'libdmumps.a', 'libcmumps.a', 'libzmumps.a'] + libc) 62 config.package.Package.configureLibrary(self) 63 self.addDefine('HAVE_MUMPS_MIXED_PRECISION',1) 64 except Exception as e: 65 self.log.write('MUMPS mixed precision with '+str(e)+'. Now only try the precision PetscScalar uses.\n') 66 if self.scalartypes.precision == 'single': 67 if self.scalartypes.scalartype == 'real': l = 's' 68 else: l = 'c' 69 elif self.scalartypes.precision == 'double': 70 if self.scalartypes.scalartype == 'real': l = 'd' 71 else: l = 'z' 72 else: raise RuntimeError('With a partial installation of MUMPS, you can only use single or double precision') 73 self.functions = [l+'mumps_c'] 74 self.includes = [l+'mumps_c.h'] 75 self.liblist = [] 76 for libc in liblist_common: 77 self.liblist.append(['lib'+l+'mumps.a'] + libc) 78 config.package.Package.configureLibrary(self) 79 80 def Install(self): 81 import os 82 83 if self.openmp.found and self.argDB['download-mumps-openmp']: 84 # MUMPS has no make flags for turning on/off OpenMP it just uses it if it can 85 # we only pass OpenMP compiler flags to MUMPS if self.usesopenmp is yes 86 self.usesopenmp = 'yes' 87 # use OMP_NUM_THREADS to control the number of threads used 88 89 if not self.fortran.FortranDefineCompilerOption: 90 raise RuntimeError('Fortran compiler cannot handle preprocessing directives from command line.') 91 g = open(os.path.join(self.packageDir,'Makefile.inc'),'w') 92 g.write('LPORDDIR = $(topdir)/PORD/lib/\n') 93 g.write('IPORD = -I$(topdir)/PORD/include/\n') 94 g.write('LPORD = -L$(LPORDDIR) -lpord\n') 95 g.write('PLAT = \n') 96 orderingsc = '-Dpord' 97 orderingsf = self.fortran.FortranDefineCompilerOption+'pord' 98 if self.metis.found: 99 g.write('IMETIS = '+self.headers.toString(self.metis.include)+'\n') 100 g.write('LMETIS = '+self.libraries.toString(self.metis.lib)+'\n') 101 orderingsc += ' -Dmetis' 102 orderingsf += ' '+self.fortran.FortranDefineCompilerOption+'metis' 103 if self.parmetis.found: 104 g.write('IPARMETIS = '+self.headers.toString(self.parmetis.include)+'\n') 105 g.write('LPARMETIS = '+self.libraries.toString(self.parmetis.lib)+'\n') 106 orderingsc += ' -Dparmetis' 107 orderingsf += ' '+self.fortran.FortranDefineCompilerOption+'parmetis' 108 if self.ptscotch.found: 109 g.write('ISCOTCH = '+self.headers.toString(self.ptscotch.include)+'\n') 110 g.write('LSCOTCH = '+self.libraries.toString(self.ptscotch.lib)+'\n') 111 orderingsc += ' -Dscotch -Dptscotch' 112 orderingsf += ' '+self.fortran.FortranDefineCompilerOption+'scotch '+self.fortran.FortranDefineCompilerOption+'ptscotch' 113 114 g.write('ORDERINGSC = '+orderingsc+'\n') 115 g.write('ORDERINGSF = '+orderingsf+'\n') 116 g.write('LORDERINGS = $(LPARMETIS) $(LMETIS) $(LPORD) $(LSCOTCH)\n') 117 g.write('IORDERINGSC = $(IPARMETIS) $(IMETIS) $(IPORD) $(ISCOTCH)\n') 118 g.write('IORDERINGSF = $(ISCOTCH)\n') 119 120 g.write('RM = '+self.programs.RM+'\n') 121 self.pushLanguage('C') 122 g.write('CC = '+self.getCompiler()+'\n') 123 g.write('OPTC = '+self.updatePackageCFlags(self.getCompilerFlags())+'\n') 124 g.write('OUTC = -o \n') 125 self.popLanguage() 126 if not self.fortran.fortranIsF90: 127 raise RuntimeError('Installing MUMPS requires a F90 compiler') 128 self.pushLanguage('FC') 129 g.write('FC = '+self.getCompiler()+'\n') 130 g.write('FL = '+self.getCompiler()+'\n') 131 if self.usesopenmp == 'yes': 132 g.write('OPTF = '+self.updatePackageFFlags(self.getCompilerFlags())+'\n') 133 else: 134 g.write('OPTF = '+self.updatePackageFFlags(' '.join(self.removeOpenMPFlag(self.getCompilerFlags().split())))+'\n') 135 if self.blasLapack.checkForRoutine('dgemmt'): 136 g.write('OPTF += -DGEMMT_AVAILABLE\n') 137 g.write('OUTF = -o \n') 138 self.popLanguage() 139 140 # set fortran name mangling 141 # this mangling information is for both BLAS and the Fortran compiler so cannot use the BlasLapack mangling flag 142 if self.compilers.fortranManglingDoubleUnderscore: 143 g.write('CDEFS = -DAdd__\n') 144 elif self.compilers.fortranMangling == 'underscore': 145 g.write('CDEFS = -DAdd_\n') 146 elif self.compilers.fortranMangling == 'caps': 147 g.write('CDEFS = -DUPPPER\n') 148 149 g.write('AR = '+self.setCompilers.AR+' '+self.setCompilers.AR_FLAGS+' \n') 150 g.write('LIBEXT = .'+self.setCompilers.AR_LIB_SUFFIX+'\n') 151 g.write('RANLIB = '+self.setCompilers.RANLIB+'\n') 152 g.write('SCALAP = '+self.libraries.toString(self.scalapack.lib)+'\n') 153 if not self.mpi.usingMPIUni: 154 g.write('INCPAR = '+self.headers.toString(self.mpi.include)+'\n') 155 g.write('LIBPAR = $(SCALAP) '+self.libraries.toString(self.mpi.lib)+'\n') 156 else: 157 g.write('INCPAR = -I../libseq\n') 158 g.write('INCSEQ = -I$(topdir)/libseq\n') 159 g.write('LIBSEQ = $(LAPACK) -L$(topdir)/libseq -lmpiseq\n') 160 g.write('LIBBLAS = '+self.libraries.toString(self.blasLapack.dlib)+'\n') 161 g.write('OPTL = '+self.getLinkerFlags()+'\n') 162 g.write('INCS = $(INCPAR)\n') 163 g.write('LIBS = $(LIBPAR)\n') 164 if self.mpi.usingMPIUni: 165 g.write('LIBSEQNEEDED = libseqneeded\n') 166 g.write('LIBS = $(LIBSEQ)\n') 167 else: 168 g.write('LIBSEQNEEDED =\n') 169 if self.openmp.found and self.hwloc.found: 170 g.write('LIBS += '+self.libraries.toString(self.hwloc.lib)+'\n') 171 g.write('OPTF += -DUSE_LIBHWLOC\n') 172 g.write('OPTC += -DUSE_LIBHWLOC\n') 173 # To avoid a bug related to MPI_IN_PLACE and old MPICH releases, see MR 4410 174 self.avoid_mpi_in_place = 0 175 if 'download-mumps-avoid-mpi-in-place' in self.framework.clArgDB: # user-provided value takes precedence 176 self.avoid_mpi_in_place = self.framework.clArgDB['download-mumps-avoid-mpi-in-place'] 177 elif hasattr(self.mpi, 'mpich_numversion') and int(self.mpi.mpich_numversion) < 40000101: 178 self.avoid_mpi_in_place = 1 179 if self.avoid_mpi_in_place: 180 g.write('OPTF += -DAVOID_MPI_IN_PLACE\n') # only take effect since mumps-5.6.2 181 self.addDefine('HAVE_MUMPS_AVOID_MPI_IN_PLACE', 1) 182 g.close() 183 if self.installNeeded('Makefile.inc'): 184 try: 185 output1,err1,ret1 = config.package.Package.executeShellCommand('make clean', cwd=self.packageDir, timeout=60, log = self.log) 186 except RuntimeError as e: 187 pass 188 try: 189 self.logPrintBox('Compiling MUMPS; this may take several minutes') 190 output2,err2,ret2 = config.package.Package.executeShellCommand(self.make.make_jnp+' prerequisites', cwd=self.packageDir, timeout=2500, log = self.log) 191 output3,err3,ret3 = config.package.Package.executeShellCommand(self.make.make_jnp+' all', cwd=os.path.join(self.packageDir,'src'), timeout=2500, log = self.log) 192 libDir = self.libDir 193 includeDir = os.path.join(self.installDir, self.includedir) 194 self.logPrintBox('Installing MUMPS; this may take several minutes') 195 output,err,ret = config.package.Package.executeShellCommandSeq( 196 ['mkdir -p '+libDir+' '+includeDir, 197 'cp -f lib/*.* '+libDir, 198 'cp -f include/*.* '+includeDir 199 ], cwd=self.packageDir, timeout=60, log = self.log) 200 if self.mpi.usingMPIUni: 201 output,err,ret = config.package.Package.executeShellCommand(['cp', '-f', 'libseq/libmpiseq.a', libDir+'/.'], cwd=self.packageDir, timeout=60, log = self.log) 202 except RuntimeError as e: 203 self.logPrint('Error running make on MUMPS: '+str(e)) 204 raise RuntimeError('Error running make on MUMPS') 205 self.postInstall(output2+err2+output3+err3,'Makefile.inc') 206 return self.installDir 207