Coverage for eminus/config.py: 85.39%
89 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-18 08:43 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-18 08:43 +0000
1# SPDX-FileCopyrightText: 2021 The eminus developers
2# SPDX-License-Identifier: Apache-2.0
3"""Consolidated configuration module."""
5import numbers
6import os
7import pathlib
8import sys
10from .logger import log
13class ConfigClass:
14 """Configuration class holding user specifiable variables.
16 An instance of this class will be set as the same name as this module. This will effectively
17 make this module a singleton data class.
18 """
20 def __init__(self):
21 """Initialize the ConfigClass object."""
22 self.use_torch = True # Use the faster Torch FFTs if available
23 self.use_gpu = False # Disable GPU by default, since it is slower in my tests
24 self.use_pylibxc = True # Use Libxc over PySCF if available since it is faster
25 self.threads = None # Read threads from environment variables by default
26 self.verbose = "INFO" # Only display warnings (and worse) by default
28 # ### Class properties ###
30 @property
31 def use_torch(self):
32 """Whether to use Torch or SciPy if Torch is installed."""
33 # Add the logic in the getter method so it does not run on initialization since importing
34 # Torch is rather slow
35 if self._use_torch:
36 try:
37 import torch # noqa: F401
39 return True # noqa: TRY300
40 except ImportError:
41 pass
42 return False
44 @use_torch.setter
45 def use_torch(self, value):
46 self._use_torch = value
48 @property
49 def use_gpu(self):
50 """Whether to use Torch on the GPU if available."""
51 # Only use GPU if Torch is available
52 if self.use_torch and self._use_gpu:
53 import torch
55 return torch.cuda.is_available()
56 return False
58 @use_gpu.setter
59 def use_gpu(self, value):
60 self._use_gpu = value
62 @property
63 def use_pylibxc(self):
64 """Whether to use pylibxc or PySCF for functionals if both are installed."""
65 if self._use_pylibxc:
66 try:
67 import pylibxc # noqa: F401
69 return True # noqa: TRY300
70 except ImportError:
71 pass
72 return False
74 @use_pylibxc.setter
75 def use_pylibxc(self, value):
76 self._use_pylibxc = value
78 @property
79 def threads(self):
80 """Number of threads used in FFT calculations."""
81 if self._threads is None:
82 try:
83 if self.use_torch:
84 import torch
86 return torch.get_num_threads()
87 # Read the OMP threads for the default operators
88 return int(os.environ["OMP_NUM_THREADS"])
89 except KeyError:
90 return None
91 return int(self._threads)
93 @threads.setter
94 def threads(self, value):
95 self._threads = value
96 if isinstance(value, numbers.Integral):
97 if self.use_torch:
98 import torch
100 return torch.set_num_threads(value)
101 os.environ["OMP_NUM_THREADS"] = str(value)
102 return None
104 @property
105 def verbose(self):
106 """Logger verbosity level."""
107 return log.verbose
109 @verbose.setter
110 def verbose(self, value):
111 # Logic in setter to run it on initialization
112 log.verbose = value
114 # ### Class methods ###
116 def info(self):
117 """Print configuration and performance information."""
118 sys.stdout.write("--- Configuration infos ---\n")
119 sys.stdout.write(f"Global verbosity : {self.verbose}\n")
120 # Only print if PySCF or pylibxc is installed
121 if not self.use_pylibxc:
122 try:
123 import pyscf # noqa: F401
125 sys.stdout.write("Libxc backend : PySCF\n")
126 except ImportError:
127 pass
128 else:
129 sys.stdout.write("Libxc backend : pylibxc\n")
131 sys.stdout.write(
132 "\n--- Performance infos ---\n"
133 f"FFT backend : {'Torch' if self.use_torch else 'SciPy'}\n"
134 f"FFT device : {'GPU' if self.use_gpu else 'CPU'}\n"
135 )
136 # Do not print threading information when using GPU
137 if self.use_gpu:
138 return
139 # Check FFT threads
140 if self.threads is None:
141 sys.stdout.write(
142 "FFT threads : 1\n"
143 "INFO: No OMP_NUM_THREADS environment variable was found.\nTo improve "
144 'performance, add "export OMP_NUM_THREADS=n" to your ".bashrc".\nMake sure to '
145 'replace "n", typically with the number of cores your CPU.\nTemporarily, you can '
146 'set them in your Python environment with "eminus.config.threads=n".\n'
147 )
148 else:
149 sys.stdout.write(f"FFT threads : {self.threads}\n")
152# Do not initialize the class when Sphinx is running
153# Since we set the class instance to the module name Sphinx will only document the main docstring of
154# the class without the properties
155if "sphinx-build" not in pathlib.Path(sys.argv[0]).name:
156 sys.modules[__name__] = ConfigClass()