qupled 0.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ include qupled/Darwin/qupled.so
2
+ include qupled/Linux/qupled.so
qupled-0.0.2/PKG-INFO ADDED
@@ -0,0 +1,27 @@
1
+ Metadata-Version: 2.1
2
+ Name: qupled
3
+ Version: 0.0.2
4
+ Summary: qupled: a package to investigate quantum plasmas via the dielectric formalism
5
+ Author-email: Federico Lucco Castello <federico.luccocastello@gmail.com>
6
+ Classifier: Programming Language :: Python :: 3.10
7
+ Classifier: Operating System :: MacOS
8
+ Classifier: Operating System :: POSIX :: Linux
9
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
10
+ Requires-Python: <3.13,>=3.10
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: matplotlib~=3.7
13
+ Requires-Dist: numpy<2.0
14
+ Requires-Dist: pandas~=2.0
15
+ Requires-Dist: tables~=3.10
16
+ Provides-Extra: testing
17
+ Requires-Dist: pytest~=8.0; extra == "testing"
18
+ Requires-Dist: pytest-mock~=3.12; extra == "testing"
19
+ Provides-Extra: docs
20
+ Requires-Dist: sphinx-rtd-theme~=2.0.0; extra == "docs"
21
+ Requires-Dist: sphinxcontrib-applehelp~=2.0.0; extra == "docs"
22
+ Requires-Dist: sphinxcontrib-devhelp~=2.0.0; extra == "docs"
23
+ Requires-Dist: sphinxcontrib-htmlhelp~=2.1.0; extra == "docs"
24
+ Requires-Dist: sphinxcontrib-jquery~=4.1; extra == "docs"
25
+ Requires-Dist: sphinxcontrib-jsmath~=1.0.1; extra == "docs"
26
+ Requires-Dist: sphinxcontrib-qthelp~=2.0.0; extra == "docs"
27
+ Requires-Dist: sphinxcontrib-serializinghtml~=2.0.0; extra == "docs"
@@ -0,0 +1,40 @@
1
+ [project]
2
+ name = "qupled"
3
+ version = "0.0.2"
4
+ description = "qupled: a package to investigate quantum plasmas via the dielectric formalism"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10, <3.13"
7
+ authors = [
8
+ { name = "Federico Lucco Castello", email = "federico.luccocastello@gmail.com" }
9
+ ]
10
+ classifiers = [
11
+ "Programming Language :: Python :: 3.10",
12
+ "Operating System :: MacOS",
13
+ "Operating System :: POSIX :: Linux",
14
+ "License :: OSI Approved :: GNU General Public License v3 (GPLv3)"
15
+ ]
16
+ dependencies = [
17
+ "matplotlib~=3.7",
18
+ "numpy<2.0",
19
+ "pandas~=2.0",
20
+ "tables~=3.10"
21
+ ]
22
+
23
+ [project.optional-dependencies]
24
+ testing = [
25
+ "pytest~=8.0",
26
+ "pytest-mock~=3.12"
27
+ ]
28
+ docs = [
29
+ "sphinx-rtd-theme~=2.0.0",
30
+ "sphinxcontrib-applehelp~=2.0.0",
31
+ "sphinxcontrib-devhelp~=2.0.0",
32
+ "sphinxcontrib-htmlhelp~=2.1.0",
33
+ "sphinxcontrib-jquery~=4.1",
34
+ "sphinxcontrib-jsmath~=1.0.1",
35
+ "sphinxcontrib-qthelp~=2.0.0",
36
+ "sphinxcontrib-serializinghtml~=2.0.0"
37
+ ]
38
+
39
+ [tool.setuptools]
40
+ include-package-data = true
Binary file
Binary file
@@ -0,0 +1,9 @@
1
+ import platform
2
+
3
+ system = platform.system()
4
+ if system == "Linux":
5
+ import qupled.Linux.qupled as native
6
+ elif system == "Darwin":
7
+ import qupled.Darwin.qupled as native
8
+ else:
9
+ raise ImportError(f"Platform {system} is not supported")
@@ -0,0 +1,489 @@
1
+ from __future__ import annotations
2
+ import sys
3
+ import os
4
+ import numpy as np
5
+ import pandas as pd
6
+ from qupled import native
7
+ import qupled.util as qu
8
+
9
+
10
+ # -----------------------------------------------------------------------
11
+ # _ClassicScheme class
12
+ # -----------------------------------------------------------------------
13
+
14
+
15
+ class _ClassicScheme:
16
+
17
+ def __init__(self):
18
+ # File to store output on disk
19
+ self.hdfFileName: str = None #: Name of the output file.
20
+
21
+ # Compute the scheme
22
+ def _compute(self, scheme) -> None:
23
+ self.hdfFileName = self._getHdfFile(scheme.inputs)
24
+ status = scheme.compute()
25
+ self._checkStatusAndClean(status, scheme.recovery)
26
+
27
+ # Check that the dielectric scheme was solved without errors
28
+ @qu.MPI.runOnlyOnRoot
29
+ def _checkStatusAndClean(self, status: bool, recovery: str) -> None:
30
+ """Checks that the scheme was solved correctly and removes temporarary files generated at run-time
31
+
32
+ Args:
33
+ status: status obtained from the native code. If status == 0 the scheme was solved correctly.
34
+ recovery: name of the recovery file.
35
+ """
36
+ if status == 0:
37
+ if os.path.isfile(recovery):
38
+ os.remove(recovery)
39
+ print("Dielectric theory solved successfully!")
40
+ else:
41
+ sys.exit("Error while solving the dielectric theory")
42
+
43
+ # Save results to disk
44
+ def _getHdfFile(self, inputs) -> str:
45
+ """Sets the name of the hdf file used to store the output
46
+
47
+ Args:
48
+ inputs: input parameters
49
+ """
50
+ coupling = inputs.coupling
51
+ degeneracy = inputs.degeneracy
52
+ theory = inputs.theory
53
+ return f"rs{coupling:5.3f}_theta{degeneracy:5.3f}_{theory}.h5"
54
+
55
+ @qu.MPI.runOnlyOnRoot
56
+ def _save(self, scheme) -> None:
57
+ inputs = scheme.inputs
58
+ """Stores the results obtained by solving the scheme."""
59
+ pd.DataFrame(
60
+ {
61
+ "coupling": inputs.coupling,
62
+ "degeneracy": inputs.degeneracy,
63
+ "theory": inputs.theory,
64
+ "resolution": inputs.resolution,
65
+ "cutoff": inputs.cutoff,
66
+ "matsubara": inputs.matsubara,
67
+ },
68
+ index=["info"],
69
+ ).to_hdf(self.hdfFileName, key="info", mode="w")
70
+ pd.DataFrame(scheme.idr).to_hdf(self.hdfFileName, key="idr")
71
+ pd.DataFrame(scheme.sdr).to_hdf(self.hdfFileName, key="sdr")
72
+ pd.DataFrame(scheme.slfc).to_hdf(self.hdfFileName, key="slfc")
73
+ pd.DataFrame(scheme.ssf).to_hdf(self.hdfFileName, key="ssf")
74
+ pd.DataFrame(scheme.ssfHF).to_hdf(self.hdfFileName, key="ssfHF")
75
+ pd.DataFrame(scheme.wvg).to_hdf(self.hdfFileName, key="wvg")
76
+
77
+ # Compute radial distribution function
78
+ def computeRdf(
79
+ self, rdfGrid: np.ndarray = None, writeToHdf: bool = True
80
+ ) -> np.array:
81
+ """Computes the radial distribution function from the data stored in the output file.
82
+
83
+ Args:
84
+ rdfGrid: The grid used to compute the radial distribution function.
85
+ Default = ``None`` (see :func:`qupled.util.Hdf.computeRdf`)
86
+ writeToHdf: Flag marking whether the rdf data should be added to the output hdf file, default to True
87
+
88
+ Returns:
89
+ The radial distribution function
90
+
91
+ """
92
+ if qu.MPI().getRank() > 0:
93
+ writeToHdf = False
94
+ return qu.Hdf().computeRdf(self.hdfFileName, rdfGrid, writeToHdf)
95
+
96
+ # Compute the internal energy
97
+ def computeInternalEnergy(self) -> float:
98
+ """Computes the internal energy from the data stored in the output file.
99
+
100
+ Returns:
101
+ The internal energy
102
+
103
+ """
104
+ return qu.Hdf().computeInternalEnergy(self.hdfFileName)
105
+
106
+ # Plot results
107
+ @qu.MPI.runOnlyOnRoot
108
+ def plot(
109
+ self,
110
+ toPlot: list[str],
111
+ matsubara: np.ndarray = None,
112
+ rdfGrid: np.ndarray = None,
113
+ ) -> None:
114
+ """Plots the results stored in the output file.
115
+
116
+ Args:
117
+ toPlot: A list of quantities to plot. This list can include all the values written to the
118
+ output hdf file. The radial distribution funciton is computed and added to the output
119
+ file if necessary
120
+ matsubara: A list of matsubara frequencies to plot. Applies only when the idr is plotted.
121
+ (Default = None, all matsubara frequencies are plotted)
122
+ rdfGrid: The grid used to compute the radial distribution function. Applies only when the radial
123
+ distribution function is plotted. Default = ``None`` (see :func:`qupled.util.Hdf.computeRdf`).
124
+
125
+ """
126
+ if "rdf" in toPlot:
127
+ self.computeRdf(rdfGrid)
128
+ qu.Hdf().plot(self.hdfFileName, toPlot, matsubara)
129
+
130
+
131
+ # -----------------------------------------------------------------------
132
+ # RPA class
133
+ # -----------------------------------------------------------------------
134
+
135
+
136
+ class Rpa(_ClassicScheme):
137
+
138
+ # Compute
139
+ @qu.MPI.recordTime
140
+ @qu.MPI.synchronizeRanks
141
+ def compute(self, inputs: Rpa.Input) -> None:
142
+ """
143
+ Solves the scheme and saves the results.
144
+
145
+ Args:
146
+ inputs: Input parameters.
147
+ """
148
+ scheme = native.Rpa(inputs.toNative())
149
+ self._compute(scheme)
150
+ self._save(scheme)
151
+
152
+ # Input class
153
+ class Input:
154
+ """
155
+ Class used to manage the input for the :obj:`qupled.classic.Rpa` class.
156
+ """
157
+
158
+ def __init__(self, coupling: float, degeneracy: float):
159
+ self.coupling: float = coupling
160
+ """Coupling parameter."""
161
+ self.degeneracy: float = degeneracy
162
+ """Degeneracy parameter."""
163
+ self.chemicalPotential: list[float] = [-10.0, 10.0]
164
+ """Initial guess for the chemical potential. Default = ``[-10, 10]``"""
165
+ self.matsubara: int = 128
166
+ """Number of Matsubara frequencies. Default = ``128``"""
167
+ self.resolution: float = 0.1
168
+ """Resolution of the wave-vector grid. Default = ``0.1``"""
169
+ self.cutoff: float = 10.0
170
+ """Cutoff for the wave-vector grid. Default = ``10.0``"""
171
+ self.intError: float = 1.0e-5
172
+ """Accuracy (relative error) in the computation of integrals. Default = ``1.0e-5``"""
173
+ self.int2DScheme: str = "full"
174
+ """
175
+ Scheme used to solve two-dimensional integrals
176
+ allowed options include:
177
+
178
+ - full: the inner integral is evaluated at arbitrary points
179
+ selected automatically by the quadrature rule
180
+
181
+ - segregated: the inner integral is evaluated on a fixed
182
+ grid that depends on the integrand that is being processed
183
+
184
+ Segregated is usually faster than full but it could become
185
+ less accurate if the fixed points are not chosen correctly. Default = ``'full'``
186
+ """
187
+ self.threads: int = 1
188
+ """Number of OMP threads for parallel calculations. Default = ``1``"""
189
+ self.theory: str = "RPA"
190
+
191
+ def toNative(self) -> native.RpaInput:
192
+ native_input = native.RpaInput()
193
+ for attr, value in self.__dict__.items():
194
+ setattr(native_input, attr, value)
195
+ return native_input
196
+
197
+
198
+ # -----------------------------------------------------------------------
199
+ # ESA class
200
+ # -----------------------------------------------------------------------
201
+
202
+
203
+ class ESA(_ClassicScheme):
204
+ """
205
+ Args:
206
+ inputs: Input parameters.
207
+ """
208
+
209
+ # Compute
210
+ @qu.MPI.recordTime
211
+ @qu.MPI.synchronizeRanks
212
+ def compute(self, inputs: ESA.Input) -> None:
213
+ """
214
+ Solves the scheme and saves the results.
215
+
216
+ Args:
217
+ inputs: Input parameters.
218
+ """
219
+ scheme = native.ESA(inputs.toNative())
220
+ self._compute(scheme)
221
+ self._save(scheme)
222
+
223
+ # Input class
224
+ class Input(Rpa.Input):
225
+ """
226
+ Class used to manage the input for the :obj:`qupled.classic.ESA` class.
227
+ """
228
+
229
+ def __init__(self, coupling: float, degeneracy: float):
230
+ super().__init__(coupling, degeneracy)
231
+ # Undocumented default values
232
+ self.theory = "ESA"
233
+
234
+
235
+ # -----------------------------------------------------------------------
236
+ # _IterativeScheme class
237
+ # -----------------------------------------------------------------------
238
+
239
+
240
+ class _IterativeScheme(_ClassicScheme):
241
+
242
+ # Set the initial guess from a dataframe produced in output
243
+ @staticmethod
244
+ def getInitialGuess(fileName: str) -> _IterativeScheme.Guess:
245
+ """Constructs an initial guess object by extracting the information from an output file.
246
+
247
+ Args:
248
+ fileName : name of the file used to extract the information for the initial guess.
249
+ """
250
+ hdfData = qu.Hdf().read(fileName, ["wvg", "slfc"])
251
+ return _IterativeScheme.Guess(hdfData["wvg"], hdfData["slfc"])
252
+
253
+ # Save results to disk
254
+ @qu.MPI.runOnlyOnRoot
255
+ def _save(self, scheme) -> None:
256
+ """Stores the results obtained by solving the scheme."""
257
+ super()._save(scheme)
258
+ inputs = scheme.inputs
259
+ pd.DataFrame(
260
+ {
261
+ "coupling": inputs.coupling,
262
+ "degeneracy": inputs.degeneracy,
263
+ "error": scheme.error,
264
+ "theory": inputs.theory,
265
+ "resolution": inputs.resolution,
266
+ "cutoff": inputs.cutoff,
267
+ "matsubara": inputs.matsubara,
268
+ },
269
+ index=["info"],
270
+ ).to_hdf(self.hdfFileName, key="info")
271
+
272
+ # Initial guess
273
+ class Guess:
274
+
275
+ def __init__(self, wvg: np.ndarray = None, slfc: np.ndarray = None):
276
+ self.wvg = wvg
277
+ """ Wave-vector grid. Default = ``None``"""
278
+ self.slfc = slfc
279
+ """ Static local field correction. Default = ``None``"""
280
+
281
+ def toNative(self) -> native.StlsGuess:
282
+ native_guess = native.StlsGuess()
283
+ for attr, value in self.__dict__.items():
284
+ native_value = value if value is not None else np.empty(0)
285
+ setattr(native_guess, attr, native_value)
286
+ return native_guess
287
+
288
+
289
+ # -----------------------------------------------------------------------
290
+ # Stls class
291
+ # -----------------------------------------------------------------------
292
+
293
+
294
+ class Stls(_IterativeScheme):
295
+
296
+ # Compute
297
+ @qu.MPI.recordTime
298
+ @qu.MPI.synchronizeRanks
299
+ def compute(self, inputs: Stls.Input) -> None:
300
+ """
301
+ Solves the scheme and saves the results.
302
+
303
+ Args:
304
+ inputs: Input parameters.
305
+ """
306
+ scheme = native.Stls(inputs.toNative())
307
+ self._compute(scheme)
308
+ self._save(scheme)
309
+
310
+ # Input class
311
+ class Input(Rpa.Input):
312
+ """
313
+ Class used to manage the input for the :obj:`qupled.classic.Stls` class.
314
+ """
315
+
316
+ def __init__(self, coupling: float, degeneracy: float):
317
+ super().__init__(coupling, degeneracy)
318
+ self.error: float = 1.0e-5
319
+ """Minimum error for convergence. Default = ``1.0e-5``"""
320
+ self.mixing: float = 1.0
321
+ """Mixing parameter. Default = ``1.0``"""
322
+ self.iterations: int = 1000
323
+ """Maximum number of iterations. Default = ``1000``"""
324
+ self.outputFrequency: int = 10
325
+ """Output frequency to write the recovery file. Default = ``10``"""
326
+ self.recoveryFile: str = ""
327
+ """Name of the recovery file. Default = ``""``"""
328
+ self.guess: Stls.Guess = Stls.Guess()
329
+ """Initial guess. Default = ``Stls.Guess()``"""
330
+ # Undocumented default values
331
+ self.theory: str = "STLS"
332
+
333
+ def toNative(self) -> native.StlsInput:
334
+ native_input = native.StlsInput()
335
+ for attr, value in self.__dict__.items():
336
+ if attr == "guess":
337
+ setattr(native_input, attr, value.toNative())
338
+ else:
339
+ setattr(native_input, attr, value)
340
+ return native_input
341
+
342
+
343
+ # -----------------------------------------------------------------------
344
+ # StlsIet class
345
+ # -----------------------------------------------------------------------
346
+
347
+
348
+ class StlsIet(_IterativeScheme):
349
+
350
+ # Compute
351
+ @qu.MPI.recordTime
352
+ @qu.MPI.synchronizeRanks
353
+ def compute(self, inputs: StlsIet.Input) -> None:
354
+ """
355
+ Solves the scheme and saves the results.
356
+
357
+ Args:
358
+ inputs: Input parameters.
359
+ """
360
+ scheme = native.Stls(inputs.toNative())
361
+ self._compute(scheme)
362
+ self._save(scheme)
363
+
364
+ # Save results to disk
365
+ @qu.MPI.runOnlyOnRoot
366
+ def _save(self, scheme) -> None:
367
+ """Stores the results obtained by solving the scheme."""
368
+ super()._save(scheme)
369
+ pd.DataFrame(scheme.bf).to_hdf(self.hdfFileName, key="bf")
370
+
371
+ # Input class
372
+ class Input(Stls.Input):
373
+ """
374
+ Class used to manage the input for the :obj:`qupled.classic.StlsIet` class.
375
+ Accepted theories: ``STLS-HNC``, ``STLS-IOI`` and ``STLS-LCT``.
376
+ """
377
+
378
+ def __init__(self, coupling: float, degeneracy: float, theory: str):
379
+ super().__init__(coupling, degeneracy)
380
+ if theory not in {"STLS-HNC", "STLS-IOI", "STLS-LCT"}:
381
+ sys.exit("Invalid dielectric theory")
382
+ self.theory = theory
383
+ self.mapping = "standard"
384
+ r"""
385
+ Mapping for the classical-to-quantum coupling parameter
386
+ :math:`\Gamma` used in the iet schemes. Allowed options include:
387
+
388
+ - standard: :math:`\Gamma \propto \Theta^{-1}`
389
+
390
+ - sqrt: :math:`\Gamma \propto (1 + \Theta)^{-1/2}`
391
+
392
+ - linear: :math:`\Gamma \propto (1 + \Theta)^{-1}`
393
+
394
+ where :math:`\Theta` is the degeneracy parameter. Far from the ground state
395
+ (i.e. :math:`\Theta\gg1`) all mappings lead identical results, but at
396
+ the ground state they can differ significantly (the standard
397
+ mapping diverges). Default = ``standard``.
398
+ """
399
+
400
+ def toNative(self) -> native.StlsInput:
401
+ native_input = native.StlsInput()
402
+ for attr, value in self.__dict__.items():
403
+ if attr == "guess":
404
+ setattr(native_input, attr, value.toNative())
405
+ else:
406
+ setattr(native_input, attr, value)
407
+ return native_input
408
+
409
+
410
+ # -----------------------------------------------------------------------
411
+ # VSStls class
412
+ # -----------------------------------------------------------------------
413
+
414
+
415
+ class VSStls(_IterativeScheme):
416
+
417
+ # Compute
418
+ @qu.MPI.recordTime
419
+ @qu.MPI.synchronizeRanks
420
+ def compute(self, inputs: VSStls.Input) -> None:
421
+ """
422
+ Solves the scheme and saves the results.
423
+
424
+ Args:
425
+ inputs: Input parameters.
426
+ """
427
+ scheme = native.VSStls(inputs.toNative())
428
+ self._compute(scheme)
429
+ self._save(scheme)
430
+
431
+ # Save results
432
+ @qu.MPI.runOnlyOnRoot
433
+ def _save(self, scheme) -> None:
434
+ """Stores the results obtained by solving the scheme."""
435
+ super()._save(scheme)
436
+ pd.DataFrame(scheme.freeEnergyGrid).to_hdf(self.hdfFileName, key="fxcGrid")
437
+ pd.DataFrame(scheme.freeEnergyIntegrand).to_hdf(self.hdfFileName, key="fxci")
438
+ pd.DataFrame(scheme.alpha).to_hdf(self.hdfFileName, key="alpha")
439
+
440
+ # Set the free energy integrand from a dataframe produced in output
441
+ @staticmethod
442
+ def getFreeEnergyIntegrand(fileName: str) -> native.FreeEnergyIntegrand():
443
+ """Constructs the free energy integrand by extracting the information from an output file.
444
+
445
+ Args:
446
+ fileName : name of the file used to extract the information for the free energy integrand.
447
+ """
448
+ fxci = native.FreeEnergyIntegrand()
449
+ hdfData = qu.Hdf().read(fileName, ["fxcGrid", "fxci", "alpha"])
450
+ fxci.grid = hdfData["fxcGrid"]
451
+ fxci.integrand = np.ascontiguousarray(hdfData["fxci"])
452
+ fxci.alpha = hdfData["alpha"]
453
+ return fxci
454
+
455
+ # Input class
456
+ class Input(Stls.Input):
457
+ """
458
+ Class used to manage the input for the :obj:`qupled.classic.VSStls` class.
459
+ """
460
+
461
+ def __init__(self, coupling: float, degeneracy: float):
462
+ super().__init__(coupling, degeneracy)
463
+ self.alpha: list[float] = [0.5, 1.0]
464
+ """Initial guess for the free parameter. Default = ``[0.5, 1.0]``"""
465
+ self.couplingResolution: float = 0.1
466
+ """Resolution of the coupling parameter grid. Default = ``0.1``"""
467
+ self.degeneracyResolution: float = 0.1
468
+ """Resolution of the degeneracy parameter grid. Default = ``0.1``"""
469
+ self.errorAlpha: float = 1.0e-3
470
+ """Minimum error for convergence in the free parameter. Default = ``1.0e-3``"""
471
+ self.iterationsAlpha: int = 50
472
+ """Maximum number of iterations to determine the free parameter. Default = ``50``"""
473
+ self.freeEnergyIntegrand: qupled.FreeEnergyIntegrand = (
474
+ native.FreeEnergyIntegrand()
475
+ )
476
+ """Pre-computed free energy integrand."""
477
+ self.threads: int = 9
478
+ """Number of threads. Default = ``9``"""
479
+ # Undocumented default values
480
+ self.theory: str = "VSSTLS"
481
+
482
+ def toNative(self) -> native.VSStlsInput:
483
+ native_input = native.VSStlsInput()
484
+ for attr, value in self.__dict__.items():
485
+ if attr == "guess":
486
+ setattr(native_input, attr, value.toNative())
487
+ else:
488
+ setattr(native_input, attr, value)
489
+ return native_input
@@ -0,0 +1,300 @@
1
+ from __future__ import annotations
2
+
3
+ import sys
4
+ import os
5
+ from shutil import rmtree
6
+ from glob import glob
7
+ import zipfile as zf
8
+ import numpy as np
9
+ import pandas as pd
10
+ from qupled import native
11
+ import qupled.util as qu
12
+ import qupled.classic as qc
13
+
14
+ # -----------------------------------------------------------------------
15
+ # _QuantumIterativeScheme class
16
+ # -----------------------------------------------------------------------
17
+
18
+
19
+ class _QuantumIterativeScheme(qc._IterativeScheme):
20
+
21
+ # Set the initial guess from a dataframe produced in output
22
+ @staticmethod
23
+ def getInitialGuess(fileName: str) -> _QuantumIterativeScheme.Guess:
24
+ """Constructs an initial guess object by extracting the information from an output file.
25
+
26
+ Args:
27
+ fileName : name of the file used to extract the information for the initial guess.
28
+ """
29
+ hdfData = qu.Hdf().read(fileName, ["wvg", "ssf", "adr", "matsubara"])
30
+ return _QuantumIterativeScheme.Guess(
31
+ hdfData["wvg"],
32
+ hdfData["ssf"],
33
+ np.ascontiguousarray(hdfData["adr"]),
34
+ hdfData["matsubara"],
35
+ )
36
+
37
+ # Save results to disk
38
+ @qu.MPI.runOnlyOnRoot
39
+ def _save(self, scheme) -> None:
40
+ """Stores the results obtained by solving the scheme."""
41
+ super()._save(scheme)
42
+ pd.DataFrame(scheme.adr).to_hdf(self.hdfFileName, key="adr")
43
+
44
+ # Initial guess
45
+ class Guess:
46
+
47
+ def __init__(
48
+ self,
49
+ wvg: np.ndarray = None,
50
+ ssf: np.ndarray = None,
51
+ adr: np.ndarray = None,
52
+ matsubara: int = 0,
53
+ ):
54
+ self.wvg = wvg
55
+ """ Wave-vector grid. Default = ``None``"""
56
+ self.ssf = ssf
57
+ """ Static structure factor. Default = ``None``"""
58
+ self.adr = adr
59
+ """ Auxiliary density response. Default = ``None``"""
60
+ self.matsubara = matsubara
61
+ """ Number of matsubara frequencies. Default = ``0``"""
62
+
63
+ def toNative(self) -> native.QStlsGuess:
64
+ native_guess = native.QstlsGuess()
65
+ for attr, value in self.__dict__.items():
66
+ native_value = value if value is not None else np.empty(0)
67
+ setattr(native_guess, attr, native_value)
68
+ return native_guess
69
+
70
+
71
+ # -----------------------------------------------------------------------
72
+ # Qstls class
73
+ # -----------------------------------------------------------------------
74
+
75
+
76
+ class Qstls(_QuantumIterativeScheme):
77
+
78
+ # Compute
79
+ @qu.MPI.recordTime
80
+ @qu.MPI.synchronizeRanks
81
+ def compute(self, inputs: Qstls.Input) -> None:
82
+ """
83
+ Solves the scheme and saves the results.
84
+
85
+ Args:
86
+ inputs: Input parameters.
87
+ """
88
+ scheme = native.Qstls(inputs.toNative())
89
+ self._compute(scheme)
90
+ self._save(scheme)
91
+
92
+ # Input class
93
+ class Input(qc.Stls.Input):
94
+ """
95
+ Class used to manage the input for the :obj:`qupled.quantum.Qstls` class.
96
+ """
97
+
98
+ def __init__(self, coupling: float, degeneracy: float):
99
+ super().__init__(coupling, degeneracy)
100
+ self.fixed: str = ""
101
+ """ Name of the file storing the fixed component of the auxiliary density
102
+ response in the QSTLS scheme. """
103
+ self.guess: Qstls.Guess = Qstls.Guess()
104
+ """Initial guess. Default = ``Qstls.Guess()``"""
105
+ # Undocumented default values
106
+ self.theory = "QSTLS"
107
+
108
+ def toNative(self) -> native.QstlsInput:
109
+ native_input = native.QstlsInput()
110
+ for attr, value in self.__dict__.items():
111
+ if attr == "guess":
112
+ setattr(native_input, attr, value.toNative())
113
+ else:
114
+ setattr(native_input, attr, value)
115
+ return native_input
116
+
117
+
118
+ # -----------------------------------------------------------------------
119
+ # QstlsIet class
120
+ # -----------------------------------------------------------------------
121
+
122
+
123
+ class QstlsIet(_QuantumIterativeScheme):
124
+ """
125
+ Args:
126
+ inputs: Input parameters.
127
+ """
128
+
129
+ # Compute
130
+ @qu.MPI.recordTime
131
+ @qu.MPI.synchronizeRanks
132
+ def compute(self, inputs: QsltsIet.Input) -> None:
133
+ """
134
+ Solves the scheme and saves the results.
135
+
136
+ Args:
137
+ inputs: Input parameters.
138
+ """
139
+ self._unpackFixedAdrFiles(inputs)
140
+ scheme = native.Qstls(inputs.toNative())
141
+ self._compute(scheme)
142
+ self._save(scheme)
143
+ self._zipFixedAdrFiles(inputs)
144
+ self._cleanFixedAdrFiles(scheme.inputs)
145
+
146
+ # Unpack zip folder with fixed component of the auxiliary density response
147
+ @qu.MPI.runOnlyOnRoot
148
+ def _unpackFixedAdrFiles(self, inputs) -> None:
149
+ fixedIetSourceFile = inputs.fixediet
150
+ if inputs.fixediet != "":
151
+ inputs.fixediet = "qupled_tmp_run_directory"
152
+ if fixedIetSourceFile != "":
153
+ with zf.ZipFile(fixedIetSourceFile, "r") as zipFile:
154
+ zipFile.extractall(inputs.fixediet)
155
+
156
+ # Save results to disk
157
+ @qu.MPI.runOnlyOnRoot
158
+ def _save(self, scheme) -> None:
159
+ super()._save(scheme)
160
+ pd.DataFrame(scheme.bf).to_hdf(self.hdfFileName, key="bf")
161
+
162
+ # Zip all files for the fixed component of the auxiliary density response
163
+ @qu.MPI.runOnlyOnRoot
164
+ def _zipFixedAdrFiles(self, inputs) -> None:
165
+ if inputs.fixediet == "":
166
+ degeneracy = inputs.degeneracy
167
+ matsubara = inputs.matsubara
168
+ theory = inputs.theory
169
+ adrFile = f"adr_fixed_theta{degeneracy:5.3f}_matsubara{matsubara}_{theory}"
170
+ adrFileZip = f"{adrFile}.zip"
171
+ adrFileBin = f"{adrFile}_wv*.bin"
172
+ with zf.ZipFile(adrFileZip, "w") as zipFile:
173
+ for binFile in glob(adrFileBin):
174
+ zipFile.write(binFile)
175
+ os.remove(binFile)
176
+
177
+ # Remove temporaray run directory
178
+ @qu.MPI.runOnlyOnRoot
179
+ def _cleanFixedAdrFiles(self, inputs) -> None:
180
+ if os.path.isdir(inputs.fixediet):
181
+ rmtree(inputs.fixediet)
182
+
183
+ # Input class
184
+ class Input(qc.StlsIet.Input, Qstls.Input):
185
+ """
186
+ Class used to manage the input for the :obj:`qupled.classic.QStlsIet` class.
187
+ Accepted theories: ``QSTLS-HNC``, ``QSTLS-IOI`` and ``QSTLS-LCT``.
188
+ """
189
+
190
+ def __init__(self, coupling: float, degeneracy: float, theory: str):
191
+ qc.StlsIet.Input.__init__(self, coupling, degeneracy, "STLS-HNC")
192
+ Qstls.Input.__init__(self, coupling, degeneracy)
193
+ if theory not in {"QSTLS-HNC", "QSTLS-IOI", "QSTLS-LCT"}:
194
+ sys.exit("Invalid dielectric theory")
195
+ self.theory = theory
196
+ self.fixediet = ""
197
+ """
198
+ Name of the zip file storing the iet part of the fixed components
199
+ of the auxiliary density response. Default = ``""``
200
+ """
201
+
202
+ def toNative(self) -> native.QstlsInput:
203
+ native_input = native.QstlsInput()
204
+ for attr, value in self.__dict__.items():
205
+ if attr == "guess":
206
+ setattr(native_input, attr, value.toNative())
207
+ else:
208
+ setattr(native_input, attr, value)
209
+ return native_input
210
+
211
+
212
+ # -----------------------------------------------------------------------
213
+ # QVSStls class
214
+ # -----------------------------------------------------------------------
215
+
216
+
217
+ class QVSStls(_QuantumIterativeScheme):
218
+
219
+ # Compute
220
+ @qu.MPI.recordTime
221
+ @qu.MPI.synchronizeRanks
222
+ def compute(self, inputs: QVSStls.Input) -> None:
223
+ """
224
+ Solves the scheme and saves the results.
225
+
226
+ Args:
227
+ inputs: Input parameters.
228
+ """
229
+ self._unpackFixedAdrFiles(inputs)
230
+ scheme = native.QVSStls(inputs.toNative())
231
+ self._compute(scheme)
232
+ self._save(scheme)
233
+ self._zipFixedAdrFiles(inputs)
234
+ self._cleanFixedAdrFiles(scheme.inputs)
235
+
236
+ # Unpack zip folder with fixed component of the auxiliary density response
237
+ @qu.MPI.runOnlyOnRoot
238
+ def _unpackFixedAdrFiles(self, inputs) -> None:
239
+ fixedSourceFile = inputs.fixed
240
+ if inputs.fixed != "":
241
+ inputs.fixed = "qupled_tmp_run_directory"
242
+ if fixedSourceFile != "":
243
+ with zf.ZipFile(fixedSourceFile, "r") as zipFile:
244
+ zipFile.extractall(inputs.fixed)
245
+
246
+ # Save results to disk
247
+ @qu.MPI.runOnlyOnRoot
248
+ def _save(self, scheme) -> None:
249
+ super()._save(scheme)
250
+ pd.DataFrame(scheme.freeEnergyGrid).to_hdf(self.hdfFileName, key="fxcGrid")
251
+ pd.DataFrame(scheme.freeEnergyIntegrand).to_hdf(self.hdfFileName, key="fxci")
252
+ pd.DataFrame(scheme.alpha).to_hdf(self.hdfFileName, key="alpha")
253
+
254
+ # Zip all files for the fixed component of the auxiliary density response
255
+ @qu.MPI.runOnlyOnRoot
256
+ def _zipFixedAdrFiles(self, inputs) -> None:
257
+ if inputs.fixed == "":
258
+ degeneracy = inputs.degeneracy
259
+ matsubara = inputs.matsubara
260
+ theory = inputs.theory
261
+ adrFileZip = (
262
+ f"adr_fixed_theta{degeneracy:5.3f}_matsubara{matsubara}_{theory}.zip"
263
+ )
264
+ adrFileBin = "THETA*.bin"
265
+ with zf.ZipFile(adrFileZip, "w") as zipFile:
266
+ for binFile in glob(adrFileBin):
267
+ zipFile.write(binFile)
268
+ os.remove(binFile)
269
+
270
+ # Remove the temporary run directory
271
+ @qu.MPI.runOnlyOnRoot
272
+ def _cleanFixedAdrFiles(self, inputs) -> None:
273
+ if os.path.isdir(inputs.fixed):
274
+ rmtree(inputs.fixed)
275
+
276
+ # Set the free energy integrand from a dataframe produced in output
277
+ @staticmethod
278
+ def getFreeEnergyIntegrand(fileName: str) -> native.FreeEnergyIntegrand():
279
+ return qc.VSStls.getFreeEnergyIntegrand(fileName)
280
+
281
+ # Input class
282
+ class Input(qc.VSStls.Input, Qstls.Input):
283
+ """
284
+ Class used to manage the input for the :obj:`qupled.classic.QVSStls` class.
285
+ """
286
+
287
+ def __init__(self, coupling: float, degeneracy: float):
288
+ qc.VSStls.Input.__init__(self, coupling, degeneracy)
289
+ Qstls.Input.__init__(self, coupling, degeneracy)
290
+ # Undocumented default values
291
+ self.theory: str = "QVSSTLS"
292
+
293
+ def toNative(self) -> native.QVSStlsInput:
294
+ native_input = native.QVSStlsInput()
295
+ for attr, value in self.__dict__.items():
296
+ if attr == "guess":
297
+ setattr(native_input, attr, value.toNative())
298
+ else:
299
+ setattr(native_input, attr, value)
300
+ return native_input
@@ -0,0 +1,330 @@
1
+ import sys
2
+ import os
3
+ import numpy as np
4
+ import pandas as pd
5
+ import matplotlib.pyplot as plt
6
+ from matplotlib import colormaps as cm
7
+ import functools
8
+ from qupled import native
9
+
10
+ # -----------------------------------------------------------------------
11
+ # Hdf class
12
+ # -----------------------------------------------------------------------
13
+
14
+
15
+ class Hdf:
16
+ """Class to manipulate the output hdf files produced when a scheme is solved."""
17
+
18
+ # Construct
19
+ def __init__(self):
20
+ # The first entry is a descriptive name of the
21
+ self.entries = {
22
+ "alpha": self.Entries("Free Parameter for VS schemes", "numpy"),
23
+ "adr": self.Entries("Auxiliary density response", "numpy2D"),
24
+ "bf": self.Entries("Bridge function adder", "numpy"),
25
+ "coupling": self.Entries("Coupling parameter", "number"),
26
+ "cutoff": self.Entries("Cutoff for the wave-vector grid", "number"),
27
+ "degeneracy": self.Entries("Degeneracy parameter", "number"),
28
+ "error": self.Entries("Residual error in the solution", "number"),
29
+ "fxcGrid": self.Entries("Coupling parameter", "numpy"),
30
+ "fxci": self.Entries("Free Energy integrand", "numpy2D"),
31
+ "matsubara": self.Entries("Number of matsubara frequencies", "number"),
32
+ "idr": self.Entries("Ideal density response", "numpy2D"),
33
+ "resolution": self.Entries("Resolution for the wave-vector grid", "number"),
34
+ "rdf": self.Entries("Radial distribution function", "numpy"),
35
+ "rdfGrid": self.Entries("Inter-particle distance", "numpy"),
36
+ "sdr": self.Entries("Static density response", "numpy"),
37
+ "slfc": self.Entries("Static local field correction", "numpy"),
38
+ "ssf": self.Entries("Static structure factor", "numpy"),
39
+ "ssfHF": self.Entries("Hartree-Fock static structure factor", "numpy"),
40
+ "theory": self.Entries("Theory that is being solved", "string"),
41
+ "wvg": self.Entries("Wave-vector", "numpy"),
42
+ }
43
+
44
+ # Structure used to cathegorize the entries stored in the hdf file
45
+ class Entries:
46
+ def __init__(self, description, entryType):
47
+ self.description = description # Descriptive string of the entry
48
+ self.entryType = (
49
+ entryType # Type of entry (numpy, numpy2, number or string)
50
+ )
51
+ assert (
52
+ self.entryType == "numpy"
53
+ or self.entryType == "numpy2D"
54
+ or self.entryType == "number"
55
+ or self.entryType == "string"
56
+ )
57
+
58
+ # Read data in hdf file
59
+ def read(self, hdf: str, toRead: list[str]) -> dict:
60
+ """Reads an hdf file produced by coupled and returns the content in the form of a dictionary
61
+
62
+ Args:
63
+ hdf: Name of the hdf file to read
64
+ toRead: A list of quantities to read. The list of quantities that can be extracted from
65
+ the hdf file can be obtained by running :func:`~qupled.util.Hdf.inspect`
66
+
67
+ Returns:
68
+ A dictionary whose entries are the quantities listed in toRead
69
+
70
+ """
71
+ output = dict.fromkeys(toRead)
72
+ for name in toRead:
73
+ if name not in self.entries:
74
+ sys.exit("Unknown entry")
75
+ if self.entries[name].entryType == "numpy":
76
+ output[name] = pd.read_hdf(hdf, name)[0].to_numpy()
77
+ elif self.entries[name].entryType == "numpy2D":
78
+ output[name] = pd.read_hdf(hdf, name).to_numpy()
79
+ elif self.entries[name].entryType == "number":
80
+ output[name] = pd.read_hdf(hdf, "info")[name].iloc[0].tolist()
81
+ elif self.entries[name].entryType == "string":
82
+ output[name] = pd.read_hdf(hdf, "info")[name].iloc[0]
83
+ else:
84
+ sys.exit("Unknown entry type")
85
+ return output
86
+
87
+ # Get all quantities stored in an hdf file
88
+ def inspect(self, hdf: str) -> dict:
89
+ """Allows to obtain a summary of the quantities stored in an hdf file
90
+
91
+ Args:
92
+ hdf: Name of the hdf file to inspect
93
+
94
+ Returns:
95
+ A dictionary containing all the quantities stored in the hdf file and a brief description for
96
+ each quantity
97
+
98
+ """
99
+ with pd.HDFStore(hdf, mode="r") as store:
100
+ datasetNames = [
101
+ name[1:] if name.startswith("/") else name for name in store.keys()
102
+ ]
103
+ if "info" in datasetNames:
104
+ datasetNames.remove("info")
105
+ for name in store["info"].keys():
106
+ datasetNames.append(name)
107
+ output = dict.fromkeys(datasetNames)
108
+ for key in output.keys():
109
+ output[key] = self.entries[key].description
110
+ return output
111
+
112
+ # Plot from data in hdf file
113
+ def plot(self, hdf: str, toPlot: list[str], matsubara: np.array = None) -> None:
114
+ """Plots the results stored in an hdf file.
115
+
116
+ Args:
117
+ hdf: Name of the hdf file
118
+ toPlot: A list of quantities to plot. Allowed quantities include adr (auxiliary density response),
119
+ bf (bridge function adder), fxci (free energy integrand), idr (ideal density response), rdf
120
+ (radial distribution function), sdr (static density response), slfc (static local field correction)
121
+ ssf (static structure factor) and ssfHF (Hartree-Fock static structure factor).
122
+ If the hdf file does not contain the specified quantity, an error is thrown
123
+ matsubara: A list of matsubara frequencies to plot. Applies only when the idr is plotted.
124
+ (Defaults to None, all matsubara frequencies are plotted)
125
+
126
+ """
127
+ for name in toPlot:
128
+ description = (
129
+ self.entries[name].description if name in self.entries.keys() else ""
130
+ )
131
+ if name == "rdf":
132
+ x = self.read(hdf, [name, "rdfGrid"])
133
+ Plot.plot1D(
134
+ x["rdfGrid"],
135
+ x[name],
136
+ self.entries["rdfGrid"].description,
137
+ description,
138
+ )
139
+ elif name in ["adr", "idr"]:
140
+ x = self.read(hdf, [name, "wvg", "matsubara"])
141
+ if matsubara is None:
142
+ matsubara = np.arange(x["matsubara"])
143
+ Plot.plot1DParametric(
144
+ x["wvg"],
145
+ x[name],
146
+ self.entries["wvg"].description,
147
+ description,
148
+ matsubara,
149
+ )
150
+ elif name == "fxci":
151
+ x = self.read(hdf, [name, "fxcGrid"])
152
+ Plot.plot1D(
153
+ x["fxcGrid"],
154
+ x[name][1, :],
155
+ self.entries["fxcGrid"].description,
156
+ description,
157
+ )
158
+ elif name in ["bf", "sdr", "slfc", "ssf", "ssfHF"]:
159
+ x = self.read(hdf, [name, "wvg"])
160
+ Plot.plot1D(
161
+ x["wvg"],
162
+ x[name],
163
+ self.entries["wvg"].description,
164
+ self.entries[name].description,
165
+ )
166
+ elif name == "alpha":
167
+ x = self.read(hdf, [name, "fxcGrid"])
168
+ Plot.plot1D(
169
+ x["fxcGrid"][::2],
170
+ x[name][::2],
171
+ self.entries["fxcGrid"].description,
172
+ self.entries[name].description,
173
+ )
174
+ else:
175
+ sys.exit("Unknown quantity to plot")
176
+
177
+ def computeRdf(
178
+ self, hdf: str, rdfGrid: np.array = None, saveRdf: bool = True
179
+ ) -> None:
180
+ """Computes the radial distribution function and returns it as a numpy array.
181
+
182
+ Args:
183
+ hdf: Name of the hdf file to load the structural properties from
184
+ rdfGrid: A numpy array specifing the grid used to compute the radial distribution function
185
+ (default = None, i.e. rdfGrid = np.arange(0.0, 10.0, 0.01))
186
+ saveRdf: Flag marking whether the rdf data should be added to the hdf file (default = True)
187
+
188
+ Returns:
189
+ The radial distribution function
190
+
191
+ """
192
+ hdfData = self.read(hdf, ["wvg", "ssf"])
193
+ if rdfGrid is None:
194
+ rdfGrid = np.arange(0.0, 10.0, 0.01)
195
+ rdf = native.computeRdf(rdfGrid, hdfData["wvg"], hdfData["ssf"])
196
+ if saveRdf:
197
+ pd.DataFrame(rdfGrid).to_hdf(hdf, key="rdfGrid", mode="r+")
198
+ pd.DataFrame(rdf).to_hdf(hdf, key="rdf", mode="r+")
199
+ return rdf
200
+
201
+ def computeInternalEnergy(self, hdf: str) -> float:
202
+ """Computes the internal energy and returns it to output.
203
+
204
+ Args:
205
+ hdf: Name of the hdf file to load the structural properties from
206
+
207
+ Returns:
208
+ The internal energy
209
+ """
210
+ hdfData = self.read(hdf, ["wvg", "ssf", "coupling"])
211
+ return native.computeInternalEnergy(
212
+ hdfData["wvg"], hdfData["ssf"], hdfData["coupling"]
213
+ )
214
+
215
+
216
+ # -----------------------------------------------------------------------
217
+ # Plot class
218
+ # -----------------------------------------------------------------------
219
+
220
+
221
+ class Plot:
222
+ """Class to collect methods used for plotting"""
223
+
224
+ # One dimensional plots
225
+ def plot1D(x, y, xlabel, ylabel):
226
+ """Produces the plot of a one-dimensional quantity.
227
+
228
+ Positional arguments:
229
+ x -- data for the x-axis (a numpy array)
230
+ y -- data for the y-axis (a numpy array)
231
+ xlabel -- label for the x-axis (a string)
232
+ ylabel -- label for the y-axis (a string)
233
+ """
234
+ plt.plot(x, y, "b")
235
+ plt.xlabel(xlabel)
236
+ plt.ylabel(ylabel)
237
+ plt.show()
238
+
239
+ # One dimensional plots with one parameter"
240
+ def plot1DParametric(x, y, xlabel, ylabel, parameters):
241
+ """Produces the plot of a one-dimensional quantity that depends on an external parameter.
242
+
243
+ Positional arguments:
244
+ x -- data for the x-axis (a numpy array)
245
+ y -- data for the y-axis (a two-dimensional numpy array)
246
+ xlabel -- label for the x-axis (a string)
247
+ ylabel -- label for the y-axis (a string)
248
+ parameters -- list of parameters for which the results should be plotted
249
+ """
250
+ numParameters = parameters.size
251
+ cmap = cm["viridis"]
252
+ for i in np.arange(numParameters):
253
+ color = cmap(1.0 * i / numParameters)
254
+ plt.plot(x, y[:, parameters[i]], color=color)
255
+ plt.xlabel(xlabel)
256
+ plt.ylabel(ylabel)
257
+ plt.show()
258
+
259
+
260
+ # -----------------------------------------------------------------------
261
+ # MPI class
262
+ # -----------------------------------------------------------------------
263
+
264
+
265
+ class MPI:
266
+ """Class to handle the calls to the MPI API"""
267
+
268
+ def __init__(self):
269
+ self.qpMPI = native.MPI
270
+
271
+ def getRank(self):
272
+ """Get rank of the process"""
273
+ return self.qpMPI.rank()
274
+
275
+ def isRoot(self):
276
+ """Check if the current process is root (rank 0)"""
277
+ return self.qpMPI.isRoot()
278
+
279
+ def barrier(self):
280
+ """Setup and MPI barrier"""
281
+ self.qpMPI.barrier()
282
+
283
+ def timer(self):
284
+ """Get wall time"""
285
+ return self.qpMPI.timer()
286
+
287
+ @staticmethod
288
+ def runOnlyOnRoot(func):
289
+ """Python decorator for all methods that have to be run only by root"""
290
+
291
+ @functools.wraps(func)
292
+ def wrapper(*args, **kwargs):
293
+ if MPI().isRoot():
294
+ return func(*args, **kwargs)
295
+
296
+ return wrapper
297
+
298
+ @staticmethod
299
+ def synchronizeRanks(func):
300
+ """Python decorator for all methods that need to rank synchronization"""
301
+
302
+ @functools.wraps(func)
303
+ def wrapper(*args, **kwargs):
304
+ func(*args, **kwargs)
305
+ MPI().barrier()
306
+
307
+ return wrapper
308
+
309
+ @staticmethod
310
+ def recordTime(func):
311
+ """Python decorator for all methods that have to be timed"""
312
+
313
+ @functools.wraps(func)
314
+ def wrapper(*args, **kwargs):
315
+ tic = MPI().timer()
316
+ func(*args, **kwargs)
317
+ toc = MPI().timer()
318
+ dt = toc - tic
319
+ hours = dt // 3600
320
+ minutes = (dt % 3600) // 60
321
+ seconds = dt % 60
322
+ if MPI().isRoot():
323
+ if hours > 0:
324
+ print("Elapsed time: %d h, %d m, %d s." % (hours, minutes, seconds))
325
+ elif minutes > 0:
326
+ print("Elapsed time: %d m, %d s." % (minutes, seconds))
327
+ else:
328
+ print("Elapsed time: %.1f s." % seconds)
329
+
330
+ return wrapper
@@ -0,0 +1,27 @@
1
+ Metadata-Version: 2.1
2
+ Name: qupled
3
+ Version: 0.0.2
4
+ Summary: qupled: a package to investigate quantum plasmas via the dielectric formalism
5
+ Author-email: Federico Lucco Castello <federico.luccocastello@gmail.com>
6
+ Classifier: Programming Language :: Python :: 3.10
7
+ Classifier: Operating System :: MacOS
8
+ Classifier: Operating System :: POSIX :: Linux
9
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
10
+ Requires-Python: <3.13,>=3.10
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: matplotlib~=3.7
13
+ Requires-Dist: numpy<2.0
14
+ Requires-Dist: pandas~=2.0
15
+ Requires-Dist: tables~=3.10
16
+ Provides-Extra: testing
17
+ Requires-Dist: pytest~=8.0; extra == "testing"
18
+ Requires-Dist: pytest-mock~=3.12; extra == "testing"
19
+ Provides-Extra: docs
20
+ Requires-Dist: sphinx-rtd-theme~=2.0.0; extra == "docs"
21
+ Requires-Dist: sphinxcontrib-applehelp~=2.0.0; extra == "docs"
22
+ Requires-Dist: sphinxcontrib-devhelp~=2.0.0; extra == "docs"
23
+ Requires-Dist: sphinxcontrib-htmlhelp~=2.1.0; extra == "docs"
24
+ Requires-Dist: sphinxcontrib-jquery~=4.1; extra == "docs"
25
+ Requires-Dist: sphinxcontrib-jsmath~=1.0.1; extra == "docs"
26
+ Requires-Dist: sphinxcontrib-qthelp~=2.0.0; extra == "docs"
27
+ Requires-Dist: sphinxcontrib-serializinghtml~=2.0.0; extra == "docs"
@@ -0,0 +1,13 @@
1
+ MANIFEST.in
2
+ pyproject.toml
3
+ qupled/__init__.py
4
+ qupled/classic.py
5
+ qupled/quantum.py
6
+ qupled/util.py
7
+ qupled.egg-info/PKG-INFO
8
+ qupled.egg-info/SOURCES.txt
9
+ qupled.egg-info/dependency_links.txt
10
+ qupled.egg-info/requires.txt
11
+ qupled.egg-info/top_level.txt
12
+ qupled/Darwin/qupled.so
13
+ qupled/Linux/qupled.so
@@ -0,0 +1,18 @@
1
+ matplotlib~=3.7
2
+ numpy<2.0
3
+ pandas~=2.0
4
+ tables~=3.10
5
+
6
+ [docs]
7
+ sphinx-rtd-theme~=2.0.0
8
+ sphinxcontrib-applehelp~=2.0.0
9
+ sphinxcontrib-devhelp~=2.0.0
10
+ sphinxcontrib-htmlhelp~=2.1.0
11
+ sphinxcontrib-jquery~=4.1
12
+ sphinxcontrib-jsmath~=1.0.1
13
+ sphinxcontrib-qthelp~=2.0.0
14
+ sphinxcontrib-serializinghtml~=2.0.0
15
+
16
+ [testing]
17
+ pytest~=8.0
18
+ pytest-mock~=3.12
@@ -0,0 +1 @@
1
+ qupled
qupled-0.0.2/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+