PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/hpc_kernel_samples/sparse_linear_algebra/casestudies/pagerank-petsc/petsc-2.3.2-p10/python/PETSc/petsc.py

https://gitlab.com/nikoloutsa/CodeVault
Python | 459 lines | 420 code | 11 blank | 28 comment | 29 complexity | e912032175d22a86d23b762e07a42a28 MD5 | raw file
  1. #!/usr/bin/env python
  2. '''
  3. This is the first try for a hierarchically configured module. The idea is to
  4. add the configure objects from a previously executed framework into the current
  5. framework. However, this necessitates a reorganization of the activities in the
  6. module.
  7. We must now have three distinct phases: location, construction, and testing.
  8. This is very similar to the current compiler checks. The construction phase is
  9. optional, and only necessary when the package has not been previously configured.
  10. The phases will necessarily interact, as an installtion must be located before
  11. testing, however anothe should be located if the testing fails.
  12. We will give each installation a unique key, which is returned by the location
  13. method. This will allow us to identify working installations, as well as those
  14. that failed testing.
  15. There is a wierd role reversal that can happen. If we look for PETSc, but
  16. cannot find it, it is reasonable to ask to have it automatically downloaded.
  17. However, in this case, rather than using the configure objects from the existing
  18. PETSc, we contribute objects to the PETSc which will be built.
  19. '''
  20. from __future__ import generators
  21. import user
  22. import config.base
  23. import re
  24. import os
  25. class InvalidPETScError(RuntimeError):
  26. pass
  27. class Configure(config.base.Configure):
  28. def __init__(self, framework):
  29. config.base.Configure.__init__(self, framework)
  30. self.headerPrefix = ''
  31. self.substPrefix = ''
  32. self.location = None
  33. self.trial = {}
  34. self.working = {}
  35. return
  36. def __str__(self):
  37. if self.found:
  38. desc = ['PETSc:']
  39. desc.append(' Type: '+self.name)
  40. desc.append(' Version: '+self.version)
  41. desc.append(' Includes: '+str(self.include))
  42. desc.append(' Library: '+str(self.lib))
  43. return '\n'.join(desc)+'\n'
  44. else:
  45. return ''
  46. def setupHelp(self, help):
  47. import nargs
  48. help.addArgument('PETSc', '-with-petsc=<bool>', nargs.ArgBool(None, 1, 'Activate PETSc'))
  49. # Location options
  50. help.addArgument('PETSc', '-with-petsc-dir=<root dir>', nargs.ArgDir(None, None, 'Specify the root directory of the PETSc installation'))
  51. help.addArgument('PETSc', '-with-petsc-arch=<arch>', nargs.Arg(None, None, 'Specify PETSC_ARCH'))
  52. # Construction options
  53. help.addArgument('PETSc', '-download-petsc=<no,yes,ifneeded>', nargs.ArgFuzzyBool(None, 0, 'Install PETSc'))
  54. # Testing options
  55. help.addArgument('PETSc', '-with-petsc-shared=<bool>', nargs.ArgBool(None, 1, 'Require that the PETSc library be shared'))
  56. return
  57. def setupPackageDependencies(self, framework):
  58. import sys
  59. petscConf = None
  60. for (name, (petscDir, petscArch)) in self.getLocations():
  61. petscPythonDir = os.path.join(petscDir, 'python')
  62. sys.path.append(petscPythonDir)
  63. confPath = os.path.join(petscDir, 'bmake', petscArch)
  64. petscConf = framework.loadFramework(confPath)
  65. if petscConf:
  66. self.logPrint('Loaded PETSc-AS configuration ('+name+') from '+confPath)
  67. self.location = (petscDir, petscArch)
  68. self.trial[self.location] = name
  69. break
  70. else:
  71. self.logPrint('PETSc-AS has no cached configuration in '+confPath)
  72. sys.path.reverse()
  73. sys.path.remove(petscPythonDir)
  74. sys.path.reverse()
  75. if not petscConf:
  76. self.downloadPETSc()
  77. framework.addPackageDependency(petscConf, confPath)
  78. return
  79. def setupDependencies(self, framework):
  80. config.base.Configure.setupDependencies(self, framework)
  81. self.languages = framework.require('PETSc.utilities.languages', self)
  82. self.compilers = framework.require('config.compilers', self)
  83. self.headers = framework.require('config.headers', self)
  84. self.libraries = framework.require('config.libraries', self)
  85. self.blaslapack = framework.require('PETSc.packages.BlasLapack', self)
  86. self.mpi = framework.require('PETSc.packages.MPI', self)
  87. return
  88. def getPETScArch(self, petscDir):
  89. '''Return the allowable PETSc architectures for a given root'''
  90. if 'with-petsc-arch' in self.framework.argDB:
  91. yield self.framework.argDB['with-petsc-arch']
  92. elif 'PETSC_ARCH' in os.environ:
  93. yield os.environ['PETSC_ARCH']
  94. else:
  95. if os.path.isdir(os.path.join(petscDir, 'bmake')):
  96. for d in os.listdir(os.path.join(petscDir, 'bmake')):
  97. if not os.path.isdir(os.path.join(petscDir, 'bmake', d)):
  98. continue
  99. if d in ['common', 'docsonly', 'SCCS']:
  100. continue
  101. yield d
  102. return
  103. def getLocations(self):
  104. '''Return all allowable locations for PETSc'''
  105. if hasattr(self, '_configured'):
  106. key =(self.dir, self.arch)
  107. yield (self.working[key], key)
  108. raise InvalidPETScError('Configured PETSc is not usable')
  109. if self.framework.argDB['download-petsc'] == 1:
  110. yield self.downloadPETSc()
  111. raise InvalidPETScError('Downloaded PETSc is not usable')
  112. if 'with-petsc-dir' in self.framework.argDB:
  113. petscDir = self.framework.argDB['with-petsc-dir']
  114. for petscArch in self.getPETScArch(petscDir):
  115. yield ('User specified installation root', (petscDir, petscArch))
  116. raise InvalidPETScError('No working architecitures in '+str(petscDir))
  117. elif 'PETSC_DIR' in os.environ:
  118. petscDir = os.environ['PETSC_DIR']
  119. for petscArch in self.getPETScArch(petscDir):
  120. yield ('User specified installation root', (petscDir, petscArch))
  121. raise InvalidPETScError('No working architecitures in '+str(petscDir))
  122. else:
  123. for petscArch in self.getPETScArch(petscDir):
  124. yield ('Default compiler locations', ('', petscArch))
  125. petscDirRE = re.compile(r'(PETSC|pets)c(-.*)?')
  126. trialDirs = []
  127. for packageDir in self.framework.argDB['package-dirs']:
  128. if os.path.isdir(packageDir):
  129. for d in os.listdir(packageDir):
  130. if petscDirRE.match(d):
  131. trialDirs.append(('Package directory installation root', os.path.join(packageDir, d)))
  132. usrLocal = os.path.join('/usr', 'local')
  133. if os.path.isdir(os.path.join('/usr', 'local')):
  134. trialDirs.append(('Frequent user install location (/usr/local)', usrLocal))
  135. for d in os.listdir(usrLocal):
  136. if petscDirRE.match(d):
  137. trialDirs.append(('Frequent user install location (/usr/local/'+d+')', os.path.join(usrLocal, d)))
  138. if 'HOME' in os.environ and os.path.isdir(os.environ['HOME']):
  139. for d in os.listdir(os.environ['HOME']):
  140. if petscDirRE.match(d):
  141. trialDirs.append(('Frequent user install location (~/'+d+')', os.path.join(os.environ['HOME'], d)))
  142. return
  143. def downloadPETSc(self):
  144. if self.framework.argDB['download-petsc'] == 0:
  145. raise RuntimeError('No functioning PETSc located')
  146. # Download and build PETSc
  147. # Use only the already configured objects from this run
  148. raise RuntimeError('Not implemented')
  149. def getDir(self):
  150. if self.location:
  151. return self.location[0]
  152. return None
  153. dir = property(getDir, doc = 'The PETSc root directory')
  154. def getArch(self):
  155. if self.location:
  156. return self.location[1]
  157. return None
  158. arch = property(getArch, doc = 'The PETSc architecture')
  159. def getFound(self):
  160. return self.location and self.location in self.working
  161. found = property(getFound, doc = 'Did we find a valid PETSc installation')
  162. def getName(self):
  163. if self.location and self.location in self.working:
  164. return self.working[self.location][0]
  165. return None
  166. name = property(getName, doc = 'The PETSc installation type')
  167. def getInclude(self, useTrial = 0):
  168. if self.location and self.location in self.working:
  169. return self.working[self.location][1]
  170. elif useTrial and self.location and self.location in self.trial:
  171. return self.trial[self.location][1]
  172. return None
  173. include = property(getInclude, doc = 'The PETSc include directories')
  174. def getLib(self, useTrial = 0):
  175. if self.location and self.location in self.working:
  176. return self.working[self.location][2]
  177. elif useTrial and self.location and self.location in self.trial:
  178. return self.trial[self.location][2]
  179. return None
  180. lib = property(getLib, doc = 'The PETSc libraries')
  181. def getVersion(self):
  182. if self.location and self.location in self.working:
  183. return self.working[self.location][3]
  184. return None
  185. version = property(getVersion, doc = 'The PETSc version')
  186. def getOtherIncludes(self):
  187. if not hasattr(self, '_otherIncludes'):
  188. includes = []
  189. includes.extend([self.headers.getIncludeArgument(inc) for inc in self.mpi.include])
  190. return ' '.join(includes)
  191. return self._otherIncludes
  192. def setOtherIncludes(self, otherIncludes):
  193. self._otherIncludes = otherIncludes
  194. otherIncludes = property(getOtherIncludes, setOtherIncludes, doc = 'Includes needed to compile PETSc')
  195. def getOtherLibs(self):
  196. if not hasattr(self, '_otherLibs'):
  197. libs = self.compilers.flibs[:]
  198. libs.extend(self.mpi.lib)
  199. libs.extend(self.blaslapack.lib)
  200. return libs
  201. return self._otherLibs
  202. def setOtherLibs(self, otherLibs):
  203. self._otherLibs = otherLibs
  204. otherLibs = property(getOtherLibs, setOtherLibs, doc = 'Libraries needed to link PETSc')
  205. def checkLib(self, libraries):
  206. '''Check for PETSc creation functions in libraries, which can be a list of libraries or a single library
  207. - PetscInitialize from libpetsc
  208. - VecCreate from libpetscvec
  209. - MatCreate from libpetscmat
  210. - DADestroy from libpetscdm
  211. - KSPCreate from libpetscksp
  212. - SNESCreate from libpetscsnes
  213. - TSCreate from libpetscts
  214. '''
  215. if not isinstance(libraries, list): libraries = [libraries]
  216. oldLibs = self.compilers.LIBS
  217. self.libraries.pushLanguage(self.languages.clanguage)
  218. found = (self.libraries.check(libraries, 'PetscInitializeNoArguments', otherLibs = self.otherLibs, prototype = 'int PetscInitializeNoArguments(void);', cxxMangle = not self.languages.cSupport) and
  219. self.libraries.check(libraries, 'VecDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_Vec *Vec;int VecDestroy(Vec);', call = 'VecDestroy((Vec) 0)', cxxMangle = not self.languages.cSupport) and
  220. self.libraries.check(libraries, 'MatDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_Mat *Mat;int MatDestroy(Mat);', call = 'MatDestroy((Mat) 0)', cxxMangle = not self.languages.cSupport) and
  221. self.libraries.check(libraries, 'DADestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_DA *DA;int DADestroy(DA);', call = 'DADestroy((DA) 0)', cxxMangle = not self.languages.cSupport) and
  222. self.libraries.check(libraries, 'KSPDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_KSP *KSP;int KSPDestroy(KSP);', call = 'KSPDestroy((KSP) 0)', cxxMangle = not self.languages.cSupport) and
  223. self.libraries.check(libraries, 'SNESDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_SNES *SNES;int SNESDestroy(SNES);', call = 'SNESDestroy((SNES) 0)', cxxMangle = not self.languages.cSupport) and
  224. self.libraries.check(libraries, 'TSDestroy', otherLibs = self.otherLibs, prototype = 'typedef struct _p_TS *TS;int TSDestroy(TS);', call = 'TSDestroy((TS) 0)', cxxMangle = not self.languages.cSupport))
  225. self.libraries.popLanguage()
  226. self.compilers.LIBS = oldLibs
  227. return found
  228. def checkInclude(self, includeDir):
  229. '''Check that petsc.h is present'''
  230. oldFlags = self.compilers.CPPFLAGS
  231. self.compilers.CPPFLAGS += ' '.join([self.headers.getIncludeArgument(inc) for inc in includeDir])
  232. if self.otherIncludes:
  233. self.compilers.CPPFLAGS += ' '+self.otherIncludes
  234. self.pushLanguage(self.languages.clanguage)
  235. found = self.checkPreprocess('#include <petsc.h>\n')
  236. self.popLanguage()
  237. self.compilers.CPPFLAGS = oldFlags
  238. return found
  239. def checkPETScLink(self, includes, body, cleanup = 1, codeBegin = None, codeEnd = None, shared = None):
  240. '''Analogous to checkLink(), but the PETSc includes and libraries are automatically provided'''
  241. success = 0
  242. oldFlags = self.compilers.CPPFLAGS
  243. self.compilers.CPPFLAGS += ' '.join([self.headers.getIncludeArgument(inc) for inc in self.getInclude(useTrial = 1)])
  244. if self.otherIncludes:
  245. self.compilers.CPPFLAGS += ' '+self.otherIncludes
  246. oldLibs = self.compilers.LIBS
  247. self.compilers.LIBS = ' '.join([self.libraries.getLibArgument(lib) for lib in self.getLib(useTrial = 1)+self.otherLibs])+' '+self.compilers.LIBS
  248. if self.checkLink(includes, body, cleanup, codeBegin, codeEnd, shared):
  249. success = 1
  250. self.compilers.CPPFLAGS = oldFlags
  251. self.compilers.LIBS = oldLibs
  252. return success
  253. def checkWorkingLink(self):
  254. '''Checking that we can link a PETSc executable'''
  255. self.pushLanguage(self.languages.clanguage)
  256. if not self.checkPETScLink('#include <petsclog.h>\n', 'PetscLogDouble time;\nPetscErrorCode ierr;\n\nierr = PetscGetTime(&time); CHKERRQ(ierr);\n'):
  257. self.logPrint('PETSc cannot link, which indicates a problem with the PETSc installation')
  258. return 0
  259. self.logPrint('PETSc can link with '+self.languages.clanguage)
  260. self.popLanguage()
  261. if hasattr(self.compilers, 'CXX') and self.languages.clanguage == 'C':
  262. self.pushLanguage('C++')
  263. self.sourceExtension = '.C'
  264. if not self.checkPETScLink('#define PETSC_USE_EXTERN_CXX\n#include <petsc.h>\n', 'PetscLogDouble time;\nPetscErrorCode ierr;\n\nierr = PetscGetTime(&time); CHKERRQ(ierr);\n'):
  265. self.logPrint('PETSc cannot link C++ but can link C, which indicates a problem with the PETSc installation')
  266. self.popLanguage()
  267. return 0
  268. self.popLanguage()
  269. self.logPrint('PETSc can link with C++')
  270. if hasattr(self.compilers, 'FC'):
  271. self.pushLanguage('FC')
  272. self.sourceExtension = '.F'
  273. if not self.checkPETScLink('', ' integer ierr\n real time\n call PetscGetTime(time, ierr)\n'):
  274. self.logPrint('PETSc cannot link Fortran, but can link C, which indicates a problem with the PETSc installation\nRun with -with-fc=0 if you do not wish to use Fortran')
  275. self.popLanguage()
  276. return 0
  277. self.popLanguage()
  278. self.logPrint('PETSc can link with Fortran')
  279. return 1
  280. def checkSharedLibrary(self, libraries):
  281. '''Check that the libraries for PETSc are shared libraries'''
  282. if config.setCompilers.Configure.isDarwin():
  283. # on Apple if you list the MPI libraries again you will generate multiply defined errors
  284. # since they are already copied into the PETSc dynamic library.
  285. self.setOtherLibs([])
  286. self.pushLanguage(self.languages.clanguage)
  287. isShared = self.libraries.checkShared('#include <petsc.h>\n', 'PetscInitialize', 'PetscInitialized', 'PetscFinalize', checkLink = self.checkPETScLink, libraries = libraries, initArgs = '&argc, &argv, 0, 0', boolType = 'PetscTruth', executor = self.mpi.mpirun)
  288. self.popLanguage()
  289. return isShared
  290. def configureVersion(self):
  291. '''Determine the PETSc version'''
  292. majorRE = re.compile(r'^#define PETSC_VERSION_MAJOR([\s]+)(?P<versionNum>\d+)[\s]*$');
  293. minorRE = re.compile(r'^#define PETSC_VERSION_MINOR([\s]+)(?P<versionNum>\d+)[\s]*$');
  294. subminorRE = re.compile(r'^#define PETSC_VERSION_SUBMINOR([\s]+)(?P<versionNum>\d+)[\s]*$');
  295. patchRE = re.compile(r'^#define PETSC_VERSION_PATCH([\s]+)(?P<patchNum>\d+)[\s]*$');
  296. dateRE = re.compile(r'^#define PETSC_VERSION_DATE([\s]+)"(?P<date>(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d\d?, \d\d\d\d)"[\s]*$');
  297. input = file(os.path.join(self.dir, 'include', 'petscversion.h'))
  298. lines = []
  299. majorNum = 'Unknown'
  300. minorNum = 'Unknown'
  301. subminorNum = 'Unknown'
  302. patchNum = 'Unknown'
  303. self.date = 'Unknown'
  304. for line in input.readlines():
  305. m1 = majorRE.match(line)
  306. m2 = minorRE.match(line)
  307. m3 = subminorRE.match(line)
  308. m4 = patchRE.match(line)
  309. m5 = dateRE.match(line)
  310. if m1:
  311. majorNum = int(m1.group('versionNum'))
  312. elif m2:
  313. minorNum = int(m2.group('versionNum'))
  314. elif m3:
  315. subminorNum = int(m3.group('versionNum'))
  316. if m4:
  317. patchNum = int(m4.group('patchNum'))+1
  318. lines.append('#define PETSC_VERSION_PATCH'+m4.group(1)+str(patchNum)+'\n')
  319. elif m5:
  320. self.date = time.strftime('%b %d, %Y', time.localtime(time.time()))
  321. lines.append('#define PETSC_VERSION_DATE'+m5.group(1)+'"'+self.date+'"\n')
  322. else:
  323. lines.append(line)
  324. input.close()
  325. self.logPrint('Found PETSc version (%s,%s,%s) patch %s on %s' % (majorNum, minorNum, subminorNum, patchNum, self.date))
  326. return '%d.%d.%d' % (majorNum, minorNum, subminorNum)
  327. def includeGuesses(self, path = None):
  328. '''Return all include directories present in path or its ancestors'''
  329. if not path:
  330. yield []
  331. while path:
  332. dir = os.path.join(path, 'include')
  333. if os.path.isdir(dir):
  334. yield [dir, os.path.join(path, 'bmake', self.arch)]
  335. if path == '/':
  336. return
  337. path = os.path.dirname(path)
  338. return
  339. def libraryGuesses(self, root = None):
  340. '''Return standard library name guesses for a given installation root'''
  341. libs = ['ts', 'snes', 'ksp', 'dm', 'mat', 'vec', '']
  342. if root:
  343. d = os.path.join(root, 'lib', self.arch)
  344. if not os.path.isdir(d):
  345. self.logPrint('', 3, 'petsc')
  346. return
  347. yield [os.path.join(d, 'libpetsc'+lib+'.a') for lib in libs]
  348. else:
  349. yield ['libpetsc'+lib+'.a' for lib in libs]
  350. return
  351. def configureLibrary(self):
  352. '''Find a working PETSc
  353. - Right now, C++ builds are required to use PETSC_USE_EXTERN_CXX'''
  354. for location, name in self.trial.items():
  355. self.framework.logPrintDivider()
  356. self.framework.logPrint('Checking for a functional PETSc in '+name+', location/origin '+str(location))
  357. lib = None
  358. include = None
  359. found = 0
  360. for libraries in self.libraryGuesses(location[0]):
  361. if self.checkLib(libraries):
  362. lib = libraries
  363. for includeDir in self.includeGuesses(location[0]):
  364. if self.checkInclude(includeDir):
  365. include = includeDir
  366. self.trial[location] = (name, include, lib, 'Unknown')
  367. if self.executeTest(self.checkWorkingLink):
  368. found = 1
  369. break
  370. else:
  371. self.framework.logPrintDivider(single = 1)
  372. self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkWorkingLink test')
  373. else:
  374. self.framework.logPrintDivider(single = 1)
  375. self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkInclude test with includeDir: '+str(includeDir))
  376. if not found:
  377. self.framework.logPrintDivider(single = 1)
  378. self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkIncludes test')
  379. continue
  380. else:
  381. self.framework.logPrintDivider(single = 1)
  382. self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkLib test with libraries: '+str(libraries))
  383. continue
  384. if self.framework.argDB['with-petsc-shared']:
  385. if not self.executeTest(self.checkSharedLibrary, [libraries]):
  386. self.framework.logPrintDivider(single = 1)
  387. self.framework.logPrint('PETSc in '+name+', location/origin '+str(location)+' failed checkSharedLibrary test with libraries: '+str(libraries))
  388. found = 0
  389. if found:
  390. break
  391. if found:
  392. version = self.executeTest(self.configureVersion)
  393. self.working[location] = (name, include, lib, version)
  394. break
  395. if found:
  396. self.logPrint('Choose PETSc '+self.version+' in '+self.name)
  397. else:
  398. raise RuntimeError('Could not locate any functional PETSc')
  399. return
  400. def setOutput(self):
  401. '''Add defines and substitutions
  402. - HAVE_PETSC is defined if a working PETSc is found
  403. - PETSC_INCLUDE and PETSC_LIB are command line arguments for the compile and link'''
  404. if self.found:
  405. self.addDefine('HAVE_PETSC', 1)
  406. self.addSubstitution('PETSC_INCLUDE', ' '.join([self.headers.getIncludeArgument(inc) for inc in self.include]))
  407. self.addSubstitution('PETSC_LIB', ' '.join(map(self.libraries.getLibArgument, self.lib)))
  408. return
  409. def configure(self):
  410. self.executeTest(self.configureLibrary)
  411. self.setOutput()
  412. return
  413. if __name__ == '__main__':
  414. import config.framework
  415. import sys
  416. framework = config.framework.Framework(sys.argv[1:])
  417. framework.setup()
  418. framework.addChild(Configure(framework))
  419. framework.configure()
  420. framework.dumpSubstitutions()