xref: /petsc/config/PETSc/options/scalarTypes.py (revision 534a8f05a7a8aff70dd8cfd53d9cd834400a8dbf)
1#!/usr/bin/env python
2from __future__ import generators
3import config.base
4
5class Configure(config.base.Configure):
6  def __init__(self, framework):
7    config.base.Configure.__init__(self, framework)
8    self.headerPrefix   = ''
9    self.substPrefix    = ''
10    self.have__float128 = 0
11    return
12
13  def __str1__(self):
14    output  = '  Scalar type: ' + self.scalartype + '\n'
15    output += '  Precision: ' + self.precision + '\n'
16    if self.have__float128 and not self.precision == '__float128': output += '  Support for __float128\n'
17    return output
18
19  def setupHelp(self, help):
20    import nargs
21    #  Dec 2016, the __fp16 type is only available with GNU compilers on ARM systems
22    help.addArgument('PETSc', '-with-precision=<__fp16,single,double,__float128>', nargs.Arg(None, 'double', 'Specify numerical precision'))
23    help.addArgument('PETSc', '-with-scalar-type=<real or complex>', nargs.Arg(None, 'real', 'Specify real or complex numbers'))
24    return
25
26  def setupDependencies(self, framework):
27    config.base.Configure.setupDependencies(self, framework)
28    self.types         = framework.require('config.types', self)
29    self.languages     = framework.require('PETSc.options.languages', self)
30    self.compilers     = framework.require('config.compilers', self)
31    self.libraries     = framework.require('config.libraries',self)
32    self.setCompilers  = framework.require('config.setCompilers', self)
33    self.compilerFlags = framework.require('config.compilerFlags', self)
34    self.types         = framework.require('config.types', self)
35    self.headers       = framework.require('config.headers', self)
36    self.libraries     = framework.require('config.libraries', self)
37    return
38
39
40  def configureScalarType(self):
41    '''Choose between real and complex numbers'''
42    self.scalartype = self.framework.argDB['with-scalar-type'].lower()
43    if self.scalartype == 'complex':
44      self.addDefine('USE_COMPLEX', '1')
45      if self.languages.clanguage == 'C' and not self.types.c99_complex:
46        raise RuntimeError('C Compiler provided doest not support C99 complex')
47      if self.languages.clanguage == 'Cxx' and not self.types.cxx_complex:
48        raise RuntimeError('Cxx compiler provided does not support std::complex')
49      if self.languages.clanguage == 'Cxx':
50        self.addDefine('USE_CXXCOMPLEX',1)
51    elif not self.scalartype == 'real':
52      raise RuntimeError('--with-scalar-type must be real or complex')
53    self.logPrint('Scalar type is '+str(self.scalartype))
54    # On apple isinf() and isnan() do not work when <complex> is included
55    self.pushLanguage(self.languages.clanguage)
56    if self.scalartype == 'complex' and self.languages.clanguage == 'Cxx':
57      if self.checkLink('#include <math.h>\n#include <complex>\n','double b = 2.0;int a = isnormal(b);\n'):
58        self.addDefine('HAVE_ISNORMAL',1)
59      if self.checkLink('#include <math.h>\n#include <complex>\n','double b = 2.0;int a = isnan(b);\n'):
60        self.addDefine('HAVE_ISNAN',1)
61      if self.checkLink('#include <math.h>\n#include <complex>\n','double b = 2.0;int a = isinf(b);\n'):
62        self.addDefine('HAVE_ISINF',1)
63      if self.checkLink('#include <float.h>\n#include <complex>\n','double b = 2.0;int a = _isnan(b);\n'):
64        self.addDefine('HAVE__ISNAN',1)
65      if self.checkLink('#include <float.h>\n#include <complex>\n','double b = 2.0;int a = _finite(b);\n'):
66        self.addDefine('HAVE__FINITE',1)
67    else:
68      if self.checkLink('#include <math.h>\n','double b = 2.0; int a = isnormal(b);\n'):
69        self.addDefine('HAVE_ISNORMAL',1)
70      if self.checkLink('#include <math.h>\n','double b = 2.0; int a = isnan(b);\n'):
71        self.addDefine('HAVE_ISNAN',1)
72      if self.checkLink('#include <math.h>\n','double b = 2.0; int a = isinf(b);\n'):
73        self.addDefine('HAVE_ISINF',1)
74      if self.checkLink('#include <float.h>\n','double b = 2.0;int a = _isnan(b);\n'):
75        self.addDefine('HAVE__ISNAN',1)
76      if self.checkLink('#include <float.h>\n','double b = 2.0;int a = _finite(b);\n'):
77        self.addDefine('HAVE__FINITE',1)
78    self.popLanguage()
79    return
80
81  def configurePrecision(self):
82    '''Set the default real number precision for PETSc objects'''
83    self.log.write('Checking C compiler works with __float128\n')
84    self.have__float128 = 0
85    if self.libraries.check('quadmath','logq',prototype='#include <quadmath.h>',call='__float128 f; logq(f);'):
86      self.log.write('C compiler with quadmath library\n')
87      self.have__float128 = 1
88      if hasattr(self.compilers, 'FC'):
89        self.libraries.pushLanguage('FC')
90        self.log.write('Checking Fortran works with quadmath library\n')
91        if self.libraries.check('quadmath','     ',call = '      real*16 s,w; w = 2.0 ;s = cos(w)'):
92          self.log.write('Fortran works with quadmath library\n')
93        else:
94          self.have__float128 = 0
95          self.log.write('Fortran fails with quadmath library\n')
96        self.libraries.popLanguage()
97      if self.have__float128:
98          self.libraries.add('quadmath','logq',prototype='#include <quadmath.h>',call='__float128 f; logq(f);')
99          self.addDefine('HAVE_REAL___FLOAT128', '1')
100
101    self.precision = self.framework.argDB['with-precision'].lower()
102    if self.precision == '__fp16':  # supported by gcc trunk
103      if self.scalartype == 'complex':
104        raise RuntimeError('__fp16 can only be used with real numbers, not complex')
105      if hasattr(self.compilers, 'FC'):
106        raise RuntimeError('__fp16 can only be used with C compiler, not Fortran')
107      self.addDefine('USE_REAL___FP16', '1')
108      self.addMakeMacro('PETSC_SCALAR_SIZE', '16')
109    elif self.precision == 'single':
110      self.addDefine('USE_REAL_SINGLE', '1')
111      self.addMakeMacro('PETSC_SCALAR_SIZE', '32')
112    elif self.precision == 'double':
113      self.addDefine('USE_REAL_DOUBLE', '1')
114      self.addMakeMacro('PETSC_SCALAR_SIZE', '64')
115    elif self.precision == '__float128':  # supported by gcc 4.6/gfortran and later
116      if self.have__float128:
117        self.addDefine('USE_REAL___FLOAT128', '1')
118        self.addMakeMacro('PETSC_SCALAR_SIZE', '128')
119      else:
120        raise RuntimeError('__float128 support not found. --with-precision=__float128 works with gcc-4.6 and newer compilers.')
121    else:
122      raise RuntimeError('--with-precision must be __fp16, single, double, or __float128')
123    self.logPrint('Precision is '+str(self.precision))
124    if self.precision == '__float128' and self.scalartype == 'complex' and self.languages.clanguage == 'Cxx':
125      raise RuntimeError('Cannot use --with-precision=__float128 --with-scalar-type=complex and --with-clanguage=cxx because C++ std:complex class has no support for __float128, use --with-clanguage=c')
126    return
127
128  def configure(self):
129    self.executeTest(self.configureScalarType)
130    self.executeTest(self.configurePrecision)
131    return
132