mirror of https://github.com/abinit/abipy.git
Merged trunk/develop
This commit is contained in:
commit
74b2f6e741
|
@ -52,6 +52,9 @@ docs/flow_gallery
|
|||
# Pycharm
|
||||
.idea/
|
||||
|
||||
# VSC
|
||||
.vscode/
|
||||
|
||||
# vim files
|
||||
*.swp
|
||||
*.swo
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
|
||||
Release 0.9.1:
|
||||
Release 0.9.1:
|
||||
|
||||
* abiopen, abiview and abicom now supports --plotly to produce plotly figures in the local browser
|
||||
* Add "-ew", "--expose-web",
|
||||
* abiopen, abiview and abicomp now supports --plotly to produce plotly figures in the local browser
|
||||
and --chart-studio to push the figure to the chart studio service.
|
||||
Note that, at present, only DDB files support plotly.
|
||||
* AbinitInput set_kpath and make_ebands_input now support negative values of ndivsm that
|
||||
* AbinitInput set_kpath and make_ebands_input now support negative values of ndivsm that
|
||||
are interpreted as line_density following pymatgen conventions.
|
||||
This option is the recommended one if the k-path contains two consecutive high symmetry k-points
|
||||
This option is the recommended one if the k-path contains two consecutive high symmetry k-points
|
||||
that are very close as ndivsm > 0 may produce a very large number of wavevectors.
|
||||
* Preliminary support for plotly plots (phonons).
|
||||
* AbinitInputParser now can parse strings in the input file and read structure is the `suctructre:abivars`
|
||||
* AbinitInputParser now can parse strings in the input file and read structure is the `structure:abivars`
|
||||
syntax in used.
|
||||
|
||||
|
||||
Release 0.9.0:
|
||||
Release 0.9.0:
|
||||
|
||||
* Require pymatgen >= 2019.12.22
|
||||
* Integration with abinit 9.4.0
|
||||
|
@ -24,13 +24,12 @@ Release 0.9.0:
|
|||
* Use last version of apscheduler.
|
||||
* Minor bug fixes
|
||||
* New tools for Phonon and EPH calculations.
|
||||
* Note that this is last AbiPy version supporting Abinit8.
|
||||
* Note that this is the last AbiPy version supporting Abinit8.
|
||||
AbiPy version 1.0 will start to take advantage of features and ameliorations introduced in Abinit9
|
||||
We will also take the opportunity to refactor the code base so backward incompatibe changes in the API
|
||||
are expected in the next major version.
|
||||
|
||||
|
||||
Release 0.8.0:
|
||||
Release 0.8.0:
|
||||
|
||||
* Add abicheck.py --create-config option to install predefined yaml configuration files
|
||||
* Add support for NSCF calculations with meta-GGA.
|
||||
|
@ -70,7 +69,7 @@ Release:0.3.0 2017-12-26
|
|||
and ``flow-gallery`` with AbiPy flows are now automatically generated.
|
||||
* Add Shankland-Koelling-Wood Fourier interpolation scheme.
|
||||
|
||||
Release 0.2.0 <2017-03-10>
|
||||
Release 0.2.0 2017-03-10
|
||||
|
||||
This is the first official release in which we have reached a relatively stable API
|
||||
and a well-defined interface with the netcdf files produced by Abinit.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""
|
||||
This module gathers the most important classes and helper functions used for scripting.
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import collections
|
||||
|
||||
|
@ -178,6 +179,14 @@ def extcls_supporting_panel(as_table=True, **tabulate_kwargs):
|
|||
return tabulate(items, headers=["Extension", "Class"], **tabulate_kwargs)
|
||||
|
||||
|
||||
def abipanel(**kwargs):
|
||||
"""
|
||||
Activate panel extensions used by AbiPy. Return panel module.
|
||||
"""
|
||||
from abipy.panels.core import abipanel
|
||||
return abipanel(**kwargs)
|
||||
|
||||
|
||||
def abifile_subclass_from_filename(filename):
|
||||
"""
|
||||
Returns the appropriate class associated to the given filename.
|
||||
|
@ -331,14 +340,24 @@ def mjson_write(d, filepath, **kwargs):
|
|||
json.dump(d, fh, cls=MontyEncoder, **kwargs)
|
||||
|
||||
|
||||
def software_stack():
|
||||
def software_stack(as_dataframe=False):
|
||||
"""
|
||||
Import all the hard dependencies. Returns ordered dict: package --> string with version info.
|
||||
Import all the hard dependencies and some optional packages.
|
||||
Returns ordered dict: package --> string with version info or pandas dataframe if as_dataframe.
|
||||
"""
|
||||
import platform
|
||||
system, node, release, version, machine, processor = platform.uname()
|
||||
# These packages are required
|
||||
import numpy, scipy, netCDF4, pymatgen, apscheduler, pydispatch, yaml
|
||||
import numpy, scipy, netCDF4, pymatgen, apscheduler, pydispatch, yaml, plotly
|
||||
|
||||
from importlib import import_module
|
||||
def get_version(pkg_name):
|
||||
"""Return version of package from string."""
|
||||
try:
|
||||
mod = import_module(pkg_name)
|
||||
return mod.__version__
|
||||
except:
|
||||
return None
|
||||
|
||||
try:
|
||||
from pymatgen.core import __version__ as pmg_version
|
||||
|
@ -355,17 +374,19 @@ def software_stack():
|
|||
("apscheduler", apscheduler.version),
|
||||
("pydispatch", pydispatch.__version__),
|
||||
("yaml", yaml.__version__),
|
||||
("boken", get_version("bokeh")),
|
||||
("panel", get_version("panel")),
|
||||
("plotly", get_version("plotly")),
|
||||
("ase", get_version("ase")),
|
||||
("phonopy", get_version("phonopy")),
|
||||
("monty", get_version("monty")),
|
||||
("pymatgen", pmg_version),
|
||||
("abipy", __version__),
|
||||
])
|
||||
|
||||
# Optional but strongly suggested.
|
||||
#try:
|
||||
# import matplotlib
|
||||
# d["matplotlib"] = "%s (backend: %s)" % (matplotlib.__version__, matplotlib.get_backend())
|
||||
#except ImportError:
|
||||
# pass
|
||||
|
||||
return d
|
||||
if not as_dataframe: return d
|
||||
import pandas as pd
|
||||
return pd.Series(data=d, name="version").to_frame().rename_axis("Package")
|
||||
|
||||
|
||||
def abicheck(verbose=0):
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
To update the python modules using the more recent version available in the Abinit repository use vimdiff:
|
||||
To update the python modules using the more recent version available in the Abinit repository
|
||||
and use eg. vimdiff:
|
||||
|
||||
vimdiff $ABINIT_REPO/abimkdocs/variables_abinit.py variables_abinit.py
|
||||
|
||||
and patch the file manually!
|
||||
to patch the file manually!
|
||||
Do not change the initial part of the module since it's needed by AbiPy.
|
||||
|
||||
To automate the process, use:
|
||||
|
||||
invoke update-vars ABINIT_REPO/
|
||||
|
|
|
@ -18,7 +18,7 @@ Variable(
|
|||
mnemonics="ACCURACY",
|
||||
added_in_version="before_v9",
|
||||
text=r"""
|
||||
Allows to tune the accuracy of a calculation by setting automatically the
|
||||
Allows to tune the accuracy of a ground-state or DFPT calculation [[optdriver]]=0 or 1, by setting automatically the
|
||||
variables according to the following table:
|
||||
|
||||
accuracy | 1 | 2 | 3 | 4 | 5 | 6
|
||||
|
@ -51,6 +51,10 @@ If the user wants to modify one of the input variable automatically tuned by *ac
|
|||
they must put it in the input file. The other input variables automatically tuned
|
||||
by *accuracy* will not be affected.
|
||||
*accuracy* = 0 means that this input variable is deactivated.
|
||||
|
||||
For the other values of [[optdriver]], many of the above input variables have no meaning,
|
||||
so the accuracy has to be tuned by the user (e.g. for GW calculations, perform convergence studies
|
||||
with respect to [[ecuteps]] and other relevant input variables).
|
||||
""",
|
||||
),
|
||||
|
||||
|
@ -424,32 +428,32 @@ Control the size of the block in the LOBPCG algorithm.
|
|||
!!! important
|
||||
|
||||
This keyword works only with [[paral_kgb]] = 1 and has to be either 1 or a multiple of 2.
|
||||
Moreover [[nband]] / ([[npband]] $\times$ n) has to be integer.
|
||||
Moreover [[nband]] / ([[npband]] $\times$ [[bandpp]]) has to be integer.
|
||||
|
||||
With [[npband]] = 1:
|
||||
|
||||
* 1 --> band-per-band algorithm
|
||||
* n --> The minimization is performed using [[nband]] blocks of n bands.
|
||||
* [[bandpp]]=1 --> band-per-band algorithm
|
||||
* [[bandpp]]/=1 --> The minimization is performed using [[nband]]/[[bandpp]] blocks of [[bandpp]] bands.
|
||||
|
||||
With [[npband]] > 1:
|
||||
|
||||
* 1 --> The minimization is performed using [[nband]] / [[npband]] blocks of [[npband]] bands.
|
||||
* n --> The minimization is performed using [[nband]] / ([[npband]] $\times$ n) blocks of [[npband]] $\times$ n bands.
|
||||
* [[bandpp]]=1 --> The minimization is performed using [[nband]] / [[npband]] blocks of [[npband]] bands.
|
||||
* [[bandpp]]/=1 --> The minimization is performed using [[nband]] / ([[npband]] $\times$ [[bandpp]]) blocks of [[npband]] $\times$ [[bandpp]] bands.
|
||||
|
||||
By minimizing a larger number of bands together in LOBPCG, we increase the
|
||||
convergence of the residuals. The better minimization procedure (as concerns
|
||||
the convergence, but not as concerns the speed) is generally performed by
|
||||
using *bandpp* $\times$ [[npband]] = [[nband]].
|
||||
using [[bandpp]] $\times$ [[npband]] = [[nband]].
|
||||
|
||||
When performing Gamma-only calculations ([[istwfk]] = 2), it is recommended to set *bandpp* = 2
|
||||
When performing Gamma-only calculations ([[istwfk]] = 2), it is recommended to set [[bandpp]] = 2
|
||||
(or a multiple of 2) as the time spent in FFTs is divided by two.
|
||||
Also, the time required to apply the non-local part of the KS Hamiltonian can be significantly
|
||||
reduced if [[bandpp]] > 1 is used in conjunction with [[use_gemm_nonlop]] = 1.
|
||||
|
||||
Note that increasing the value of [[bandpp] can have a significant impact on the computing time
|
||||
Note that increasing the value of [[bandpp]] can have a significant impact (reduction) on the computing time
|
||||
(especially if [[use_gemm_nonlop]] is used)
|
||||
but keep in mind that the size of the workspace arrays will also increase so the calculation may go out-of-memory
|
||||
if a too large [[bandpp] is used in systems if many atoms.
|
||||
if a too large [[bandpp]] is used in systems if many atoms.
|
||||
""",
|
||||
),
|
||||
|
||||
|
@ -625,10 +629,10 @@ Variable(
|
|||
* 1 --> the polarization will be kept in the same branch on each iteration.
|
||||
At the end of the run, a file "POLSAVE" will be saved containing the reduced polarization in atomic units.
|
||||
|
||||
!!! note
|
||||
!!! note
|
||||
|
||||
Make sure that "POLSAVE" is empty or it does not exist before the calculation, or else that
|
||||
it specifies the desired polarization branch.
|
||||
Make sure that "POLSAVE" is empty or it does not exist before the calculation, or else that
|
||||
it specifies the desired polarization branch.
|
||||
""",
|
||||
),
|
||||
|
||||
|
@ -3496,7 +3500,7 @@ Variable(
|
|||
abivarname="ecutsigx",
|
||||
varset="gw",
|
||||
vartype="real",
|
||||
topics=['SelfEnergy_compulsory'],
|
||||
topics=['SelfEnergy_basic'],
|
||||
dimensions="scalar",
|
||||
defaultval=0.0,
|
||||
mnemonics="Energy CUT-off for SIGma eXchange",
|
||||
|
@ -3510,6 +3514,8 @@ calculations, it is pointless to have [[ecutsigx]] bigger than 4*[[ecut]],
|
|||
while for PAW calculations, the maximal useful value is [[pawecutdg]]. Thus,
|
||||
if you do not care about CPU time, please use these values. If you want to
|
||||
spare some CPU time, you might try to use a value between [[ecut]] and these upper limits.
|
||||
|
||||
[[ecutsigx]] is actually used to initialize the internal variable [[npwsigx]].
|
||||
""",
|
||||
),
|
||||
|
||||
|
@ -3556,7 +3562,7 @@ Variable(
|
|||
abivarname="ecutwfn",
|
||||
varset="gw",
|
||||
vartype="real",
|
||||
topics=['Susceptibility_compulsory', 'SelfEnergy_compulsory'],
|
||||
topics=['Susceptibility_basic', 'SelfEnergy_basic'],
|
||||
dimensions="scalar",
|
||||
defaultval=ValueWithConditions({'[[optdriver]] in [3, 4]': '[[ecut]]', 'defaultval': 0.0}),
|
||||
mnemonics="Energy CUT-off for WaveFunctioNs",
|
||||
|
@ -4421,7 +4427,7 @@ In reciprocal space, this expression is evaluated by a convolution in which
|
|||
the number of reciprocal lattice vectors employed to describe the
|
||||
wavefunctions is given by [[ecutwfn]]. In the case of screening calculations,
|
||||
the number of **G** vectors in the above expression is defined by [[ecuteps]],
|
||||
while [[ecutsigx]] defined the number of **G** used in sigma calculations. To
|
||||
while [[ecutsigx]] defines the number of **G** used in sigma calculations. To
|
||||
improve the efficiency of the code, the oscillator matrix elements are
|
||||
evaluated in real space through FFT techniques, and the [[fftgw]] input
|
||||
variable is used to select the FFT mesh to be used.
|
||||
|
@ -6213,7 +6219,7 @@ Variable(
|
|||
abivarname="gwaclowrank",
|
||||
varset="gw",
|
||||
vartype="integer",
|
||||
topics=['GW_basic', 'SelfEnergy_basic'],
|
||||
topics=['GW_useful', 'SelfEnergy_useful'],
|
||||
dimensions="scalar",
|
||||
defaultval=0,
|
||||
mnemonics="GW Analytic Continuation LOW RANK approximation",
|
||||
|
@ -6715,7 +6721,7 @@ Variable(
|
|||
abivarname="gwmem",
|
||||
varset="gw",
|
||||
vartype="integer",
|
||||
topics=['Susceptibility_expert', 'SelfEnergy_expert', 'GW_expert'],
|
||||
topics=['Susceptibility_expert', 'SelfEnergy_expert', 'GW_expert', 'TuningSpeedMem_expert'],
|
||||
dimensions="scalar",
|
||||
defaultval=11,
|
||||
mnemonics="GW MEMory",
|
||||
|
@ -6733,6 +6739,12 @@ Variable(
|
|||
The default is [[gwmem]] = 11, which is the fastest, but also the most memory
|
||||
consuming. When experiencing memory shortage, one should try [[gwmem]] = 0.
|
||||
The first digit is only meaningful when performing sigma calculations.
|
||||
|
||||
!!! important
|
||||
|
||||
Note that reading the screening file the SCR file during the sigma run leads to a **significant increase of the IO**
|
||||
with a subsequent slowdown. Use this option if you really need it and make sure the sysadmin won't complain
|
||||
about an abnormal IO activity of your jobs.
|
||||
""",
|
||||
),
|
||||
|
||||
|
@ -6758,6 +6770,17 @@ In the present status of the code, only the parallelization over bands
|
|||
([[gwpara]] = 2) allows one to reduce the memory allocated by each processor.
|
||||
Using [[gwpara]] = 1, indeed, requires the same amount of memory as a sequential
|
||||
run, irrespectively of the number of CPUs used.
|
||||
|
||||
In the screening calculation [[optdriver]]=3, with [[gwpara]]=2, the
|
||||
code distributes the wavefunctions such that each processing unit owns the
|
||||
FULL set of occupied bands while the empty states are DISTRIBUTED among the
|
||||
nodes. Thus the parallelisation is over the unoccupied states.
|
||||
|
||||
The parallelism of the self-energy calculation [[optdriver]]=4,
|
||||
with [[gwpara]]=2, is somehow different. It is over the entire set of bands,
|
||||
and has different characteristics for the correlation calculation and for the exchange calculation..
|
||||
The MPI computation of the correlation part is efficient when the number of processors divides [[nband]].
|
||||
Optimal scaling in the exchange part is obtained only when each node possesses the full set of occupied states.
|
||||
""",
|
||||
),
|
||||
|
||||
|
@ -7580,9 +7603,10 @@ No meaning for RF calculations.
|
|||
For instance, a server that wants to performs calculations with varying unit cells
|
||||
should set [[optcell]] > 0 in the initial input.
|
||||
|
||||
Note that this feature is still under DEVELOPMENT and is mainly used to interface ABINIT
|
||||
with the ASE optimization routines.
|
||||
Examples will be provided when the feature is ready for production.
|
||||
Note that, at present, this feature is mainly used to interface ABINIT
|
||||
with the ASE optimization routines. Moreover the user is responsible for creating an input
|
||||
file with tuned tolerances to prevent Abinit from exiting when internal convergence is reached.
|
||||
See examples available in the [ASE documentation](https://wiki.fysik.dtu.dk/ase/dev/ase/calculators/socketio/socketio.html)
|
||||
|
||||
**Purpose:** Structural optimization driver by the server (MD runs are not yet supported)
|
||||
**Cell optimization:** Yes (provide [[optcell]] > 0 in the initial input)
|
||||
|
@ -8694,7 +8718,7 @@ See [[cite:Sun2011]] for the formulas.
|
|||
* 207 --> XC_MGGA_X_BJ06 Becke & Johnson correction to Becke-Roussel 89 [[cite:Becke2006]]
|
||||
|
||||
!!! warning
|
||||
This Vxc-only mGGA can only be used with a LDA correlation, typically Perdew-Wang 92 [[cite:Perdew1992a]].
|
||||
This Vxc-only mGGA can only be used with a LDA correlation, typically Perdew-Wang 92 [[cite:Perdew1992a]], hence [[ixc]]=-12208 ..
|
||||
|
||||
* 208 --> XC_MGGA_X_TB09 Tran-blaha - correction to Becke & Johnson correction to Becke-Roussel 89 [[cite:Tran2009]]
|
||||
|
||||
|
@ -11078,10 +11102,13 @@ Variable(
|
|||
added_in_version="before_v9",
|
||||
text=r"""
|
||||
Give the number of images (or replicas) of the system, for which the forces
|
||||
and stresses might be computed independently, in the context of the string
|
||||
method, the genetic algorithm, hyperdynamics or Path-Integral Molecular
|
||||
Dynamics depending on the value of [[imgmov]]). Related input variables:
|
||||
and stresses might be computed independently, in the context of string
|
||||
or NEB method, genetic algorithm, hyperdynamics, Path-Integral Molecular
|
||||
Dynamics, linear combination of images, pSIC, genetic algorithm, etc, depending on the value of [[imgmov]]). Related input variables:
|
||||
[[dynimage]], [[npimage]], [[ntimimage]] and [[prtvolimg]].
|
||||
If [[nimage]]>1, the default choice for printing many files is set to zero, and the user might
|
||||
want to manually reestablish the printing, using, e.g. [[prtgsr]], [[prtwf]], [[prtebands]], [[prteig]], etc.
|
||||
|
||||
Images might differ by the position of atoms in the unit cell, their velocity,
|
||||
as well as by their cell geometry. The following input variables might be used
|
||||
to define the images:
|
||||
|
@ -11882,7 +11909,7 @@ Variable(
|
|||
text=r"""
|
||||
[[npwsigx]] determines the cut-off energy of the planewave set used to
|
||||
generate the exchange part of the self-energy operator.
|
||||
It is an internal variable, determined from [[ecutsigx]].
|
||||
It is an internal variable, determined from the largest of [[ecutsigx]] or [[ecutwfn]].
|
||||
""",
|
||||
),
|
||||
|
||||
|
@ -12675,18 +12702,22 @@ Variable(
|
|||
varset="gstate",
|
||||
vartype="real",
|
||||
topics=['BandOcc_basic'],
|
||||
dimensions=['[[nband]]', "[[mband]]", "[[nsppol]]"],
|
||||
dimensions=['[[nband]]', '[[nsppol]]'],
|
||||
commentdims="in case [[occopt]]=2, dimensions are ([[mband]],[[nkpt]],[[nsppol]])",
|
||||
defaultval=MultipleValue(number=None, value=0),
|
||||
mnemonics="OCCupation numbers",
|
||||
characteristics=['[[EVOLVING]]'],
|
||||
added_in_version="before_v9",
|
||||
text=r"""
|
||||
Gives occupation numbers for all bands in the problem. Needed if [[occopt]] == 0
|
||||
or [[occopt]] == 2. Ignored otherwise. Also ignored when [[iscf]] = -2.
|
||||
Typical band occupancy is either 2 or 0, but can be 1 for half-occupied band
|
||||
or other choices in special circumstances.
|
||||
or [[occopt]] == 2. Ignored otherwise (automatically computed). Also ignored when [[iscf]] = -2.
|
||||
Typical band occupancy is either 2.0 or 0.0, but will usually be 1.0 or 0.0 for [[nsppol]]=2, or [[nspinor]]=2,
|
||||
or half-occupied band, or other choices in special circumstances.
|
||||
|
||||
If [[occopt]] is not 2, then the occupancies must be the same for each k point.
|
||||
If [[nsppol]]=1, the total number of arrays which must be provided is [[nband]], in order of increasing energy.
|
||||
If [[nsppol]]=2, the total number of arrays which must be provided is [[nband]]*[[nsppol]],
|
||||
first spin up, in order of increasing electronic eigenenergy, then spin down, in order of increasing electronic eigenenergy.
|
||||
|
||||
If [[occopt]] = 2, then the band occupancies must be provided explicitly for
|
||||
each band, EACH k POINT, and EACH SPIN-POLARIZATION, in an array which runs
|
||||
|
@ -12696,6 +12727,7 @@ point (spin up), then all bands at the second k point (spin up), etc, then all
|
|||
k-points spin down.
|
||||
The total number of array elements which must be provided is
|
||||
( [[nband]](1)+[[nband]](2)+...+ [[nband]]([[nkpt]]) ) * [[nsppol]].
|
||||
|
||||
The occupation numbers evolve only for metallic occupations, that is, [[occopt]] ≥ 3.
|
||||
|
||||
When there are several images, [[occ]] might depend on the image number, see the description in [[nimage]].
|
||||
|
@ -12716,7 +12748,7 @@ Controls how input parameters [[nband]], [[occ]], and [[wtk]] are handled.
|
|||
Possible values are from 0 to 9.
|
||||
For gapped materials (semiconductors, molecules, ...), [[occopt]]=1 is the favourite for most usages.
|
||||
For metallic situations (also molecules with degenerate levels at Fermi energy), [[occopt]]=7 is the favourite for most usages,
|
||||
and one need to pay attention to the input variable [[tsmear]].
|
||||
and one needs moreover to control the input variable [[tsmear]].
|
||||
Use [[occopt]]=9 for quasi-Fermi energy calculations of excited states in gapped materials.
|
||||
|
||||
* [[occopt]] = 0:
|
||||
|
@ -12748,7 +12780,7 @@ the sum of [[nband]](ikpt) over all k points and spins. The k point weights
|
|||
Metallic occupation of levels, using different occupation schemes (see below).
|
||||
The corresponding thermal broadening, or cold smearing, is defined by the
|
||||
input variable [[tsmear]] (see below: the variable xx is the energy in Ha,
|
||||
divided by [[tsmear]])
|
||||
divided by [[tsmear]]).
|
||||
Like for [[occopt]] = 1, the variable [[occ]] is not read.
|
||||
All k points have the same number of bands, [[nband]] is given as a single
|
||||
number, read by the code.
|
||||
|
@ -12757,31 +12789,35 @@ the code to add to 1. The combination of a broadening and a physical temperature
|
|||
can be obtained by using both [[tsmear]] and [[tphysel]].
|
||||
|
||||
* [[occopt]] = 3:
|
||||
Fermi-Dirac smearing (finite-temperature metal) Smeared delta function:
|
||||
0.25/(cosh(xx/2.0)**2). For usual calculations, at zero temperature, do not use [[occopt]]=3,
|
||||
Fermi-Dirac smearing (finite-temperature metal). Smeared delta function:
|
||||
$\tilde{\delta}(x)=0.25 (\cosh(x/2.0))^{-2}$. For usual calculations, at zero temperature, do not use [[occopt]]=3,
|
||||
but likely [[occopt]]=7. If you want to do a calculation at finite temperature, please also read the
|
||||
information about [[tphysel]].
|
||||
|
||||
* [[occopt]] = 4:
|
||||
"Cold smearing" of N. Marzari (see his thesis work), with a=-.5634
|
||||
(minimization of the bump)
|
||||
(minimization of the bump).
|
||||
Smeared delta function:
|
||||
exp(-xx 2 )/sqrt(pi) * (1.5+xx*(-a*1.5+xx*(-1.0+a*xx)))
|
||||
$\tilde{\delta}(x)= (1.5+x(-1.5a+x(-1.0+ax))) \exp(-x^2)/\sqrt{\pi}$ .
|
||||
Must be used with caution, see the note below.
|
||||
|
||||
* [[occopt]] = 5:
|
||||
"Cold smearing" of N. Marzari (see his thesis work), with a=-.8165 (monotonic
|
||||
function in the tail)
|
||||
Same smeared delta function as [[occopt]] = 4, with different a.
|
||||
Must be used with caution, see the note below.
|
||||
|
||||
* [[occopt]] = 6:
|
||||
Smearing of Methfessel and Paxton [[cite:Methfessel1989]] with Hermite polynomial
|
||||
of degree 2, corresponding to "Cold smearing" of N. Marzari with a=0 (so, same
|
||||
smeared delta function as [[occopt]] = 4, with different a).
|
||||
Must be used with caution, see the note below.
|
||||
|
||||
* [[occopt]] = 7:
|
||||
Gaussian smearing, corresponding to the 0 order Hermite polynomial of
|
||||
Gaussian smearing, corresponding to the 0-order Hermite polynomial of
|
||||
Methfessel and Paxton.
|
||||
Smeared delta function: 1.0*exp(-xx**2)/sqrt(pi)
|
||||
Smeared delta function: $\tilde{\delta}(x)=\exp(-x^2)/\sqrt{\pi}$ .
|
||||
Robust and quite efficient.
|
||||
|
||||
* [[occopt]] = 8:
|
||||
Uniform smearing (the delta function is replaced by a constant function of
|
||||
|
@ -12789,7 +12825,7 @@ value one over ]-1/2,1/2[ (with one-half value at the boundaries). Used for
|
|||
testing purposes only.
|
||||
|
||||
* [[occopt]] = 9:
|
||||
Fermi-Dirac occupation is enforced with two distinct quasi-Fermi levels: [[nqfd]] holes are forced in bands 1 to [[ivalence]] and [[nqfd]] electrons are forced in bands with index > [[ivalence]]. See details in [[cite:Paillard2019]]. At present, the number of holes and electrons should be the same. Note that occopt = 9 cannot be used with fixed magnetization calculation.
|
||||
Fermi-Dirac occupation is enforced with two distinct quasi-Fermi levels: [[nqfd]] holes are forced in bands 1 to [[ivalence]] and [[nqfd]] electrons are forced in bands with index > [[ivalence]]. See details in [[cite:Paillard2019]]. At present, the number of holes and electrons should be the same. Note that [[occopt]] = 9 cannot be used with fixed magnetization calculation.
|
||||
|
||||
!!! note
|
||||
|
||||
|
@ -12995,7 +13031,7 @@ Variable(
|
|||
([[kptopt]] == 3 or [[kptopt]] == 0) """,
|
||||
added_in_version="before_v9",
|
||||
text=r"""
|
||||
Compute quantities related to orbital magnetization. The
|
||||
Compute quantities related to orbital magnetic moment. The
|
||||
implementation assumes an insulator, so no empty or partially
|
||||
filled bands, and currently restricted to [[nspinor]] 1. Such
|
||||
insulators have orbital magnetization zero, except in the presence
|
||||
|
@ -13003,24 +13039,15 @@ Compute quantities related to orbital magnetization. The
|
|||
is parallelized over k points only. The implementation follows the
|
||||
theory outlined in [[cite:Gonze2011a]] extended to the PAW case;
|
||||
see also [[cite:Ceresoli2006]]. The computed results are returned in the
|
||||
standard output file, search for "Orbital magnetization" and "Chern number".
|
||||
standard output file, search for "Orbital magnetic moment". This calculation requires
|
||||
both the ground state and DDK wavefunctions, and is triggered at the end of a
|
||||
DDK calculation.
|
||||
|
||||
* [[orbmag]] = 11: Compute orbital magnetization and Chern number (integral of the
|
||||
Berry curvature over the Brillouin zone) using both GS and DDK wavefunctions. This is
|
||||
the most robust method.
|
||||
* [[orbmag]] = 1: Compute Chern number using discretized wavefunctions. This computation is
|
||||
faster than the full [[orbmag]] calculation, and a nonzero value indicates a circulating
|
||||
electronic current.
|
||||
* [[orbmag]] = 2: Compute electronic orbital magnetization.
|
||||
* [[orbmag]] = 3: Compute both Chern number and electronic orbital magnetization.
|
||||
|
||||
[[orbmag]] values 1--3 use an implementation based on a discretization of the wavefunction
|
||||
derivatives, as in [[cite:Ceresoli2006]]. Using [[orbmag]] -1, -2, -3 delivers the
|
||||
same computations as the corresponding 1, 2, 3 values, but based on an implementation
|
||||
using a discretization of the density operator itself. Both methods should converge to
|
||||
the same values but in our experience the wavefunction-based method converges faster. The
|
||||
DDK method converges considerably faster than either of the above methods and is also robust
|
||||
in case of only a single kpt.
|
||||
* [[orbmag]] = 1: Compute orbital magnetization and integral of the
|
||||
Berry curvature (Chern number) over the Brillouin zone.
|
||||
* [[orbmag]] = 2: Same as [[orbmag]] 1 but also print out values of each term making up total
|
||||
orbital magnetic moment.
|
||||
* [[orbmag]] = 3: Same as [[orbmag]] 2 but print out values of each term for each band.
|
||||
""",
|
||||
),
|
||||
|
||||
|
@ -13524,6 +13551,10 @@ The following values are permitted for **pawovlp**:
|
|||
- **pawovlp** < 0 --> overlap is always allowed
|
||||
- **pawovlp** = 0 --> no overlap is allowed
|
||||
- **pawovlp** > 0 and < 100 --> overlap is allowed only if it is less than **pawovlp** %
|
||||
|
||||
Note that ABINIT will not stop at the first time a too large overlap is identified, in case of [[ionmov]]/=0
|
||||
or [[imgmov]]/=0, but only at the second time in the same dataset. Indeed, such trespassing might only be transient.
|
||||
However, a second trespassing in the same dataset, or if both [[ionmov]]=0 and [[imgmov]]=0, will induce stop.
|
||||
""",
|
||||
),
|
||||
|
||||
|
@ -15325,7 +15356,7 @@ Variable(
|
|||
vartype="integer",
|
||||
topics=['printing_prgs'],
|
||||
dimensions="scalar",
|
||||
defaultval="prtgsr = 0",
|
||||
defaultval=ValueWithConditions({'[[nimage]] > 1': 0, 'defaultval': 1}),
|
||||
mnemonics="PRinT the GSR file",
|
||||
added_in_version="before_v9",
|
||||
text=r"""
|
||||
|
@ -15516,8 +15547,10 @@ Variable(
|
|||
text=r"""
|
||||
Print out VASP-style POSCAR and FORCES files, for use with PHON or frophon
|
||||
codes for frozen phonon calculations. See the associated script in
|
||||
{% modal ../scripts/post_processing/phondisp2abi.py %} for further details on
|
||||
interfacing with PHON, PHONOPY, etc...
|
||||
|
||||
{% dialog ../scripts/post_processing/phondisp2abi.py %}
|
||||
|
||||
for further details on interfacing with PHON, PHONOPY, etc...
|
||||
""",
|
||||
),
|
||||
|
||||
|
@ -15961,11 +15994,12 @@ will be the root output name, followed by _WFK. If [[nqpt]] = 1, the root name
|
|||
will be followed by _WFQ. For response-function calculations, the root name
|
||||
will be followed by _1WFx, where x is the number of the perturbation. The
|
||||
dataset information will be added as well, if relevant.
|
||||
No wavefunction output is provided by [[prtwf]] = 0.
|
||||
|
||||
If [[prtwf]] = 0, no wavefunction output is provided.
|
||||
|
||||
If [[prtwf]] = -1, the code writes the wavefunction file only if convergence is
|
||||
not achieved in the self-consistent cycle.
|
||||
|
||||
|
||||
If [[prtwf]] = 2, a file pwfn.data is produced, to be used as input for the
|
||||
CASINO QMC code. See more explanation at the end of this section.
|
||||
If [[prtwf]] = 3, the file that is created is nearly the same as with
|
||||
|
@ -16913,7 +16947,7 @@ elements of the dynamical matrix, use different values of [[rfatpol]] and/or
|
|||
[[rfdir]]. The name 'iatpol' is used for the part of the internal variable
|
||||
ipert when it runs from 1 to [[natom]]. The internal variable ipert can also
|
||||
assume values larger than [[natom]], denoting perturbations of electric field
|
||||
or stress type (see [the DFPT help file](../guide/respfn)).
|
||||
or stress type (see [the DFPT help file](/guide/respfn)).
|
||||
""",
|
||||
),
|
||||
|
||||
|
@ -20531,7 +20565,7 @@ The different possibilities are:
|
|||
where LOBPCG does not scale anymore. It is not able to use preconditionning and therefore might converge slower than other algorithms.
|
||||
By design, it will **not** converge the last bands: it is recommended to use slightly more bands than necessary.
|
||||
For usage with [[tolwfr]], it is imperative to use [[nbdbuf]]. For more performance, try [[use_gemm_nonlop]].
|
||||
For more information, see the [performance guide](../../theory/howto_chebfi.pdf) and the [[cite:Levitt2015]]. Status: experimental but usable.
|
||||
For more information, see the [performance guide](/theory/howto_chebfi.pdf) and the [[cite:Levitt2015]]. Status: experimental but usable.
|
||||
Questions and bug reports should be sent to antoine (dot) levitt (at) gmail.com.
|
||||
""",
|
||||
),
|
||||
|
@ -20764,7 +20798,7 @@ Variable(
|
|||
added_in_version="before_v9",
|
||||
text=r"""
|
||||
The modified Becke-Johnson exchange-correlation functional by
|
||||
[[cite:Tran2009 | Tran and Blaha]] reads:
|
||||
[[cite:Tran2009 | Tran and Blaha]] (acronym TB09, used when [[ixc]]=-12208, which needs [[usekden]]=1) reads:
|
||||
|
||||
$$ V_x(r) =
|
||||
c V_x^{BR}(r) +
|
||||
|
@ -20773,7 +20807,7 @@ c V_x^{BR}(r) +
|
|||
|
||||
where $\rho(r)$ is the electron density,
|
||||
$t(r)$ is the kinetic-energy density, and
|
||||
$ V_x^{BR}(r)$ is the Becke-Roussel potential.
|
||||
$V_x^{BR}(r)$ is the Becke-Roussel potential.
|
||||
|
||||
In this equation the parameter $c$ can be evaluated at each SCF step according
|
||||
to the following equation:
|
||||
|
@ -21519,7 +21553,7 @@ allocated for the wavefunctions, especially when we have to sum over empty state
|
|||
parallelize along this dimension. The parallelization over q-points seem to be more efficient than
|
||||
the one over perturbations although it introduces some load imbalance because, due to memory reasons,
|
||||
the code distributes the q-points in the IBZ (nqibz) instead of the q-points in the full BZ (nqbz).
|
||||
Moreover non all the q-points in the IBZ contribute to the imaginary part of $\Sigma_nk$.
|
||||
Moreover non all the q-points in the IBZ contribute to the imaginary part of $\Sigma_{nk}$.
|
||||
The MPI parallelism over k-points and spins is supported with similar behaviour as in **eph_task** +4.
|
||||
|
||||
|
||||
|
@ -21712,9 +21746,9 @@ to integrate the Frohlich divergence.
|
|||
|
||||
Possible values:
|
||||
|
||||
- = 0 --> Approximate oscillators with $ \delta_{b_1 b_2} $
|
||||
- > 0 --> Use full expression with G-dependence
|
||||
- < 0 --> Deactivate computation of oscillators.
|
||||
- = 0 --> Approximate oscillators with $ \delta_{b_1 b_2} $
|
||||
- > 0 --> Use full expression with G-dependence
|
||||
- < 0 --> Deactivate computation of oscillators.
|
||||
|
||||
!!! important
|
||||
|
||||
|
@ -22098,9 +22132,9 @@ to go from $W(\rr,\RR)$ to $v1scf(\rr,\qq)$.
|
|||
|
||||
Possible values are:
|
||||
|
||||
0 --> Use unit super cell for $\RR$ space. All weights set to 1.
|
||||
1 --> Use Wigner-Seitz super cell and atom-dependent weights (same algorithm as for the dynamical matrix).
|
||||
Note that this option leads to more $\RR$-points with a non-negligible increase of the memory allocated.
|
||||
0 --> Use unit super cell for $\RR$ space. All weights set to 1.
|
||||
1 --> Use Wigner-Seitz super cell and atom-dependent weights (same algorithm as for the dynamical matrix).
|
||||
Note that this option leads to more $\RR$-points with a non-negligible increase of the memory allocated.
|
||||
|
||||
!!! tip
|
||||
|
||||
|
@ -22266,8 +22300,8 @@ When performing structural relaxations, RMM-DIIS is activated after [[rmm_diis]]
|
|||
once the first GS calculation is completed.
|
||||
This means that using [[rmm_diis]] = 1 for a structural relaxation leads to:
|
||||
|
||||
- 4 SCF iterations with the CG/LOBPCG eigensolver followed by RMM-DIIS when are performing the **first GS calculation**.
|
||||
- 1 SCF iterations with CG/LOBPCG followed by RMM-DIIS for all the subsequent relaxation steps.
|
||||
- 4 SCF iterations with the CG/LOBPCG eigensolver followed by RMM-DIIS when are performing the **first GS calculation**.
|
||||
- 1 SCF iterations with CG/LOBPCG followed by RMM-DIIS for all the subsequent relaxation steps.
|
||||
|
||||
A negative value [[rmm_diis]] (e.g. -3) can be used to bypass the initial CG/LOBPCG iterations
|
||||
but this option should be used with extreme care and it is not recommended in general.
|
||||
|
@ -22281,7 +22315,7 @@ However, the additional steps of the algorithm (subspace rotation and Cholesky o
|
|||
present poor MPI-scalability hence this part will start to dominate the wall-time in systems with large [[nband]].
|
||||
|
||||
The algorithm can also be used for NSCF band structure calculations although one should not expect RMM-DIIS
|
||||
to provide **high-energy** states of the same quality as the one obtain with other eigenvalue solvers.
|
||||
to provide **high-energy** states of the same quality as the one obtained with other eigenvalue solvers.
|
||||
Although RMM-DIIS can be used for computing band structures and electron DOS with [[iscf]] = -2, we do not recommend
|
||||
using this solver to produce WFK files with many empty states as required by many-body calculations.
|
||||
|
||||
|
@ -22304,8 +22338,8 @@ for the Rayleigh-Ritz subspace rotation and this step is crucial for finding the
|
|||
to the eigenvectors before starting the DIIS optimization.
|
||||
|
||||
For a given precision, RMM-DIIS usually requires more iterations than the other eigensolvers.
|
||||
For performance reasons, one should avoid using tight tolerances, .
|
||||
Something of the order of [[tolvrs] = 1e-8 or [[toldfe]] = 1e-10 to stop the SCF cycle should be fine.
|
||||
For performance reasons, one should avoid using tight tolerances.
|
||||
Something of the order of [[tolvrs]] = 1e-8 or [[toldfe]] = 1e-10 to stop the SCF cycle should be fine.
|
||||
Avoid using ([[tolwfr]]) (criterion on the residuals) as converge criterion for SCF cycles
|
||||
Use [[tolwfr]] only if you are using RMM-DIIS for NSCF band structure calculations (as this is the only converge criterion
|
||||
available for NSCF calculations).
|
||||
|
@ -22334,4 +22368,51 @@ In this case, one can use [[rmm_diis_savemem]] = 1 to activate a version of RMM-
|
|||
""",
|
||||
),
|
||||
|
||||
Variable(
|
||||
abivarname="useextfpmd",
|
||||
varset="gstate",
|
||||
vartype="integer",
|
||||
topics=['ExtFPMD_basic'],
|
||||
dimensions="scalar",
|
||||
defaultval=0,
|
||||
mnemonics="USE EXTended FPMD model",
|
||||
added_in_version="9.5.2",
|
||||
text=r"""
|
||||
Enables the calculation of contributions to the energy, entropy, stresses,
|
||||
number of electrons and chemical potential using the extended first principle
|
||||
molecular dynamics model for high temperature simulations.
|
||||
|
||||
* **useextfpmd** = 1 *(Recommanded)*, the energy shift factor will be evaluated
|
||||
by making an integration of the trial potential over the real space and the
|
||||
contributions will be computed with integrals over the band number.
|
||||
|
||||
* **useextfpmd** = 2, the energy shift factor will be evaluated by making
|
||||
the average between the eigenvalues and the Fermi gas energy over the last
|
||||
[[extfpmd_nbcut]] bands, and the contributions will be computed with integrals
|
||||
over the band number.
|
||||
|
||||
* **useextfpmd** = 3, the energy shift factor will be evaluated by making the
|
||||
average between the eigenvalues and the kinetic energies over the last
|
||||
[[extfpmd_nbcut]] bands, and the contributions will be computed using the
|
||||
density of states of the Fermi gas.
|
||||
""",
|
||||
),
|
||||
|
||||
Variable(
|
||||
abivarname="extfpmd_nbcut",
|
||||
varset="gstate",
|
||||
vartype="integer",
|
||||
topics=['ExtFPMD_basic'],
|
||||
dimensions="scalar",
|
||||
defaultval=25,
|
||||
mnemonics="EXTended FPMD: Number of Bands at CUT",
|
||||
added_in_version="9.5.2",
|
||||
text=r"""
|
||||
Specify the number of bands to use when averaging over last bands to get the
|
||||
energy shift factor when [[useextfpmd]] = 2 or 3.
|
||||
|
||||
**extfpmd_nbcut** must be less than [[nband]].
|
||||
""",
|
||||
),
|
||||
|
||||
]
|
||||
|
|
|
@ -20,7 +20,7 @@ Variable(
|
|||
characteristics=['[[ENERGY]]'],
|
||||
added_in_version="before_v9",
|
||||
text=r"""
|
||||
Smearing width for the Eliashberg $\\alpha^2$F function (similar to a phonon DOS),
|
||||
Smearing width for the Eliashberg $\alpha^2$F function (similar to a phonon DOS),
|
||||
which is sampled on a finite q and k grid. The Dirac delta functions in energy
|
||||
are replaced by Gaussians of width **a2fsmear** (by default in Hartree).
|
||||
""",
|
||||
|
@ -1612,6 +1612,7 @@ Variable(
|
|||
text=r"""
|
||||
Only for electron-phonon calculations. This input variable is used to
|
||||
calculate the nesting function defined as:
|
||||
|
||||
$$
|
||||
\chi_{nm}(q) = \sum_k\delta(\epsilon_{k,n}-\epsilon_F) \delta(\epsilon_{k+q,m}-\epsilon_F).
|
||||
$$
|
||||
|
@ -2378,4 +2379,21 @@ instead of the legacy mode based on the files file. Example:
|
|||
""",
|
||||
),
|
||||
|
||||
Variable(
|
||||
abivarname="dos_maxmode@anaddb",
|
||||
varset="anaddb",
|
||||
vartype="integer",
|
||||
topics=['PhononBands_useful'],
|
||||
dimensions="scalar",
|
||||
defaultval=0,
|
||||
mnemonics="Phonon DOS MAX MODE included",
|
||||
added_in_version="9.5",
|
||||
text=r"""
|
||||
This variable specifies the maximum phonon mode index (up to 3*natom)
|
||||
included in the computation of the phonon DOS
|
||||
|
||||
Default is 0 i.e. all modes are included in the DOS.
|
||||
""",
|
||||
),
|
||||
|
||||
]
|
||||
|
|
|
@ -184,6 +184,24 @@ symmetry of the material. The directions of the requested components are specifi
|
|||
""",
|
||||
),
|
||||
|
||||
Variable(
|
||||
abivarname="prtlincompmatrixelements@optic",
|
||||
varset="optic",
|
||||
vartype="integer",
|
||||
topics=['Optic_basic'],
|
||||
dimensions="scalar",
|
||||
defaultval=0,
|
||||
mnemonics="PRinT the LINear COMPonent of the dielectric tensor's MATRIX ELEMENTS",
|
||||
added_in_version="v9.5",
|
||||
text=r"""
|
||||
If set to 1, the matrix elements, the renormalized (but unshifted) Kohn-Sham eigenvalues,
|
||||
the occupations and the kpts weights are all printed out in the ‘_OPTIC.nc’ file
|
||||
generated by the optic script. The matrix elements are the ones used to build the linear
|
||||
components of the dielectric tensor. Useful for post processing of matrix elements or
|
||||
rebuild the linear components of the dielectric tensor in an external script.
|
||||
""",
|
||||
),
|
||||
|
||||
Variable(
|
||||
abivarname="linel_comp@optic",
|
||||
varset="optic",
|
||||
|
|
|
@ -665,7 +665,7 @@ def structure_from_abistruct_fmt(string):
|
|||
"""
|
||||
Parse geometrical information given in the structure:abivars format return Structure object
|
||||
|
||||
A typical input file in "structure:abivars" format looks like:
|
||||
A typical input file in "structure:abivars" format looks like::
|
||||
|
||||
# MgB2 lattice structure.
|
||||
natom 3
|
||||
|
|
|
@ -157,6 +157,12 @@ class AbstractInput(MutableMapping, metaclass=abc.ABCMeta):
|
|||
kwargs.update(dict(*args))
|
||||
for varname, varvalue in kwargs.items():
|
||||
self[varname] = varvalue
|
||||
|
||||
# Just to make life easier to the user, we update some dimensions
|
||||
# if only the "array" part is specified in input.
|
||||
if "shiftk" in kwargs:
|
||||
self["nshiftk"] = len(np.reshape(self["shiftk"], (-1, 3)))
|
||||
|
||||
return kwargs
|
||||
|
||||
def set_vars_ifnotin(self, *args, **kwargs):
|
||||
|
@ -1213,6 +1219,7 @@ with the Abinit version you are using. Please contact the AbiPy developers.""" %
|
|||
Return a new input with the given variables.
|
||||
|
||||
Example:
|
||||
|
||||
new = input.new_with_vars(ecut=20, tsmear=0.04)
|
||||
"""
|
||||
# Avoid modifications in self.
|
||||
|
@ -1386,6 +1393,7 @@ with the Abinit version you are using. Please contact the AbiPy developers.""" %
|
|||
as ndivsm > 0 may produce a very large number of wavevectors.
|
||||
tolwfr: Tolerance on residuals for NSCF calculation.
|
||||
nscf_nband: Number of bands for NSCF calculation. If None, use nband + nb_extra
|
||||
nb_extra: Extra bandd to to be added to input nband if nscf_nband is None.
|
||||
"""
|
||||
nscf_input = self.deepcopy()
|
||||
nscf_input.pop_vars(["ngkpt", "shiftk"])
|
||||
|
@ -1451,7 +1459,7 @@ with the Abinit version you are using. Please contact the AbiPy developers.""" %
|
|||
|
||||
return nscf_input
|
||||
|
||||
def make_dfpt_effmass_inputs(self, kpts, effmass_bands_f90, tolwfr=1e-20, iscf=-2):
|
||||
def make_dfpt_effmass_inputs(self, kpts, effmass_bands_f90, ngfft=None, tolwfr=1e-20, iscf=-2):
|
||||
"""
|
||||
Return a |MultiDataset| object with 2 inputs for the calculation of effective masses with DFPT
|
||||
The first input in a standard NSCF run, the second input computes the effective masses.
|
||||
|
@ -1460,6 +1468,7 @@ with the Abinit version you are using. Please contact the AbiPy developers.""" %
|
|||
kpts: List of k-points in reduced coordinates where effective masses are wanted.
|
||||
efmas_bands_f90: (nkpt, 2) array with band range for effmas computation.
|
||||
WARNING: Assumes Fortran convention with indices starting from 1.
|
||||
ngfft: FFT divisions (3 integers). Used to enforce the same FFT mesh in the NSCF run as the one used for GS.
|
||||
tolwfr: Tolerance on residuals.
|
||||
"""
|
||||
multi = MultiDataset.replicate_input(input=self, ndtset=3)
|
||||
|
@ -1469,7 +1478,7 @@ with the Abinit version you are using. Please contact the AbiPy developers.""" %
|
|||
kpts = np.reshape(kpts, (-1, 3))
|
||||
nkpt = len(kpts)
|
||||
# NSCF calculation (requires DEN)
|
||||
multi[0].set_vars(tolwfr=tolwfr, kptopt=0, iscf=-2, nkpt=nkpt, kpt=kpts, prtwf=1)
|
||||
multi[0].set_vars(tolwfr=tolwfr, kptopt=0, iscf=-2, nkpt=nkpt, kpt=kpts, prtwf=1, ngfft=ngfft)
|
||||
|
||||
# Response function calculation: d/dk (requires DEN and GS WFK)
|
||||
multi[1].set_vars(
|
||||
|
@ -1484,6 +1493,7 @@ with the Abinit version you are using. Please contact the AbiPy developers.""" %
|
|||
efmas_calc_dirs=1,
|
||||
efmas_n_dirs=7,
|
||||
efmas_dirs=np.reshape([1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0], (7, 3)),
|
||||
ngfft=ngfft,
|
||||
)
|
||||
|
||||
# Input variables for Frohlich model calculation (need DDB, WFK and EFMAS file)
|
||||
|
@ -1909,32 +1919,60 @@ with the Abinit version you are using. Please contact the AbiPy developers.""" %
|
|||
#new.add_phbbands_vars()
|
||||
return new
|
||||
|
||||
def make_eph_isotc_input(self, ddb_ngqpt, eph_fsewin, eph_ngqpt_fine=None,
|
||||
mixprec=1, boxcutmin=1.1):
|
||||
"""
|
||||
Return an |AbinitInput| to perform phonon-limited transport calculations.
|
||||
This method is usually called with with the input associated to the NSCF run that produces
|
||||
the WFK file used to start the EPH run so that we can directly inherit the k-mesh
|
||||
#def make_eph_zpr_input(self, ddb_ngqpt, tmesh, eph_ngqpt_fine=None,,
|
||||
# mixprec=1, boxcutmin=1.1):
|
||||
# """
|
||||
# Return an |AbinitInput| to perform phonon-limited transport calculations.
|
||||
# This method is usually called with with the input associated to the NSCF run that produces
|
||||
# the WFK file used to start the EPH run so that we can directly inherit the k-mesh
|
||||
|
||||
Args:
|
||||
ddb_ngqpt: the coarse qpt grid used to compute the DDB and DVDB files in the phonon_work.
|
||||
eph_fsewin:
|
||||
eph_ngqpt_fine: the fine qpt grid used for the Fourier interpolation.
|
||||
boxcutmin: For the last task only, 1.1 is often used to decrease memory and is faster over the Abinit default of 2.
|
||||
mixprec: For the last task only, 1 is often used to make the EPH calculation faster. Note that Abinit default is 0.
|
||||
"""
|
||||
eph_ngqpt_fine = self.get("ngkpt") if eph_ngqpt_fine is None else eph_ngqpt_fine
|
||||
new = self.new_with_vars(
|
||||
optdriver=7, # Enter EPH driver.
|
||||
eph_task=-4, # Compute imag part of Phi phonon self-energy due to to electrons.
|
||||
ddb_ngqpt=ddb_ngqpt, # Ab-initio coarse q-mesh used to produce the DDB/DVDB files.
|
||||
eph_ngqpt_fine=eph_ngqpt_fine, # Interpolate DFPT potentials on this denser q-mesh.
|
||||
eph_fsewin=eph_fsewin,
|
||||
mixprec=mixprec,
|
||||
boxcutmin=boxcutmin,
|
||||
)
|
||||
#new.add_phbbands_vars()
|
||||
return new
|
||||
# Args:
|
||||
# ddb_ngqpt: the coarse qpt grid used to compute the DDB and DVDB files in the phonon_work.
|
||||
# eph_ngqpt_fine: the fine qpt grid used for the Fourier interpolation.
|
||||
# sigma_erange: Energy window for k-states (see Abinit variable)
|
||||
# tmesh: The mesh of temperatures (in Kelvin)
|
||||
# boxcutmin: For the last task only, 1.1 is often used to decrease memory and is faster over the Abinit default of 2.
|
||||
# mixprec: For the last task only, 1 is often used to make the EPH calculation faster. Note that Abinit default is 0.
|
||||
# """
|
||||
# eph_ngqpt_fine = self.get("ngkpt") if eph_ngqpt_fine is None else eph_ngqpt_fine
|
||||
# new = self.new_with_vars(
|
||||
# optdriver=7, # Enter EPH driver.
|
||||
# eph_task=+4, # Compute real and imag part of sigma_eph.
|
||||
# ddb_ngqpt=ddb_ngqpt, # Ab-initio coarse q-mesh used to produce the DDB/DVDB files.
|
||||
# eph_ngqpt_fine=eph_ngqpt_fine, # Interpolate DFPT potentials on this denser q-mesh.
|
||||
# tmesh=tmesh,
|
||||
# mixprec=mixprec,
|
||||
# boxcutmin=boxcutmin,
|
||||
# )
|
||||
# #new.add_phbbands_vars()
|
||||
# return ne
|
||||
|
||||
#def make_eph_isotc_input(self, ddb_ngqpt, eph_fsewin, eph_ngqpt_fine=None,,
|
||||
# mixprec=1, boxcutmin=1.1):
|
||||
# """
|
||||
# Return an |AbinitInput| to perform phonon-limited transport calculations.
|
||||
# This method is usually called with with the input associated to the NSCF run that produces
|
||||
# the WFK file used to start the EPH run so that we can directly inherit the k-mesh
|
||||
|
||||
# Args:
|
||||
# ddb_ngqpt: the coarse qpt grid used to compute the DDB and DVDB files in the phonon_work.
|
||||
# eph_fsewin:
|
||||
# eph_ngqpt_fine: the fine qpt grid used for the Fourier interpolation.
|
||||
# boxcutmin: For the last task only, 1.1 is often used to decrease memory and is faster over the Abinit default of 2.
|
||||
# mixprec: For the last task only, 1 is often used to make the EPH calculation faster. Note that Abinit default is 0.
|
||||
# """
|
||||
# eph_ngqpt_fine = self.get("ngkpt") if eph_ngqpt_fine is None else eph_ngqpt_fine
|
||||
# new = self.new_with_vars(
|
||||
# optdriver=7, # Enter EPH driver.
|
||||
# eph_task=-4, # Compute imag part of Phi phonon self-energy due to to electrons.
|
||||
# ddb_ngqpt=ddb_ngqpt, # Ab-initio coarse q-mesh used to produce the DDB/DVDB files.
|
||||
# eph_ngqpt_fine=eph_ngqpt_fine, # Interpolate DFPT potentials on this denser q-mesh.
|
||||
# eph_fsewin=eph_fsewin,
|
||||
# mixprec=mixprec,
|
||||
# boxcutmin=boxcutmin,
|
||||
# )
|
||||
# #new.add_phbbands_vars()
|
||||
# return new
|
||||
|
||||
def abivalidate(self, workdir=None, manager=None):
|
||||
"""
|
||||
|
|
|
@ -148,6 +148,9 @@ class TestAbinitInput(AbipyTest):
|
|||
assert popped["npband"] == 2 and "npband" not in new_inp
|
||||
assert popped["npfft"] == 3 and "npfft" not in new_inp
|
||||
|
||||
new_inp.set_vars(shiftk=[0, 0, 0, 0.5, 0, 0, 0, 0, 0.5])
|
||||
assert new_inp["nshiftk"] == 3
|
||||
|
||||
def test_input_errors(self):
|
||||
"""Testing typical AbinitInput Error"""
|
||||
si_structure = abilab.Structure.from_file(abidata.cif_file("si.cif"))
|
||||
|
|
|
@ -109,7 +109,7 @@ def phunit_tag(units, unicode=False):
|
|||
return s
|
||||
|
||||
|
||||
def wlabel_from_units(units):
|
||||
def wlabel_from_units(units, unicode=False):
|
||||
"""
|
||||
Return latex string for phonon frequencies in ``units``.
|
||||
"""
|
||||
|
@ -119,10 +119,15 @@ def wlabel_from_units(units):
|
|||
'thz': r'Frequency (Thz)',
|
||||
}
|
||||
try:
|
||||
return d[units.lower().strip()]
|
||||
s = d[units.lower().strip()]
|
||||
except KeyError:
|
||||
raise KeyError('Value for units `{}` unknown\nPossible values are:\n {}'.format(units, list(d.keys())))
|
||||
|
||||
if unicode:
|
||||
s = s.replace('$^{-1}$', '⁻¹')
|
||||
|
||||
return s
|
||||
|
||||
|
||||
def phdos_label_from_units(units, unicode=False):
|
||||
"""
|
||||
|
|
|
@ -546,11 +546,7 @@ class Function1D(object):
|
|||
if exchange_xy:
|
||||
xx, yy = yy, xx
|
||||
|
||||
if ply_row == 1 and ply_col == 1:
|
||||
fig.add_trace(go.Scatter(x=xx, y=yy, mode="lines", showlegend=showlegend, *args, **kwargs))
|
||||
|
||||
else:
|
||||
fig.add_trace(go.Scatter(x=xx, y=yy, mode="lines", showlegend=showlegend, *args, **kwargs),
|
||||
fig.add_trace(go.Scatter(x=xx, y=yy, mode="lines", showlegend=showlegend, *args, **kwargs),
|
||||
row=ply_row, col=ply_col)
|
||||
|
||||
@add_fig_kwargs
|
||||
|
|
|
@ -13,8 +13,7 @@ from monty.collections import AttrDict, dict2namedtuple
|
|||
from monty.functools import lazy_property
|
||||
from monty.string import marquee
|
||||
from pymatgen.core.lattice import Lattice
|
||||
from pymatgen.util.serialization import pmg_serialize
|
||||
from pymatgen.util.serialization import SlotPickleMixin
|
||||
from pymatgen.util.serialization import pmg_serialize, SlotPickleMixin
|
||||
from abipy.iotools import ETSF_Reader
|
||||
from abipy.tools.derivatives import finite_diff
|
||||
from abipy.tools.numtools import add_periodic_replicas, is_diagonal
|
||||
|
@ -1059,6 +1058,34 @@ class KpointList(collections.abc.Sequence):
|
|||
err_msg += "%s\n%s" % (self.__class__, self.to_string(verbose=0))
|
||||
raise ValueError(err_msg)
|
||||
|
||||
def get_highsym_datataframe(self, with_cart_coords=False):
|
||||
"""
|
||||
Return pandas Dataframe with the names of the high-symmetry k-points
|
||||
and the reduced coordinates.
|
||||
|
||||
Args:
|
||||
with_cart_coords: True to add extra column with the Cartesian coordinates.
|
||||
|
||||
Return: |pandas-DataFrame|
|
||||
"""
|
||||
replace = {
|
||||
r"$\Gamma$": "Γ",
|
||||
}
|
||||
|
||||
import pandas as pd
|
||||
rows, index = [], []
|
||||
for ik, kpt in enumerate(self):
|
||||
if kpt.name is None: continue
|
||||
d = dict(name=replace.get(kpt.name, kpt.name), frac_coords=kpt.frac_coords)
|
||||
if with_cart_coords: d["cart_coords"] = kpt.cart_coords
|
||||
rows.append(d)
|
||||
index.append(ik)
|
||||
|
||||
df = pd.DataFrame(rows, index=index)
|
||||
df.index.name = "Idx"
|
||||
|
||||
return df
|
||||
|
||||
def remove_duplicated(self):
|
||||
"""
|
||||
Remove duplicated k-points from self. Returns new :class:`KpointList` instance.
|
||||
|
@ -1109,6 +1136,19 @@ class KpointList(collections.abc.Sequence):
|
|||
return plot_brillouin_zone(self.reciprocal_lattice, kpoints=self.frac_coords,
|
||||
ax=ax, fold=fold, **kwargs)
|
||||
|
||||
def plotly(self, fig=None, **kwargs):
|
||||
"""Plot k-points with plotly."""
|
||||
from abipy.tools.plotting import plotly_wigner_seitz, plotly_brillouin_zone
|
||||
fold = False
|
||||
if self.is_path:
|
||||
labels = {k.name: k.frac_coords for k in self if k.name}
|
||||
frac_coords_lines = [self.frac_coords[line] for line in self.lines]
|
||||
return plotly_brillouin_zone(self.reciprocal_lattice, lines=frac_coords_lines, labels=labels,
|
||||
fig=fig, fold=fold, **kwargs)
|
||||
else:
|
||||
return plotly_brillouin_zone(self.reciprocal_lattice, kpoints=self.frac_coords,
|
||||
fig=fig, fold=fold, **kwargs)
|
||||
|
||||
def get_k2kqg_map(self, qpt, atol_kdiff=None):
|
||||
"""
|
||||
Compute mapping k_index --> (k + q)_index, g0
|
||||
|
@ -1190,15 +1230,21 @@ class Kpath(KpointList):
|
|||
@classmethod
|
||||
def from_vertices_and_names(cls, structure, vertices_names, line_density=20):
|
||||
"""
|
||||
Generate normalized K-path from a list of vertices and the corresponding labels.
|
||||
Generate normalized k-path from a list of vertices and the corresponding labels.
|
||||
|
||||
Args:
|
||||
structure: |Structure| object.
|
||||
vertices_names: List of tuple, each tuple is of the form (kfrac_coords, kname) where
|
||||
kfrac_coords are the reduced coordinates of the k-point and kname is a string with the name of
|
||||
the k-point. Each point represents a vertex of the k-path.
|
||||
line_density: Number of points used to sample the smallest segment of the path
|
||||
line_density: Number of points used to sample the smallest segment of the path.
|
||||
If 0, use list of k-points given in vertices_names
|
||||
"""
|
||||
if line_density == 0:
|
||||
frac_coords = [vn[0] for vn in vertices_names]
|
||||
knames = [vn[1] for vn in vertices_names]
|
||||
return cls(structure.lattice.reciprocal_lattice, frac_coords=frac_coords, weights=None, names=knames)
|
||||
|
||||
gmet = structure.lattice.reciprocal_lattice.metric_tensor
|
||||
vnames = [str(vn[1]) for vn in vertices_names]
|
||||
vertices = np.array([vn[0] for vn in vertices_names], dtype=float)
|
||||
|
@ -1230,8 +1276,7 @@ class Kpath(KpointList):
|
|||
knames.append(vnames[-1])
|
||||
frac_coords.append(vertices[-1])
|
||||
|
||||
return cls(structure.lattice.reciprocal_lattice, frac_coords=frac_coords,
|
||||
weights=None, names=knames)
|
||||
return cls(structure.lattice.reciprocal_lattice, frac_coords=frac_coords, weights=None, names=knames)
|
||||
|
||||
def __str__(self):
|
||||
return self.to_string()
|
||||
|
|
|
@ -131,13 +131,26 @@ class AbinitNcFile(BaseFile):
|
|||
according to the ETSF-IO specifications (when available).
|
||||
An AbinitNcFile has a netcdf reader to read data from file and build objects.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def from_binary_string(cls, bstring):
|
||||
"""
|
||||
Build object from a binary string with the netcdf data.
|
||||
Useful for implementing GUIs in which widgets returns binary data.
|
||||
"""
|
||||
workdir = tempfile.mkdtemp()
|
||||
fd, tmp_path = tempfile.mkstemp(suffix=".nc")
|
||||
with open(tmp_path, "wb") as fh:
|
||||
fh.write(bstring)
|
||||
return cls.from_file(tmp_path)
|
||||
|
||||
def ncdump(self, *nc_args, **nc_kwargs):
|
||||
"""Returns a string with the output of ncdump."""
|
||||
return NcDumper(*nc_args, **nc_kwargs).dump(self.filepath)
|
||||
|
||||
@lazy_property
|
||||
def abinit_version(self):
|
||||
"""String with abinit version: three digits separated by comma."""
|
||||
"""String with the abinit version: three digits separated by comma."""
|
||||
return self.reader.rootgrp.getncattr("abinit_version")
|
||||
|
||||
@abc.abstractproperty
|
||||
|
@ -147,8 +160,21 @@ class AbinitNcFile(BaseFile):
|
|||
Used to construct |pandas-DataFrames|.
|
||||
"""
|
||||
|
||||
#def get_abinit_input(self):
|
||||
# input_string = self.rootgrp.get_varname_set("input_string")
|
||||
def get_dims_dataframe(self, path="/"):
|
||||
"""
|
||||
Return: |pandas-Dataframe| with the dimensions defined in the `path` group.
|
||||
"""
|
||||
grp = self.reader.rootgrp if path == "/" else self.path2group[path]
|
||||
d = {k: len(v) for k, v in grp.dimensions.items()}
|
||||
# Since this is a Series but we want a dataframe to faciliate interoperability.
|
||||
# we have to call init with additional kwargs.
|
||||
import pandas as pd
|
||||
return pd.DataFrame.from_dict(d, orient='index', columns=['value'])
|
||||
|
||||
#def get_abinit_input_str(self, path="/"):
|
||||
# group = self.reader.rootgrp if path == "/" else self.path2group[path]
|
||||
# input_string = group.get_varname_set("input_string")
|
||||
# return input_string
|
||||
# from abipy.abio.inputs import AbinitInput
|
||||
# return AbinitInput(structure, pseudos, pseudo_dir=None, abi_kwargs=None)
|
||||
|
||||
|
@ -281,6 +307,10 @@ class Has_Structure(metaclass=abc.ABCMeta):
|
|||
"""*Generates* a predefined list of matplotlib figures with minimal input from the user."""
|
||||
yield self.structure.plot(show=False)
|
||||
|
||||
def yield_structure_plotly_figs(self, **kwargs):
|
||||
"""*Generates* a predefined list of plotly figures with minimal input from the user."""
|
||||
yield self.structure.plotly(show=False)
|
||||
|
||||
|
||||
class Has_ElectronBands(metaclass=abc.ABCMeta):
|
||||
"""Mixin class for |AbinitNcFile| containing electron data."""
|
||||
|
@ -366,14 +396,46 @@ class Has_ElectronBands(metaclass=abc.ABCMeta):
|
|||
yield self.ebands.plot_with_edos(edos, with_gaps=with_gaps, show=False)
|
||||
yield edos.plot(show=False)
|
||||
|
||||
def expose_ebands(self, slide_mode=False, slide_timeout=None, **kwargs):
|
||||
def yield_ebands_plotly_figs(self, **kwargs):
|
||||
"""*Generates* a predefined list of plotly figures with minimal input from the user."""
|
||||
with_gaps = not self.ebands.has_metallic_scheme
|
||||
if self.ebands.kpoints.is_path:
|
||||
yield self.ebands.plotly(with_gaps=with_gaps, show=False)
|
||||
yield self.ebands.kpoints.plotly(show=False)
|
||||
yield self.ebands.kpoints.plot(show=False)
|
||||
else:
|
||||
edos = self.ebands.get_edos()
|
||||
# TODO
|
||||
#yield self.ebands.plotly_with_edos(edos, with_gaps=with_gaps, show=False)
|
||||
yield edos.plotly(show=False)
|
||||
|
||||
def expose_ebands(self, slide_mode=False, slide_timeout=None, expose_web=False, **kwargs):
|
||||
"""
|
||||
Shows a predefined list of matplotlib figures for electron bands with minimal input from the user.
|
||||
"""
|
||||
from abipy.tools.plotting import MplExpose
|
||||
with MplExpose(slide_mode=slide_mode, slide_timeout=slide_mode, verbose=1) as e:
|
||||
from abipy.tools.plotting import MplExpose, PanelExpose
|
||||
|
||||
if expose_web:
|
||||
e = PanelExpose(title=f"e-Bands of {self.structure.formula}")
|
||||
else:
|
||||
e = MplExpose(slide_mode=slide_mode, slide_timeout=slide_mode, verbose=1)
|
||||
|
||||
with e:
|
||||
e(self.yield_ebands_figs(**kwargs))
|
||||
|
||||
#def plotly_expose_ebands(self, **kwargs):
|
||||
# """
|
||||
# This function *generates* a predefined list of plotly figures with minimal input from the user.
|
||||
# """
|
||||
# chart_studio = kwargs.pop("chart_studio", None)
|
||||
# verbose = kwargs.pop("verbose", 0)
|
||||
# kwargs.update(dict(
|
||||
# renderer="chart_studio" if chart_studio else None,
|
||||
# title=f"Band structure of {self.ebands.structure.formula}",
|
||||
# with_gaps = not self.ebands.has_metallic_scheme,
|
||||
# ))
|
||||
# self.ebands.plotly(**kwargs)
|
||||
|
||||
|
||||
class Has_PhononBands(metaclass=abc.ABCMeta):
|
||||
"""
|
||||
|
@ -409,6 +471,16 @@ class Has_PhononBands(metaclass=abc.ABCMeta):
|
|||
yield self.phbands.plot(units=units, show=False)
|
||||
yield self.phbands.plot_colored_matched(units=units, show=False)
|
||||
|
||||
def yield_phbands_plotly_figs(self, **kwargs): # pragma: no cover
|
||||
"""
|
||||
This function *generates* a predefined list of plotly figures with minimal input from the user.
|
||||
Used in abiview.py to get a quick look at the results.
|
||||
"""
|
||||
units = kwargs.get("units", "mev")
|
||||
yield self.phbands.qpoints.plotly(show=False)
|
||||
yield self.phbands.plotly(units=units, show=False)
|
||||
yield self.phbands.plot_colored_matched(units=units, show=False)
|
||||
|
||||
def expose_phbands(self, slide_mode=False, slide_timeout=None, **kwargs):
|
||||
"""
|
||||
Shows a predefined list of matplotlib figures for phonon bands with minimal input from the user.
|
||||
|
@ -470,11 +542,17 @@ def get_filestat(filepath):
|
|||
])
|
||||
|
||||
|
||||
class NotebookWriter(metaclass=abc.ABCMeta):
|
||||
"""
|
||||
Mixin class for objects that are able to generate jupyter_ notebooks.
|
||||
Subclasses must provide a concrete implementation of `write_notebook`.
|
||||
"""
|
||||
class HasNotebookTools(object):
|
||||
|
||||
def has_panel(self):
|
||||
"""
|
||||
Return panel module (that evaluates to True) if panel is installed else False.
|
||||
"""
|
||||
try:
|
||||
import panel as pn
|
||||
return pn
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
def make_and_open_notebook(self, nbpath=None, foreground=False,
|
||||
classic_notebook=False, no_browser=False): # pragma: no cover
|
||||
|
@ -635,6 +713,28 @@ abilab.enable_notebook(with_seaborn=True)
|
|||
|
||||
return nbformat, nbv, nb
|
||||
|
||||
@staticmethod
|
||||
def _write_nb_nbpath(nb, nbpath):
|
||||
"""
|
||||
This method must be called at the end of ``write_notebook``.
|
||||
nb is the jupyter notebook and nbpath the argument passed to ``write_notebook``.
|
||||
"""
|
||||
import io, os, tempfile
|
||||
if nbpath is None:
|
||||
_, nbpath = tempfile.mkstemp(prefix="abinb_", suffix='.ipynb', dir=os.getcwd(), text=True)
|
||||
|
||||
# Write notebook
|
||||
import nbformat
|
||||
with io.open(nbpath, 'wt', encoding="utf8") as fh:
|
||||
nbformat.write(nb, fh)
|
||||
return nbpath
|
||||
|
||||
class NotebookWriter(HasNotebookTools, metaclass=abc.ABCMeta):
|
||||
"""
|
||||
Mixin class for objects that are able to generate jupyter_ notebooks.
|
||||
Subclasses must provide a concrete implementation of `write_notebook`.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def write_notebook(self, nbpath=None):
|
||||
"""
|
||||
|
@ -658,22 +758,6 @@ abilab.enable_notebook(with_seaborn=True)
|
|||
return self._write_nb_nbpath(nb, nbpath)
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def _write_nb_nbpath(nb, nbpath):
|
||||
"""
|
||||
This method must be called at the end of ``write_notebook``.
|
||||
nb is the jupyter notebook and nbpath the argument passed to ``write_notebook``.
|
||||
"""
|
||||
import io, os, tempfile
|
||||
if nbpath is None:
|
||||
_, nbpath = tempfile.mkstemp(prefix="abinb_", suffix='.ipynb', dir=os.getcwd(), text=True)
|
||||
|
||||
# Write notebook
|
||||
import nbformat
|
||||
with io.open(nbpath, 'wt', encoding="utf8") as fh:
|
||||
nbformat.write(nb, fh)
|
||||
return nbpath
|
||||
|
||||
@classmethod
|
||||
def pickle_load(cls, filepath):
|
||||
"""
|
||||
|
@ -705,13 +789,94 @@ abilab.enable_notebook(with_seaborn=True)
|
|||
Used in abiview.py to get a quick look at the results.
|
||||
"""
|
||||
|
||||
def expose(self, slide_mode=False, slide_timeout=None, **kwargs):
|
||||
#@abc.abstractmethod
|
||||
#def yield_plotly_figs(self, **kwargs): # pragma: no cover
|
||||
# """
|
||||
# This function *generates* a predefined list of matplotlib figures with minimal input from the user.
|
||||
# Used in abiview.py to get a quick look at the results.
|
||||
# """
|
||||
|
||||
def _get_panel_and_template(self):
|
||||
# Create panel template with matplotlib figures and show them in the browser.
|
||||
import panel as pn
|
||||
pn.config.sizing_mode = 'stretch_width'
|
||||
from abipy.panels.core import get_template_cls_from_name
|
||||
cls = get_template_cls_from_name("FastGridTemplate")
|
||||
|
||||
title = self.__class__.__name__
|
||||
if hasattr(self, "structure"): title = f"{title} <small>({self.structure.formula})</small>"
|
||||
template = cls(
|
||||
title=title,
|
||||
header_background="#ff8c00 ", # Dark orange
|
||||
)
|
||||
|
||||
return pn, template
|
||||
|
||||
def expose(self, slide_mode=False, slide_timeout=None, use_web=False, **kwargs):
|
||||
"""
|
||||
Shows a predefined list of matplotlib figures with minimal input from the user.
|
||||
Relies on the ``yield_fig``s methods implemented by the subclass to generate matplotlib figures.
|
||||
|
||||
Args:
|
||||
use_web: True to show all figures inside a panel template executed in the local browser.
|
||||
False to show figures in different GUIs
|
||||
"""
|
||||
from abipy.tools.plotting import MplExpose
|
||||
with MplExpose(slide_mode=slide_mode, slide_timeout=slide_mode, verbose=1) as e:
|
||||
e(self.yield_figs(**kwargs))
|
||||
if not use_web:
|
||||
# Produce all matplotlib versions and show them with the X-server.
|
||||
from abipy.tools.plotting import MplExpose
|
||||
with MplExpose(slide_mode=slide_mode, slide_timeout=slide_mode, verbose=1) as e:
|
||||
e(self.yield_figs(**kwargs))
|
||||
|
||||
else:
|
||||
# Create panel template with matplotlib figures and show them in the browser.
|
||||
pn, template = self._get_panel_and_template()
|
||||
pn.config.sizing_mode = 'stretch_width'
|
||||
from abipy.panels.core import mpl
|
||||
for i, fig in enumerate(self.yield_figs()):
|
||||
row, col = divmod(i, 2)
|
||||
p = mpl(fig, with_divider=False)
|
||||
if hasattr(template.main, "append"):
|
||||
template.main.append(p)
|
||||
else:
|
||||
# Assume .main area acts like a GridSpec
|
||||
row_slice = slice(3 * row, 3 * (row + 1))
|
||||
if col == 0: template.main[row_slice, :6] = p
|
||||
if col == 1: template.main[row_slice, 6:] = p
|
||||
|
||||
return template.show()
|
||||
|
||||
def plotly_expose(self, **kwargs): # chart_studio=False, verbose=0,
|
||||
"""
|
||||
This function *generates* a predefined list of plotly figures with minimal input from the user.
|
||||
Relies on yield_plotly_figs implemented by the subclass to generate the figures.
|
||||
"""
|
||||
print("in plotly expose")
|
||||
|
||||
pn, template = self._get_panel_and_template()
|
||||
pn.config.sizing_mode = 'stretch_width'
|
||||
from abipy.panels.core import mpl, ply
|
||||
|
||||
# Insert figure in template.main.
|
||||
from abipy.tools.plotting import is_mpl_figure, is_plotly_figure
|
||||
for i, fig in enumerate(self.yield_plotly_figs()):
|
||||
row, col = divmod(i, 2)
|
||||
# Handle both matplotlib and plotly figures since we dont' support plotly everywhere.
|
||||
if is_plotly_figure(fig):
|
||||
p = ply(fig, with_divider=False)
|
||||
elif is_mpl_figure(fig):
|
||||
p = mpl(fig, with_divider=False)
|
||||
else:
|
||||
raise TypeError(f"Don't know how to handle type: `{type(fig)}`")
|
||||
|
||||
if hasattr(template.main, "append"):
|
||||
template.main.append(p)
|
||||
else:
|
||||
# Assume .main area acts like a panel GridSpec
|
||||
row_slice = slice(3 * row, 3 * (row + 1))
|
||||
if col == 0: template.main[row_slice, :6] = p
|
||||
if col == 1: template.main[row_slice, 6:] = p
|
||||
|
||||
return template.show()
|
||||
|
||||
|
||||
class Has_Header(object):
|
||||
|
|
|
@ -20,7 +20,7 @@ from pymatgen.core.structure import Structure as pmg_Structure
|
|||
from pymatgen.core.sites import PeriodicSite
|
||||
from pymatgen.core.lattice import Lattice
|
||||
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
|
||||
from abipy.tools.plotting import add_fig_kwargs, get_ax_fig_plt, get_axarray_fig_plt
|
||||
from abipy.tools.plotting import add_fig_kwargs, get_ax_fig_plt, get_axarray_fig_plt, add_plotly_fig_kwargs
|
||||
from abipy.flowtk import PseudoTable
|
||||
from abipy.core.mixins import NotebookWriter
|
||||
from abipy.core.symmetries import AbinitSpaceGroup
|
||||
|
@ -660,10 +660,10 @@ class Structure(pmg_Structure, NotebookWriter):
|
|||
|
||||
return("\n".join(lines))
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, **kwargs):
|
||||
"""Build panel with widgets to interact with the structure either in a notebook or in a bokeh app"""
|
||||
from abipy.panels.structure import StructurePanel
|
||||
return StructurePanel(self).get_panel()
|
||||
return StructurePanel(self).get_panel(**kwargs)
|
||||
|
||||
def get_conventional_standard_structure(self, international_monoclinic=True,
|
||||
symprec=1e-3, angle_tolerance=5):
|
||||
|
@ -1307,6 +1307,35 @@ class Structure(pmg_Structure, NotebookWriter):
|
|||
|
||||
return od
|
||||
|
||||
def get_symb2coords_dataframe(self, with_cart_coords=False):
|
||||
"""
|
||||
Return dictionary mapping element symbol to DataFrame with atomic positions
|
||||
in cartesian coordinates.
|
||||
|
||||
Args:
|
||||
with_cart_coords: True if Cartesian coordinates should be added as well.
|
||||
"""
|
||||
from collections import defaultdict
|
||||
if with_cart_coords:
|
||||
group = {symb: {"site_idx": [], "frac_coords": [], "cart_coords": []} for symb in self.symbol_set}
|
||||
else:
|
||||
group = {symb: {"site_idx": [], "frac_coords": []} for symb in self.symbol_set}
|
||||
|
||||
for idx, site in enumerate(self):
|
||||
symb = site.specie.symbol
|
||||
group[symb]["site_idx"].append(idx)
|
||||
group[symb]["frac_coords"].append(site.frac_coords)
|
||||
if with_cart_coords:
|
||||
group[symb]["cart_coords"].append(site.coords)
|
||||
|
||||
import pandas as pd
|
||||
out = {symb: pd.DataFrame.from_dict(d) for symb, d in group.items()}
|
||||
# Use site_idx and new index.
|
||||
for df in out.values():
|
||||
df.set_index("site_idx", inplace=True)
|
||||
|
||||
return out
|
||||
|
||||
@add_fig_kwargs
|
||||
def plot(self, **kwargs):
|
||||
"""
|
||||
|
@ -1316,6 +1345,15 @@ class Structure(pmg_Structure, NotebookWriter):
|
|||
from abipy.tools.plotting import plot_structure
|
||||
return plot_structure(self, **kwargs)
|
||||
|
||||
@add_plotly_fig_kwargs
|
||||
def plotly(self, **kwargs):
|
||||
"""
|
||||
Plot structure in 3D with plotly. Return plotly Figure
|
||||
See plot_structure for kwargs
|
||||
"""
|
||||
from abipy.tools.plotting import plotly_structure
|
||||
return plotly_structure(self, **kwargs)
|
||||
|
||||
@add_fig_kwargs
|
||||
def plot_bz(self, ax=None, pmg_path=True, with_labels=True, **kwargs):
|
||||
"""
|
||||
|
@ -1335,6 +1373,25 @@ class Structure(pmg_Structure, NotebookWriter):
|
|||
else:
|
||||
return plot_brillouin_zone(self.reciprocal_lattice, ax=ax, labels=labels, show=False, **kwargs)
|
||||
|
||||
@add_plotly_fig_kwargs
|
||||
def plotly_bz(self, fig=None, pmg_path=True, with_labels=True, **kwargs):
|
||||
"""
|
||||
Use matplotlib to plot the symmetry line path in the Brillouin Zone.
|
||||
|
||||
Args:
|
||||
ax: matplotlib :class:`Axes` or None if a new figure should be created.
|
||||
pmg_path (bool): True if the default path used in pymatgen should be show.
|
||||
with_labels (bool): True to plot k-point labels.
|
||||
|
||||
Returns: |matplotlib-Figure|.
|
||||
"""
|
||||
from abipy.tools.plotting import plotly_brillouin_zone_from_kpath, plotly_brillouin_zone
|
||||
labels = None if not with_labels else self.hsym_kpath.kpath["kpoints"]
|
||||
if pmg_path:
|
||||
return plotly_brillouin_zone_from_kpath(self.hsym_kpath, fig=fig, show=False, **kwargs)
|
||||
else:
|
||||
return plotly_brillouin_zone(self.reciprocal_lattice, fig=fig, labels=labels, show=False, **kwargs)
|
||||
|
||||
@add_fig_kwargs
|
||||
def plot_xrd(self, wavelength="CuKa", symprec=0, debye_waller_factors=None,
|
||||
two_theta_range=(0, 90), annotate_peaks=True, ax=None, **kwargs):
|
||||
|
@ -1534,17 +1591,17 @@ class Structure(pmg_Structure, NotebookWriter):
|
|||
raise ImportError("jupyter_jsmol is not installed. See https://github.com/fekad/jupyter-jsmol")
|
||||
|
||||
cif_str = self.write_cif_with_spglib_symms(None, symprec=symprec, ret_string=True)
|
||||
print("cif_str:\n", cif_str)
|
||||
#print("cif_str:\n", cif_str)
|
||||
#return JsmolView.from_str(cif_str)
|
||||
|
||||
from IPython.display import display, HTML
|
||||
#from IPython.display import display, HTML
|
||||
# FIXME TEMPORARY HACK TO LOAD JSMOL.js
|
||||
# See discussion at
|
||||
# https://stackoverflow.com/questions/16852885/ipython-adding-javascript-scripts-to-ipython-notebook
|
||||
display(HTML('<script type="text/javascript" src="/nbextensions/jupyter-jsmol/jsmol/JSmol.min.js"></script>'))
|
||||
#display(HTML('<script type="text/javascript" src="/nbextensions/jupyter-jsmol/jsmol/JSmol.min.js"></script>'))
|
||||
|
||||
jsmol = JsmolView(color='white')
|
||||
display(jsmol)
|
||||
#display(jsmol)
|
||||
cmd = 'load inline "%s" {1 1 1}' % cif_str
|
||||
if verbose: print("executing cmd:", cmd)
|
||||
jsmol.script(cmd)
|
||||
|
|
|
@ -77,6 +77,7 @@ class TestHelperFunctions(AbipyTest):
|
|||
[0.4, 0.0, 0.0 ],
|
||||
[0.5, 0.0, 0.0 ]])
|
||||
|
||||
|
||||
class TestKpoint(AbipyTest):
|
||||
"""Unit tests for Kpoint object."""
|
||||
|
||||
|
@ -283,6 +284,12 @@ class TestKpath(AbipyTest):
|
|||
#assert kpath.ksampling.kptopt == 1
|
||||
#self.assert_equal(kpath.ksampling.mpdivs, [4, 4, 4])
|
||||
|
||||
df = kpath.get_highsym_datataframe(with_cart_coords=True)
|
||||
#print(df)
|
||||
assert "G" in df["name"].values
|
||||
assert "cart_coords" in df
|
||||
self.assert_equal(df["frac_coords"][0], [0.0, 0.0, 0.0])
|
||||
|
||||
assert Kpoint.from_name_and_structure("Gamma", structure) == kpath[0]
|
||||
|
||||
assert len(kpath.ds) == len(kpath) - 1
|
||||
|
|
|
@ -58,6 +58,13 @@ class TestStructure(AbipyTest):
|
|||
self.assert_equal(kfrac_coords,
|
||||
([[0. , 0. , 0. ], [0.5, 0. , 0.5], [0.5, 0.5, 0.5], [0. , 0. , 0. ]]))
|
||||
|
||||
d = si.get_symb2coords_dataframe(with_cart_coords=True)
|
||||
assert "Si" in d
|
||||
df = d["Si"]
|
||||
assert "frac_coords" in df and len(df.frac_coords) == 2
|
||||
for i in range(2):
|
||||
self.assert_equal(si.frac_coords[i], df.frac_coords.values[i])
|
||||
|
||||
si_wfk = Structure.as_structure(abidata.ref_file("si_scf_WFK.nc"))
|
||||
assert si_wfk.formula == "Si2"
|
||||
si_wfk.print_neighbors(radius=2.5)
|
||||
|
|
|
@ -33,14 +33,28 @@ from abipy.dfpt.ifc import InteratomicForceConstants
|
|||
from abipy.dfpt.elastic import ElasticData
|
||||
from abipy.dfpt.raman import Raman
|
||||
from abipy.core.abinit_units import phfactor_ev2units, phunit_tag
|
||||
from abipy.tools.plotting import (add_fig_kwargs, get_ax_fig_plt, get_axarray_fig_plt,
|
||||
plotlyfigs_to_browser, push_to_chart_studio)
|
||||
from abipy.tools.plotting import (add_fig_kwargs, get_ax_fig_plt, get_axarray_fig_plt, get_figs_plotly, get_fig_plotly,
|
||||
add_plotly_fig_kwargs, PlotlyRowColDesc, plotlyfigs_to_browser, push_to_chart_studio)
|
||||
from abipy.tools import duck
|
||||
from abipy.tools.iotools import ExitStackWithFiles
|
||||
from abipy.tools.tensors import DielectricTensor, ZstarTensor, Stress
|
||||
from abipy.abio.robots import Robot
|
||||
|
||||
|
||||
SUBSCRIPT_UNICODE = {
|
||||
"0": "₀",
|
||||
"1": "₁",
|
||||
"2": "₂",
|
||||
"3": "₃",
|
||||
"4": "₄",
|
||||
"5": "₅",
|
||||
"6": "₆",
|
||||
"7": "₇",
|
||||
"8": "₈",
|
||||
"9": "₉",
|
||||
}
|
||||
|
||||
|
||||
class DdbError(Exception):
|
||||
"""Error class raised by DDB."""
|
||||
|
||||
|
@ -909,6 +923,14 @@ class DdbFile(TextFile, Has_Structure, NotebookWriter):
|
|||
yield self.qpoints.plot(show=False)
|
||||
yield self.structure.plot_bz(show=False)
|
||||
|
||||
def yield_plotly_figs(self, **kwargs): # pragma: no cover
|
||||
"""
|
||||
This function *generates* a predefined list of plotly figures with minimal input from the user.
|
||||
"""
|
||||
yield self.structure.plotly(show=False)
|
||||
yield self.qpoints.plotly(show=False)
|
||||
yield self.structure.plotly_bz(show=False)
|
||||
|
||||
def anaget_phmodes_at_qpoint(self, qpoint=None, asr=2, chneut=1, dipdip=1, workdir=None, mpi_procs=1,
|
||||
manager=None, verbose=0, lo_to_splitting=False, spell_check=True,
|
||||
directions=None, anaddb_kwargs=None, return_input=False):
|
||||
|
@ -1422,11 +1444,13 @@ class DdbFile(TextFile, Has_Structure, NotebookWriter):
|
|||
|
||||
label = "asr: %d, chneut: %d, dipdip: %d, dipquad: %d, quadquad: %d " % (
|
||||
asr, dipdip, chneut, conf["dipquad"], conf["quadquad"])
|
||||
|
||||
if phdos_file is not None:
|
||||
phbands_plotter.add_phbands(label, phbst_file.phbands, phdos=phdos_file.phdos)
|
||||
phdos_file.close()
|
||||
else:
|
||||
phbands_plotter.add_phbands(label, phbst_file.phbands)
|
||||
|
||||
phbst_file.close()
|
||||
|
||||
return phbands_plotter
|
||||
|
@ -1544,6 +1568,7 @@ class DdbFile(TextFile, Has_Structure, NotebookWriter):
|
|||
from abipy.dfpt.converters import abinit_to_phonopy
|
||||
anaddbnc_path = task.outpath_from_ext("anaddb.nc")
|
||||
anaddbnc = AnaddbNcFile(anaddbnc_path)
|
||||
|
||||
phon = abinit_to_phonopy(anaddbnc=anaddbnc, supercell_matrix=supercell_matrix,
|
||||
symmetrize_tensors=symmetrize_tensors, output_dir_path=output_dir_path,
|
||||
prefix_outfiles=prefix_outfiles, symprec=symprec, set_masses=set_masses)
|
||||
|
@ -1847,6 +1872,7 @@ class DdbFile(TextFile, Has_Structure, NotebookWriter):
|
|||
def remove_block(self, dord, qpt=None, qpt3=None):
|
||||
"""
|
||||
Removes one block from the list of blocks in the ddb
|
||||
|
||||
Args:
|
||||
dord: the order of the perturbation (from 0 to 3).
|
||||
qpt: the fractional coordinates of the q point of the block to be
|
||||
|
@ -1909,10 +1935,12 @@ class DdbFile(TextFile, Has_Structure, NotebookWriter):
|
|||
|
||||
self.insert_block(block_data, replace=replace)
|
||||
|
||||
def get_panel(self):
|
||||
"""Build panel with widgets to interact with the |DdbFile| either in a notebook or in panel app."""
|
||||
def get_panel(self, **kwargs):
|
||||
"""
|
||||
Build panel with widgets to interact with the |DdbFile| either in a notebook or in a bokeh app.
|
||||
"""
|
||||
from abipy.panels.ddb import DdbFilePanel
|
||||
return DdbFilePanel(self).get_panel()
|
||||
return DdbFilePanel(self).get_panel(**kwargs)
|
||||
|
||||
def write_notebook(self, nbpath=None):
|
||||
"""
|
||||
|
@ -1920,11 +1948,23 @@ class DdbFile(TextFile, Has_Structure, NotebookWriter):
|
|||
working directory is created. Return path to the notebook.
|
||||
"""
|
||||
nbformat, nbv, nb = self.get_nbformat_nbv_nb(title=None)
|
||||
first_char = "" if self.has_panel() else "#"
|
||||
|
||||
nb.cells.extend([
|
||||
nbv.new_code_cell("ddb = abilab.abiopen('%s')" % self.filepath),
|
||||
nbv.new_code_cell("units = 'eV'\nprint(ddb)"),
|
||||
nbv.new_code_cell("# display(ddb.header)"),
|
||||
|
||||
# Add panel GUI but comment the python code if panel is not available.
|
||||
nbv.new_markdown_cell("## Panel dashboard"),
|
||||
nbv.new_code_cell(f"""\
|
||||
# Execute this cell to display the panel GUI (requires panel package).
|
||||
# To display the dashboard inside the browser use `abiopen.py FILE --panel`.
|
||||
|
||||
{first_char}abilab.abipanel()
|
||||
{first_char}ddb.get_panel()
|
||||
"""),
|
||||
|
||||
nbv.new_markdown_cell("## Invoke `anaddb` to compute bands and dos"),
|
||||
nbv.new_code_cell("""\
|
||||
bstfile, phdosfile = ddb.anaget_phbst_and_phdos_files(nqsmall=10, ndivsm=20,
|
||||
|
@ -2289,7 +2329,7 @@ class DielectricTensorGenerator(Has_Structure):
|
|||
def plot(self, w_min=0, w_max=None, gamma_ev=1e-4, num=500, component='diag', reim="reim", units='eV',
|
||||
with_phfreqs=True, ax=None, fontsize=12, **kwargs):
|
||||
"""
|
||||
Plots the selected components of the dielectric tensor as a function of frequency.
|
||||
Plots the selected components of the dielectric tensor as a function of frequency with matplotlib.
|
||||
|
||||
Args:
|
||||
w_min: minimum frequency in units `units`.
|
||||
|
@ -2325,8 +2365,8 @@ class DielectricTensorGenerator(Has_Structure):
|
|||
if 'linewidth' not in kwargs:
|
||||
kwargs['linewidth'] = 2
|
||||
|
||||
ax.set_xlabel('Frequency {}'.format(phunit_tag(units)))
|
||||
ax.set_ylabel(r'$\epsilon(\omega)$')
|
||||
ax.set_xlabel('Frequency {}'.format(phunit_tag(units)), fontsize=fontsize)
|
||||
ax.set_ylabel(r'$\epsilon(\omega)$', fontsize=fontsize)
|
||||
ax.grid(True)
|
||||
|
||||
reimfs = []
|
||||
|
@ -2349,7 +2389,7 @@ class DielectricTensorGenerator(Has_Structure):
|
|||
label = reims % r'$\epsilon_{%d%d}$' % (i, j)
|
||||
ax.plot(wmesh, reimf(t[:, i, j]), label=label, **kwargs)
|
||||
elif component == 'diag_av':
|
||||
label = r'$Average\, %s\epsilon_{ii}$' % reims
|
||||
label = r'Average %s' % (reims % r'$\epsilon_{ii}$')
|
||||
ax.plot(wmesh, np.trace(reimf(t), axis1=1, axis2=2)/3, label=label, **kwargs)
|
||||
else:
|
||||
raise ValueError('Unkwnown component {}'.format(component))
|
||||
|
@ -2360,6 +2400,89 @@ class DielectricTensorGenerator(Has_Structure):
|
|||
|
||||
return fig
|
||||
|
||||
@add_plotly_fig_kwargs
|
||||
def plotly(self, w_min=0, w_max=None, gamma_ev=1e-4, num=500, component='diag', reim="reim", units='eV',
|
||||
with_phfreqs=True, fig=None, rcd=None, fontsize=16, **kwargs):
|
||||
"""
|
||||
Plots the selected components of the dielectric tensor as a function of frequency with plotly.
|
||||
|
||||
Args:
|
||||
w_min: minimum frequency in units `units`.
|
||||
w_max: maximum frequency. If None it will be set to the value of the maximum frequency + 5*gamma_ev.
|
||||
gamma_ev: Phonon damping factor in eV (full width). Poles are shifted by phfreq * gamma_ev.
|
||||
Accept scalar or [nfreq] array.
|
||||
num: number of values of the frequencies between w_min and w_max.
|
||||
component: determine which components of the tensor will be displayed. Can be a list/tuple of two
|
||||
elements, indicating the indices [i, j] of the desired component or a string among::
|
||||
|
||||
* 'diag_av' to plot the average of the components on the diagonal
|
||||
* 'diag' to plot the elements on diagonal
|
||||
* 'all' to plot all the components in the upper triangle.
|
||||
* 'offdiag' to plot the off-diagonal components in the upper triangle.
|
||||
|
||||
reim: a string with "re" will plot the real part, with "im" selects the imaginary part.
|
||||
units: string specifying the units used for phonon frequencies. Possible values in
|
||||
("eV", "meV", "Ha", "cm-1", "Thz"). Case-insensitive.
|
||||
with_phfreqs: True to show phonon frequencies with dots.
|
||||
fig: |plotly.graph_objects.Figure| or None if a new figure should be created.
|
||||
rcd: PlotlyRowColDesc object used when fig is not None to specify the (row, col) of the subplot in the grid.
|
||||
fontsize: Legend and label fontsize.
|
||||
|
||||
Return: |plotly.graph_objects.Figure|
|
||||
"""
|
||||
wmesh = self._get_wmesh(gamma_ev, num, units, w_min, w_max)
|
||||
t = np.zeros((num, 3, 3), dtype=complex)
|
||||
|
||||
for i, w in enumerate(wmesh):
|
||||
t[i] = self.tensor_at_frequency(w, units=units, gamma_ev=gamma_ev)
|
||||
|
||||
if fig is None:
|
||||
fig, _ = get_fig_plotly()
|
||||
|
||||
rcd = PlotlyRowColDesc.from_object(rcd)
|
||||
iax, ply_row, ply_col = rcd.iax, rcd.ply_row, rcd.ply_col
|
||||
xaxis = 'xaxis%u' % iax
|
||||
yaxis = 'yaxis%u' % iax
|
||||
fig.layout[xaxis].title = dict(text='Frequency {}'.format(phunit_tag(units, unicode=True)), font_size=fontsize)
|
||||
fig.layout[yaxis].title = dict(text='ε(ω)', font_size=fontsize)
|
||||
|
||||
if 'line_width' not in kwargs:
|
||||
kwargs['line_width'] = 2
|
||||
|
||||
reimfs = []
|
||||
if 're' in reim: reimfs.append((np.real, "Re{%s}"))
|
||||
if 'im' in reim: reimfs.append((np.imag, "Im{%s}"))
|
||||
|
||||
for reimf, reims in reimfs:
|
||||
if isinstance(component, (list, tuple)):
|
||||
label = reims % r'ε%s%s' % (SUBSCRIPT_UNICODE[str(component[0])],SUBSCRIPT_UNICODE[str(component[1])])
|
||||
fig.add_scatter(x=wmesh, y=reimf(t[:,component[0], component[1]]), mode='lines', showlegend=True,
|
||||
name=label, row=ply_row, col=ply_col, **kwargs)
|
||||
elif component == 'diag':
|
||||
for i in range(3):
|
||||
s = SUBSCRIPT_UNICODE[str(i)]
|
||||
label = reims % r'ε%s%s' % (s, s)
|
||||
fig.add_scatter(x=wmesh, y=reimf(t[:, i, i]), mode='lines', name=label, row=ply_row, col=ply_col, **kwargs)
|
||||
elif component in ('all', "offdiag"):
|
||||
for i in range(3):
|
||||
for j in range(3):
|
||||
if component == "all" and i > j: continue
|
||||
if component == "offdiag" and i >= j: continue
|
||||
label = reims % r'ε%s%s' % (SUBSCRIPT_UNICODE[str(i)], SUBSCRIPT_UNICODE[str(j)])
|
||||
fig.add_scatter(x=wmesh, y=reimf(t[:, i, j]), mode='lines', name=label, row=ply_row,
|
||||
col=ply_col, **kwargs)
|
||||
elif component == 'diag_av':
|
||||
label = r'Average %s' % (reims % r'εᵢᵢ')
|
||||
fig.add_scatter(x=wmesh, y=np.trace(reimf(t), axis1=1, axis2=2)/3, mode='lines', name=label,
|
||||
row=ply_row, col=ply_col, **kwargs)
|
||||
else:
|
||||
raise ValueError('Unkwnown component {}'.format(component))
|
||||
|
||||
self._add_phfreqs_plotly(fig, rcd, units, with_phfreqs)
|
||||
fig.layout.legend.font.size = fontsize
|
||||
|
||||
return fig
|
||||
|
||||
def _get_wmesh(self, gamma_ev, num, units, w_min, w_max):
|
||||
"""
|
||||
Helper function to get the wmesh for the plots.
|
||||
|
@ -2500,6 +2623,22 @@ class DielectricTensorGenerator(Has_Structure):
|
|||
wvals = self.phfreqs[3:] * phfactor_ev2units(units)
|
||||
ax.scatter(wvals, np.zeros_like(wvals), s=30, marker="o", c="blue")
|
||||
|
||||
def _add_phfreqs_plotly(self, fig, rcd, units, with_phfreqs):
|
||||
"""
|
||||
Helper functions to add the phonon frequencies to the plotly fig.
|
||||
Args:
|
||||
fig: |plotly.graph_objects.Figure|
|
||||
rcd: PlotlyRowColDesc object used when fig is not None to specify the (row, col) of the subplot in the grid.
|
||||
units: string specifying the units used for phonon frequencies. Possible values in
|
||||
("eV", "meV", "Ha", "cm-1", "Thz"). Case-insensitive.
|
||||
with_phfreqs: True to show phonon frequencies with dots.
|
||||
"""
|
||||
# Add points showing phonon energies.
|
||||
if with_phfreqs:
|
||||
wvals = self.phfreqs[3:] * phfactor_ev2units(units)
|
||||
fig.add_scatter(x=wvals, y=np.zeros_like(wvals), mode='markers', marker=dict(color='blue', size=10),
|
||||
name='', row=rcd.ply_row, col=rcd.ply_col, showlegend=False)
|
||||
|
||||
def reflectivity(self, qdir, w, gamma_ev=1e-4, units='eV'):
|
||||
"""
|
||||
Calculates the reflectivity from the dielectric tensor along the specified direction
|
||||
|
@ -3009,16 +3148,16 @@ class DdbRobot(Robot):
|
|||
if all(ddb.has_at_least_one_atomic_perturbation() for ddb in self.abifiles):
|
||||
print("Invoking anaddb through anaget_phonon_plotters...")
|
||||
r = self.anaget_phonon_plotters()
|
||||
#for fig in r.phbands_plotter.yield_figs(): yield fig
|
||||
#for fig in r.phdos_plotter.yield_figs(): yield fig
|
||||
#for fig in r.phbands_plotter.yield_plotly_figs(): yield fig
|
||||
#for fig in r.phdos_plotter.yield_plotly_figs(): yield fig
|
||||
f(r.phbands_plotter.combiplotly(show=False))
|
||||
|
||||
push_to_chart_studio(figs) if chart_studio else plotlyfigs_to_browser(figs)
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, **kwargs):
|
||||
"""Return a panel object that allows the user to compare the results with a web-based interface."""
|
||||
from abipy.panels.ddb import DdbRobotPanel
|
||||
return DdbRobotPanel(self).get_panel()
|
||||
return DdbRobotPanel(self).get_panel(**kwargs)
|
||||
|
||||
def write_notebook(self, nbpath=None):
|
||||
"""
|
||||
|
@ -3053,20 +3192,20 @@ class DdbRobot(Robot):
|
|||
def get_2nd_ord_block_string(qpt, data):
|
||||
"""
|
||||
Helper function providing the lines required in a DDB file for a given
|
||||
q point and second order derivatives.
|
||||
q-point and second order derivatives.
|
||||
|
||||
Args:
|
||||
qpt: the fractional coordinates of the q point.
|
||||
data: a dictionary of the form {qpt: {(idir1, ipert1, idir2, ipert2): complex value}}
|
||||
with the data that should be given in the string.
|
||||
|
||||
Returns:
|
||||
list of str: the lines that can be added to the DDB file.
|
||||
Returns: list of str: the lines that can be added to the DDB file.
|
||||
"""
|
||||
lines = []
|
||||
lines.append(f" 2nd derivatives (non-stat.) - # elements :{len(data):8}")
|
||||
lines.append(" qpt{:16.8E}{:16.8E}{:16.8E} 1.0".format(*qpt))
|
||||
l_format = "{:4d}" * 4 + " {:22.14E}" * 2
|
||||
|
||||
for p, v in data.items():
|
||||
lines.append(l_format.format(*p, v.real, v.imag))
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ from abipy.iotools import ETSF_Reader
|
|||
from abipy.tools import duck
|
||||
from abipy.tools.numtools import gaussian, sort_and_groupby
|
||||
from abipy.tools.plotting import add_fig_kwargs, get_ax_fig_plt, set_axlims, get_axarray_fig_plt, set_visible,\
|
||||
set_ax_xylabels, get_figs_plotly, get_fig_plotly, add_plotly_fig_kwargs,\
|
||||
plotlyfigs_to_browser, push_to_chart_studio, PlotlyRowColDesc, plotly_klabels
|
||||
set_ax_xylabels, get_figs_plotly, get_fig_plotly, add_plotly_fig_kwargs, plotlyfigs_to_browser,\
|
||||
push_to_chart_studio, PlotlyRowColDesc, plotly_klabels, plotly_set_xylabels, plotly_set_lims
|
||||
from .phtk import match_eigenvectors, get_dyn_mat_eigenvec, open_file_phononwebsite, NonAnalyticalPh
|
||||
|
||||
__all__ = [
|
||||
|
@ -1015,7 +1015,7 @@ See also <https://forum.abinit.org/viewtopic.php?f=10&t=545>
|
|||
|
||||
# Handle conversion factor.
|
||||
if units:
|
||||
fig.layout['yaxis%u' % iax].title.text = abu.wlabel_from_units(units).replace('$^{-1}$', '⁻¹')
|
||||
fig.layout['yaxis%u' % iax].title.text = abu.wlabel_from_units(units, unicode=True)
|
||||
|
||||
fig.layout[xaxis].title.text = "Wave Vector"
|
||||
|
||||
|
@ -1085,7 +1085,7 @@ See also <https://forum.abinit.org/viewtopic.php?f=10&t=545>
|
|||
|
||||
@add_plotly_fig_kwargs
|
||||
def plotly(self, units="eV", qlabels=None, branch_range=None, match_bands=False, temp=None,
|
||||
fig=None, rcd=None, fontsize=16, **kwargs):
|
||||
fig=None, rcd=None, fontsize=12, **kwargs):
|
||||
r"""
|
||||
Plot the phonon band structure with plotly.
|
||||
|
||||
|
@ -1108,7 +1108,7 @@ See also <https://forum.abinit.org/viewtopic.php?f=10&t=545>
|
|||
branch_range = range(self.num_branches) if branch_range is None else \
|
||||
range(branch_range[0], branch_range[1], 1)
|
||||
|
||||
fig, go = get_fig_plotly(fig=fig)
|
||||
fig, _ = get_fig_plotly(fig=fig)
|
||||
|
||||
# Decorate the axis (e.g. add ticks and labels).
|
||||
rcd = PlotlyRowColDesc.from_object(rcd)
|
||||
|
@ -1124,9 +1124,8 @@ See also <https://forum.abinit.org/viewtopic.php?f=10&t=545>
|
|||
# Scatter plot with Bose-Einstein occupation factors for T = temp
|
||||
factor = abu.phfactor_ev2units(units)
|
||||
if temp < 1: temp = 1
|
||||
# this will be covered if the title is set by the user
|
||||
fig.layout.title.text = "T = %.1f K" % temp
|
||||
fig.layout.title.font.size = fontsize
|
||||
fig.layout.annotations=[dict(text="T = %.1f K" % temp, font_size=fontsize, x=0.5, xref='paper',
|
||||
xanchor='center', y=1, yref='paper', yanchor='bottom' ,showarrow=False)]
|
||||
xs = np.arange(self.num_qpoints)
|
||||
for nu in self.branches:
|
||||
ws = self.phfreqs[:, nu]
|
||||
|
@ -1136,9 +1135,9 @@ See also <https://forum.abinit.org/viewtopic.php?f=10&t=545>
|
|||
occ = 1.0 / (np.exp(wkt) - 1.0)
|
||||
s = np.where(occ < 0.3, occ, 0.3) * 50
|
||||
#print("rcd", rcd)
|
||||
fig.add_trace(go.Scatter(x=xs, y=ws * factor, mode='markers',
|
||||
marker=dict(color=occ, colorscale='jet', size=s, opacity=0.6, line_width=0),
|
||||
showlegend=False), row=rcd.ply_row, col=rcd.ply_col)
|
||||
fig.add_scatter(x=xs, y=ws * factor, mode='markers', row=rcd.ply_row, col=rcd.ply_col, showlegend=False,
|
||||
marker=dict(color='blue', size=s, opacity=0.6, line_width=0), name='')
|
||||
# marker=dict(color=occ, colorscale='jet', size=s, opacity=0.6, line_width=0),
|
||||
return fig
|
||||
|
||||
def plot_ax(self, ax, branch, units='eV', match_bands=False, **kwargs):
|
||||
|
@ -1173,13 +1172,13 @@ See also <https://forum.abinit.org/viewtopic.php?f=10&t=545>
|
|||
return lines
|
||||
|
||||
def plotly_traces(self, fig, branch, rcd=None, units='eV', name='', match_bands=False,
|
||||
showlengend=False, **kwargs):
|
||||
showlegend=False, **kwargs):
|
||||
"""
|
||||
Plots the frequencies for the given branches indices as a function of the q-index on figure ``fig`` .
|
||||
If ``fig`` has subplots, ``rcd`` is used to add traces on these subplots.
|
||||
If ``branch`` is None, all phonon branches are plotted.
|
||||
kwargs: Passed to fig.add_scatter method.
|
||||
"""
|
||||
import plotly.graph_objects as go
|
||||
linecolor = kwargs.pop("color", "black")
|
||||
linewidth = kwargs.pop("linewidth", 2.0)
|
||||
|
||||
|
@ -1203,17 +1202,11 @@ See also <https://forum.abinit.org/viewtopic.php?f=10&t=545>
|
|||
pf = pf * factor
|
||||
xx = list(range(first_xx, first_xx + len(pf)))
|
||||
for branch in branch_range:
|
||||
if ply_row == 1 and ply_col == 1:
|
||||
fig.add_trace(
|
||||
go.Scatter(x=xx, y=pf[:, branch], mode='lines', name=name, legendgroup=name, showlegend=False,
|
||||
line=dict(color=linecolor, width=linewidth), **kwargs))
|
||||
else:
|
||||
fig.add_trace(
|
||||
go.Scatter(x=xx, y=pf[:, branch], mode='lines', name=name, legendgroup=name, showlegend=False,
|
||||
line=dict(color=linecolor, width=linewidth), **kwargs), row=ply_row, col=ply_col)
|
||||
fig.add_scatter(x=xx, y=pf[:, branch], mode='lines', name=name, legendgroup=name, showlegend=False,
|
||||
line=dict(color=linecolor, width=linewidth), **kwargs, row=ply_row, col=ply_col)
|
||||
first_xx = xx[-1]
|
||||
|
||||
if showlengend:
|
||||
if showlegend:
|
||||
fig.data[-1].showlegend = True
|
||||
|
||||
@add_fig_kwargs
|
||||
|
@ -1277,7 +1270,7 @@ See also <https://forum.abinit.org/viewtopic.php?f=10&t=545>
|
|||
use_becs=True, colormap="jet", fontsize=12, **kwargs):
|
||||
r"""
|
||||
Plot the phonon band structure with colored lines. The color of the lines indicates
|
||||
the degree to which the mode is longitudinal:
|
||||
the degree to which the mode is longitudinal.
|
||||
Red corresponds to longitudinal modes and black to purely transverse modes.
|
||||
|
||||
Args:
|
||||
|
@ -1787,7 +1780,7 @@ See also <https://forum.abinit.org/viewtopic.php?f=10&t=545>
|
|||
else:
|
||||
rcd_phdos = PlotlyRowColDesc(0, 1, 1, 2)
|
||||
|
||||
phdos.plotly_dos_idos(fig, rcd=rcd_phdos, what="d", units=units, exchange_xy=True, **kwargs)
|
||||
phdos.plotly_dos_idos(fig, rcd=rcd_phdos, what="d", units=units, exchange_xy=True, showlegend=False, **kwargs)
|
||||
|
||||
return fig
|
||||
|
||||
|
@ -2806,12 +2799,18 @@ class PhbstFile(AbinitNcFile, Has_Structure, Has_PhononBands, NotebookWriter):
|
|||
"""
|
||||
return self.yield_phbands_figs(**kwargs)
|
||||
|
||||
def plotly_expose(self, chart_studio=False, verbose=0, **kwargs):
|
||||
def yield_plotly_figs(self, **kwargs): # pragma: no cover
|
||||
"""
|
||||
This function *generates* a predefined list of plotly figures with minimal input from the user.
|
||||
"""
|
||||
renderer = "chart_studio" if chart_studio else None
|
||||
self.phbands.plotly(renderer=renderer)
|
||||
return self.yield_phbands_plotly_figs(**kwargs)
|
||||
|
||||
#def plotly_expose(self, chart_studio=False, verbose=0, **kwargs):
|
||||
# """
|
||||
# This function *generates* a predefined list of plotly figures with minimal input from the user.
|
||||
# """
|
||||
# renderer = "chart_studio" if chart_studio else None
|
||||
# self.phbands.plotly(renderer=renderer)
|
||||
|
||||
def write_notebook(self, nbpath=None):
|
||||
"""
|
||||
|
@ -2967,7 +2966,7 @@ class PhononDos(Function1D):
|
|||
units: Units for phonon plots. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz").
|
||||
Case-insensitive.
|
||||
rcd: PlotlyRowColDesc object used when fig is not None to specify the (row, col) of the subplot in the grid.
|
||||
kwargs: Options passed to plotly.graph_objects Scatter method.
|
||||
kwargs: Passed to fig.add_scatter method.
|
||||
"""
|
||||
opts = [c.lower() for c in what]
|
||||
|
||||
|
@ -3194,7 +3193,7 @@ class PhononDos(Function1D):
|
|||
ax.set_ylabel(_THERMO_YLABELS[qname][units], fontsize=fontsize)
|
||||
#ax.legend(loc="best", fontsize=fontsize, shadow=True)
|
||||
|
||||
if irow != nrows:
|
||||
if irow != nrows-1:
|
||||
set_visible(ax, False, "xlabel")
|
||||
|
||||
return fig
|
||||
|
@ -3229,7 +3228,7 @@ class PhononDos(Function1D):
|
|||
ncols = 2
|
||||
nrows = num_plots // ncols + num_plots % ncols
|
||||
|
||||
fig, go = get_figs_plotly(nrows=nrows, ncols=ncols, subplot_titles=quantities, sharex=True, sharey=False)
|
||||
fig, _ = get_figs_plotly(nrows=nrows, ncols=ncols, subplot_titles=quantities, sharex=True, sharey=False)
|
||||
|
||||
for iq, qname in enumerate(quantities):
|
||||
irow, icol = divmod(iq, ncols)
|
||||
|
@ -3238,11 +3237,13 @@ class PhononDos(Function1D):
|
|||
ys = f1d.values
|
||||
if formula_units is not None: ys /= formula_units
|
||||
if units == "Jmol": ys = ys * abu.e_Cb * abu.Avogadro
|
||||
fig.add_trace(go.Scatter(x=f1d.mesh, y=ys, mode="lines", name=qname), row=irow + 1, col=icol + 1)
|
||||
fig.add_scatter(x=f1d.mesh, y=ys, mode="lines", name=qname, row=irow + 1, col=icol + 1)
|
||||
fig.layout.annotations[iq].font.size = fontsize
|
||||
iax = iq + 1
|
||||
fig.layout['yaxis%u' % iax].title = {'text': _PLOTLY_THERMO_YLABELS[qname][units], 'font_size': fontsize}
|
||||
fig.layout['xaxis%u' % iax].title = {'text': 'T (K)', 'font_size': fontsize}
|
||||
|
||||
if irow == nrows-1:
|
||||
fig.layout['xaxis%u' % iax].title = {'text': 'T (K)', 'font_size': fontsize}
|
||||
|
||||
return fig
|
||||
|
||||
|
@ -3445,7 +3446,7 @@ class PhdosFile(AbinitNcFile, Has_Structure, NotebookWriter):
|
|||
def plot_pjdos_type(self, units="eV", stacked=True, colormap="jet", alpha=0.7, exchange_xy=False,
|
||||
ax=None, xlims=None, ylims=None, fontsize=12, **kwargs):
|
||||
"""
|
||||
Plot type-projected phonon DOS.
|
||||
Plot type-projected phonon DOS with matplotlib.
|
||||
|
||||
Args:
|
||||
ax: |matplotlib-Axes| or None if a new figure should be created.
|
||||
|
@ -3508,6 +3509,64 @@ class PhdosFile(AbinitNcFile, Has_Structure, NotebookWriter):
|
|||
|
||||
return fig
|
||||
|
||||
@add_plotly_fig_kwargs
|
||||
def plotly_pjdos_type(self, units="eV", stacked=True, exchange_xy=False,
|
||||
fig=None, xlims=None, ylims=None, fontsize=12, **kwargs):
|
||||
"""
|
||||
Plot type-projected phonon DOS with plotly.
|
||||
|
||||
Args:
|
||||
fig: plotly figure or None if a new figure should be created.
|
||||
stacked: True if DOS partial contributions should be stacked on top of each other.
|
||||
units: Units for phonon plots. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz").
|
||||
Case-insensitive.
|
||||
exchange_xy: True to exchange x-y axis.
|
||||
xlims: Set the data limits for the x-axis. Accept tuple e.g. ``(left, right)``.
|
||||
ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)``.
|
||||
fontsize: legend and title fontsize.
|
||||
|
||||
Returns: |plotly.graph_objects.Figure|
|
||||
"""
|
||||
lw = kwargs.pop("lw", 2)
|
||||
factor = abu.phfactor_ev2units(units)
|
||||
|
||||
fig, _ = get_fig_plotly(fig=fig)
|
||||
|
||||
plotly_set_lims(fig, xlims, "x")
|
||||
plotly_set_lims(fig, ylims, "y")
|
||||
|
||||
xlabel = 'Frequency %s' % abu.phunit_tag(units, unicode=True)
|
||||
ylabel = 'PJDOS %s' % abu.phdos_label_from_units(units, unicode=True)
|
||||
plotly_set_xylabels(fig, xlabel, ylabel, exchange_xy)
|
||||
|
||||
# Type projected DOSes.
|
||||
cumulative = np.zeros(len(self.wmesh))
|
||||
|
||||
for i, (symbol, pjdos) in enumerate(self.pjdos_symbol.items()):
|
||||
x, y = pjdos.mesh * factor, pjdos.values / factor
|
||||
if exchange_xy: x, y = y, x
|
||||
|
||||
if not stacked:
|
||||
fig.add_scatter(x=x, y=y, mode='lines', name=symbol, line=dict(width=lw))
|
||||
else:
|
||||
if not exchange_xy:
|
||||
fig.add_scatter(x=x, y=cumulative + y, mode='lines', name=symbol,
|
||||
line=dict(width=lw), fill='tonextx')
|
||||
cumulative += y
|
||||
else:
|
||||
fig.add_scatter(x=cumulative + x, y=y, mode='lines', name=symbol,
|
||||
line=dict(width=lw), fill='tonexty')
|
||||
cumulative += x
|
||||
|
||||
# Total PHDOS
|
||||
x, y = self.phdos.mesh * factor, self.phdos.values / factor
|
||||
if exchange_xy: x, y = y, x
|
||||
fig.add_scatter(x=x, y=y, mode='lines', line=dict(width=lw, color='black'), name="Total PHDOS")
|
||||
fig.layout.legend.font.size = fontsize
|
||||
fig.layout.title.font.size = fontsize
|
||||
|
||||
return fig
|
||||
|
||||
@add_fig_kwargs
|
||||
def plot_pjdos_cartdirs_type(self, units="eV", stacked=True, colormap="jet", alpha=0.7,
|
||||
xlims=None, ylims=None, ax_list=None, fontsize=8, **kwargs):
|
||||
|
@ -3665,10 +3724,22 @@ class PhdosFile(AbinitNcFile, Has_Structure, NotebookWriter):
|
|||
yield msqd_dos.plot(units=units, show=False)
|
||||
yield msqd_dos.plot_tensor(show=False)
|
||||
|
||||
def plotly_expose(self, chart_studio=False, units="meV", verbose=0, **kwargs):
|
||||
renderer = "chart_studio" if chart_studio else None
|
||||
#self.phdos.plotly_dos_idos(units=units, renderer=renderer, show=False)
|
||||
self.phdos.plotly(units=units, renderer=renderer, show=True)
|
||||
def yield_plotly_figs(self, **kwargs): # pragma: no cover
|
||||
"""
|
||||
This function *generates* a predefined list of plotly figures with minimal input from the user.
|
||||
Used in abiview.py to get a quick look at the results.
|
||||
"""
|
||||
units = kwargs.get("units", "mev")
|
||||
yield self.phdos.plotly(units=units, show=False)
|
||||
yield self.plotly_pjdos_type(units=units, show=False)
|
||||
# Old formats do not have MSQDOS arrays.
|
||||
#try:
|
||||
# msqd_dos = self.msqd_dos
|
||||
#except Exception:
|
||||
# msqd_dos = None
|
||||
#if msqd_dos is not None:
|
||||
# yield msqd_dos.plot(units=units, show=False)
|
||||
# yield msqd_dos.plot_tensor(show=False)
|
||||
|
||||
def write_notebook(self, nbpath=None):
|
||||
"""
|
||||
|
@ -3881,7 +3952,7 @@ class PhononBandsPlotter(NotebookWriter):
|
|||
for i, (label, phbands) in enumerate(self.phbands_dict.items()):
|
||||
app("[%d] %s --> %s" % (i, label, func(phbands)))
|
||||
|
||||
if self.phdoses_dict:
|
||||
if self.phdoses_dict and verbose:
|
||||
for i, (label, phdos) in enumerate(self.phdoses_dict.items()):
|
||||
app("[%d] %s --> %s" % (i, label, func(phdos)))
|
||||
|
||||
|
@ -4055,8 +4126,7 @@ class PhononBandsPlotter(NotebookWriter):
|
|||
Case-insensitive.
|
||||
qlabels: dictionary whose keys are tuples with the reduced coordinates of the k-points.
|
||||
The values are the labels e.g. ``klabels = {(0.0,0.0,0.0): "$\Gamma$", (0.5,0,0): "L"}``.
|
||||
ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)``
|
||||
or scalar e.g. ``left``. If left (right) is None, default values are used
|
||||
ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)``.
|
||||
width_ratios: Ratio between the width of the phonon bands plots and the DOS plots.
|
||||
Used if plotter has DOSes.
|
||||
fontsize: fontsize for titles and legend.
|
||||
|
@ -4066,24 +4136,13 @@ class PhononBandsPlotter(NotebookWriter):
|
|||
"""
|
||||
if self.phdoses_dict:
|
||||
nrows, ncols = (1, 2)
|
||||
fig, go = get_figs_plotly(nrows=nrows, ncols=ncols, subplot_titles=[], sharex=False, sharey=True,
|
||||
fig, _ = get_figs_plotly(nrows=nrows, ncols=ncols, subplot_titles=[], sharex=False, sharey=True,
|
||||
horizontal_spacing=0.03, column_widths=width_ratios)
|
||||
else:
|
||||
nrows, ncols = (1, 1)
|
||||
fig, go = get_fig_plotly()
|
||||
fig, _ = get_fig_plotly()
|
||||
|
||||
if ylims is not None:
|
||||
try:
|
||||
len_lims = len(ylims)
|
||||
except TypeError:
|
||||
# Assume Scalar
|
||||
raise NotImplementedError()
|
||||
|
||||
if len_lims is not None:
|
||||
if len(ylims) == 2:
|
||||
fig.layout.yaxis.range = ylims
|
||||
elif len(ylims) == 1:
|
||||
raise NotImplementedError()
|
||||
plotly_set_lims(fig, ylims, 'y')
|
||||
|
||||
# Plot phonon bands.
|
||||
my_kwargs, opts_label = kwargs.copy(), {}
|
||||
|
@ -4104,7 +4163,7 @@ class PhononBandsPlotter(NotebookWriter):
|
|||
if os.path.isfile(label): label = os.path.relpath(label)
|
||||
|
||||
rcd = PlotlyRowColDesc(0, 0, nrows, ncols)
|
||||
phbands.plotly_traces(fig, branch=None, rcd=rcd, units=units, name=label, showlengend=True, **my_kwargs)
|
||||
phbands.plotly_traces(fig, branch=None, rcd=rcd, units=units, name=label, showlegend=True, **my_kwargs)
|
||||
|
||||
# Set ticks and labels, legends.
|
||||
if i == 0:
|
||||
|
@ -4177,7 +4236,7 @@ class PhononBandsPlotter(NotebookWriter):
|
|||
with_dos: True to plot phonon DOS (if available).
|
||||
fontsize: legend and title fontsize.
|
||||
|
||||
Returns: |matplotlib-Figure|
|
||||
Returns: |plotly.graph_objects.Figure|
|
||||
"""
|
||||
titles = list(self._bands_dict.keys())
|
||||
phb_objects = list(self._bands_dict.values())
|
||||
|
@ -4198,15 +4257,16 @@ class PhononBandsPlotter(NotebookWriter):
|
|||
raise NotImplementedError("")
|
||||
for i, (phbands, phdos) in enumerate(zip(phb_objects, phdos_objects)):
|
||||
row, col = divmod(i, ncols)
|
||||
#rcd_phdos = PlotlyRowColDesc(row, col, nrows, ncols)
|
||||
#rcd_phbands = PlotlyRowColDesc(row, col, nrows, ncols)
|
||||
phbands.plotly_with_phdos(phdos, fig=fig, rcd_phbands=None, rcd_phdos=None,
|
||||
rcd_phdos = PlotlyRowColDesc(row, col, nrows, ncols)
|
||||
rcd_phbands = PlotlyRowColDesc(row, col, nrows, ncols)
|
||||
phbands.plotly_with_phdos(phdos, fig=fig, rcd_phbands=rcd_phbands, rcd_phdos=rcd_phdos,
|
||||
units=units, fontsize=fontsize,
|
||||
width_ratios=(2, 1), show=False)
|
||||
else:
|
||||
for i, phbands in enumerate(phb_objects):
|
||||
row, col = divmod(i, ncols)
|
||||
rcd = PlotlyRowColDesc(row, col, nrows, ncols)
|
||||
phbands.plotly(fig=fig, rcd=rcd, show=False)
|
||||
phbands.plotly(fig=fig, rcd=rcd, units=units, fontsize=fontsize, show=False)
|
||||
|
||||
return fig
|
||||
|
||||
|
@ -4644,16 +4704,15 @@ class PhononDosPlotter(NotebookWriter):
|
|||
fig: plotly figure or None if a new figure should be created.
|
||||
units: Units for phonon plots. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz").
|
||||
Case-insensitive.
|
||||
xlims: Set the data limits for the x-axis. Accept tuple e.g. `(left, right)`
|
||||
or scalar e.g. `left`. If left (right) is None, default values are used
|
||||
ylims: y-axis limits.
|
||||
xlims: Set the data limits for the x-axis. Accept tuple e.g. ``(left, right)``.
|
||||
ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)``.
|
||||
fontsize: Legend and title fontsize.
|
||||
|
||||
Returns: |plotly.graph_objects.Figure|
|
||||
"""
|
||||
fig, _ = get_fig_plotly(fig=fig)
|
||||
#set_axlims(ax, xlims, "x")
|
||||
#set_axlims(ax, ylims, "y")
|
||||
plotly_set_lims(fig, xlims, "x")
|
||||
plotly_set_lims(fig, ylims, "y")
|
||||
|
||||
fig.layout['xaxis1'].title = {'text': 'Energy %s' % abu.phunit_tag(units, unicode=True)}
|
||||
fig.layout['yaxis1'].title = {"text": 'DOS %s' % abu.phdos_label_from_units(units, unicode=True)}
|
||||
|
|
|
@ -9,7 +9,8 @@ from abipy.core.mixins import Has_Structure, NotebookWriter
|
|||
from abipy.dfpt.ddb import DdbFile
|
||||
from abipy.dfpt.phonons import PhononBands, get_dyn_mat_eigenvec, match_eigenvectors
|
||||
from abipy.abio.inputs import AnaddbInput
|
||||
from abipy.tools.plotting import add_fig_kwargs, get_ax_fig_plt, set_visible
|
||||
from abipy.tools.plotting import add_fig_kwargs, get_ax_fig_plt, set_visible, get_fig_plotly, get_figs_plotly, \
|
||||
add_plotly_fig_kwargs, plotlyfigs_to_browser, push_to_chart_studio, PlotlyRowColDesc
|
||||
from pymatgen.core.units import bohr_to_angstrom, eV_to_Ha
|
||||
|
||||
|
||||
|
@ -284,14 +285,14 @@ class SoundVelocity(Has_Structure, NotebookWriter):
|
|||
@add_fig_kwargs
|
||||
def plot_fit_freqs_dir(self, idir, ax=None, units="eV", fontsize=8, **kwargs):
|
||||
"""
|
||||
Plots the phonon frequencies, if available, along the specified direction.
|
||||
Plots the phonon frequencies with matplotlib, if available, along the specified direction.
|
||||
The line representing the fitted value will be shown as well.
|
||||
|
||||
Args:
|
||||
idir: index of the direction.
|
||||
ax: |matplotlib-Axes| or None if a new figure should be created.
|
||||
units: Units for phonon plots. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz"). Case-insensitive.
|
||||
fontsize: fontsize for legends and titles
|
||||
fontsize: fontsize for subtitles
|
||||
|
||||
Returns: |matplotlib-Figure|
|
||||
"""
|
||||
|
@ -323,16 +324,74 @@ class SoundVelocity(Has_Structure, NotebookWriter):
|
|||
|
||||
return fig
|
||||
|
||||
@add_plotly_fig_kwargs
|
||||
def plotly_fit_freqs_dir(self, idir, fig=None, rcd=None, units="eV", fontsize=12, **kwargs):
|
||||
"""
|
||||
Plots the phonon frequencies with plotly, if available, along the specified direction.
|
||||
The line representing the fitted value will be shown as well.
|
||||
|
||||
Args:
|
||||
idir: index of the direction.
|
||||
fig: |plotly.graph_objects.Figure|
|
||||
rcd: PlotlyRowColDesc object used to specify the (row, col) of the subplot in the grid.
|
||||
units: Units for phonon plots. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz"). Case-insensitive.
|
||||
fontsize: fontsize for subtitles
|
||||
|
||||
Returns: |plotly.graph_objects.Figure|
|
||||
"""
|
||||
if self.phfreqs is None or self.qpts is None:
|
||||
raise ValueError("The plot requires phonon frequencies and qpoints.")
|
||||
|
||||
title = "[{:.3f}, {:.3f}, {:.3f}]".format(*self.directions[idir])
|
||||
if self.labels:
|
||||
title += " - {}".format(self.labels[idir])
|
||||
|
||||
rcd = PlotlyRowColDesc.from_object(rcd)
|
||||
ply_row, ply_col = rcd.ply_row, rcd.ply_col
|
||||
xaxis = 'xaxis%u' % rcd.iax
|
||||
yaxis = 'yaxis%u' % rcd.iax
|
||||
|
||||
if fig is None:
|
||||
fig, _ = get_fig_plotly()
|
||||
fig.layout=dict(annotations=[dict(text=title, font_size=fontsize, x=0.5, xref='paper', xanchor='center',
|
||||
y=1, yref='paper', yanchor='bottom' ,showarrow=False)],
|
||||
yaxis_title_text=abu.wlabel_from_units(units, unicode=True),
|
||||
xaxis_title_text= "Wave Vector")
|
||||
else:
|
||||
fig.layout.annotations[idir].text = title
|
||||
fig.layout.annotations[idir].font.size = fontsize
|
||||
if idir == self.n_directions - 1:
|
||||
fig.layout[xaxis].title.text = "Wave Vector"
|
||||
if idir == 0:
|
||||
fig.layout[yaxis].title.text = abu.wlabel_from_units(units, unicode=True)
|
||||
|
||||
fig.layout[xaxis].rangemode = 'tozero'
|
||||
fig.layout[yaxis].rangemode = 'tozero'
|
||||
|
||||
rlatt = self.structure.lattice.reciprocal_lattice
|
||||
freqs = self.phfreqs[idir]
|
||||
qpt_cart_coords = np.array([np.linalg.norm(rlatt.get_cartesian_coords(c)) for c in self.qpts[idir]])
|
||||
slope = self.sound_velocities[idir] / abu.velocity_at_to_si * bohr_to_angstrom / eV_to_Ha
|
||||
|
||||
units_factor = abu.phfactor_ev2units(units)
|
||||
|
||||
for i, c in enumerate(["red", "blue", "green"]):
|
||||
fig.add_scatter(x=qpt_cart_coords, y=slope[i] * qpt_cart_coords * units_factor, line_color=c,
|
||||
name='', showlegend=False, mode='lines', row=ply_row, col=ply_col)
|
||||
fig.add_scatter(x=qpt_cart_coords, y=freqs[i] * units_factor, marker=dict(symbol=4, size=8, color=c),
|
||||
name='', showlegend=False, mode='markers', row=ply_row, col=ply_col)
|
||||
|
||||
return fig
|
||||
|
||||
@add_fig_kwargs
|
||||
def plot(self, units="eV", fontsize=8, **kwargs):
|
||||
"""
|
||||
Plots the phonon frequencies, if available, along all the directions.
|
||||
Plots the phonon frequencies with matplotlib, if available, along all the directions.
|
||||
The lines representing the fitted values will be shown as well.
|
||||
|
||||
Args:
|
||||
ax: |matplotlib-Axes| or None if a new figure should be created.
|
||||
units: Units for phonon plots. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz"). Case-insensitive.
|
||||
fontsize: fontsize for legends and titles
|
||||
fontsize: fontsize for subtitles
|
||||
|
||||
Returns: |matplotlib-Figure|
|
||||
"""
|
||||
|
@ -352,6 +411,29 @@ class SoundVelocity(Has_Structure, NotebookWriter):
|
|||
|
||||
return fig
|
||||
|
||||
@add_plotly_fig_kwargs
|
||||
def plotly(self, units="eV", fontsize=12, **kwargs):
|
||||
"""
|
||||
Plots the phonon frequencies with plotly, if available, along all the directions.
|
||||
The lines representing the fitted values will be shown as well.
|
||||
|
||||
Args:
|
||||
units: Units for phonon plots. Possible values in ("eV", "meV", "Ha", "cm-1", "Thz"). Case-insensitive.
|
||||
fontsize: fontsize for subtitles
|
||||
|
||||
Returns: |plotly.graph_objects.Figure|
|
||||
"""
|
||||
|
||||
nrows, ncols = math.ceil(self.n_directions / 2), 2
|
||||
fig, _ = get_figs_plotly(nrows=nrows, ncols=ncols, subplot_titles=list(range(1, self.n_directions+1)),
|
||||
horizontal_spacing=0.05)
|
||||
|
||||
for i in range(self.n_directions):
|
||||
rcd = PlotlyRowColDesc(i//2, i%2, nrows, ncols)
|
||||
self.plotly_fit_freqs_dir(i, fig, rcd, units=units, fontsize=fontsize, show=False)
|
||||
|
||||
return fig
|
||||
|
||||
def yield_figs(self, **kwargs): # pragma: no cover
|
||||
"""
|
||||
This function *generates* a predefined list of matplotlib figures with minimal input from the user.
|
||||
|
|
|
@ -29,7 +29,6 @@ class HistFile(AbinitNcFile, NotebookWriter):
|
|||
with HistFile("foo_HIST") as hist:
|
||||
hist.plot()
|
||||
|
||||
|
||||
.. rubric:: Inheritance Diagram
|
||||
.. inheritance-diagram:: HistFile
|
||||
"""
|
||||
|
@ -196,6 +195,7 @@ class HistFile(AbinitNcFile, NotebookWriter):
|
|||
"""
|
||||
if filepath is not None and os.path.exists(filepath) and not overwrite:
|
||||
raise RuntimeError("Cannot overwrite pre-existing file `%s`" % filepath)
|
||||
|
||||
if filepath is None:
|
||||
import tempfile
|
||||
fd, filepath = tempfile.mkstemp(text=True, suffix="_XDATCAR")
|
||||
|
@ -400,7 +400,6 @@ class HistFile(AbinitNcFile, NotebookWriter):
|
|||
ax_list, fig, plt = get_axarray_fig_plt(ax_list, nrows=nrows, ncols=ncols,
|
||||
sharex=True, sharey=False, squeeze=False)
|
||||
ax_list = ax_list.ravel()
|
||||
assert len(ax_list) == len(what_list)
|
||||
|
||||
# don't show the last ax if nplots is odd.
|
||||
if nplots % ncols != 0: ax_list[-1].axis("off")
|
||||
|
@ -443,6 +442,14 @@ class HistFile(AbinitNcFile, NotebookWriter):
|
|||
yield self.plot(show=False)
|
||||
yield self.plot_energies(show=False)
|
||||
|
||||
#def yield_plotly_figs(self, **kwargs): # pragma: no cover
|
||||
# """
|
||||
# This function *generates* a predefined list of matplotlib figures with minimal input from the user.
|
||||
# """
|
||||
# yield self.plotly(show=False)
|
||||
# yield self.plotly_energies(show=False)
|
||||
|
||||
|
||||
def mvplot_trajectories(self, colormap="hot", sampling=1, figure=None, show=True,
|
||||
with_forces=True, **kwargs): # pragma: no cover
|
||||
"""
|
||||
|
@ -515,10 +522,12 @@ class HistFile(AbinitNcFile, NotebookWriter):
|
|||
|
||||
anim()
|
||||
|
||||
def get_panel(self):
|
||||
"""Build panel with widgets to interact with the |HistFile| either in a notebook or in panel app."""
|
||||
def get_panel(self, **kwargs):
|
||||
"""
|
||||
Build panel with widgets to interact with the |HistFile| either in a notebook or in panel app.
|
||||
"""
|
||||
from abipy.panels.hist import HistFilePanel
|
||||
return HistFilePanel(self).get_panel()
|
||||
return HistFilePanel(self).get_panel(**kwargs)
|
||||
|
||||
def write_notebook(self, nbpath=None):
|
||||
"""
|
||||
|
|
|
@ -30,7 +30,22 @@ from abipy.iotools import ETSF_Reader
|
|||
from abipy.tools import duck
|
||||
from abipy.tools.numtools import gaussian
|
||||
from abipy.tools.plotting import (set_axlims, add_fig_kwargs, get_ax_fig_plt, get_axarray_fig_plt,
|
||||
get_ax3d_fig_plt, rotate_ticklabels, set_visible, plot_unit_cell, set_ax_xylabels)
|
||||
get_ax3d_fig_plt, rotate_ticklabels, set_visible, plot_unit_cell, set_ax_xylabels, get_figs_plotly,
|
||||
get_fig_plotly, add_plotly_fig_kwargs, PlotlyRowColDesc, plotly_klabels, plotly_set_lims)
|
||||
|
||||
|
||||
SUBSCRIPT_UNICODE = {
|
||||
"0": "₀",
|
||||
"1": "₁",
|
||||
"2": "₂",
|
||||
"3": "₃",
|
||||
"4": "₄",
|
||||
"5": "₅",
|
||||
"6": "₆",
|
||||
"7": "₇",
|
||||
"8": "₈",
|
||||
"9": "₉",
|
||||
}
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
@ -328,6 +343,18 @@ class ElectronBands(Has_Structure):
|
|||
assert new.__class__ == cls
|
||||
return new
|
||||
|
||||
@classmethod
|
||||
def from_binary_string(cls, bstring):
|
||||
"""
|
||||
Build object from a binary string with the netcdf data.
|
||||
Useful for implementing GUIs in which widgets returns binary data.
|
||||
"""
|
||||
workdir = tempfile.mkdtemp()
|
||||
fd, tmp_path = tempfile.mkstemp(suffix=".nc")
|
||||
with open(tmp_path, "wb") as fh:
|
||||
fh.write(bstring)
|
||||
return cls.from_file(tmp_path)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d):
|
||||
"""Reconstruct object from the dictionary in MSONable format produced by as_dict."""
|
||||
|
@ -569,6 +596,16 @@ class ElectronBands(Has_Structure):
|
|||
|
||||
__radd__ = __add__
|
||||
|
||||
def get_plotter_with(self, self_key, other_key, other_ebands):
|
||||
"""
|
||||
Build and |ElectronBandsPlotter| from self and other, use self_key and other_key as keywords
|
||||
"""
|
||||
plotter = ElectronBandsPlotter()
|
||||
plotter.add_ebands(self_key, self)
|
||||
plotter.add_ebands(other_key, other_ebands)
|
||||
|
||||
return plotter
|
||||
|
||||
# Handy variables used to loop
|
||||
@property
|
||||
def spins(self):
|
||||
|
@ -1355,29 +1392,39 @@ class ElectronBands(Has_Structure):
|
|||
|
||||
return dirgaps
|
||||
|
||||
def get_gaps_string(self, with_latex=True):
|
||||
def get_gaps_string(self, with_latex=True, unicode=False):
|
||||
"""
|
||||
Return string with info about fundamental and direct gap (if not metallic scheme)
|
||||
|
||||
Args:
|
||||
with_latex: True to get latex symbols for the gap names else text.
|
||||
with_latex: True to get latex symbols for the gap names and formula else text.
|
||||
unicode: True to get unicode symbols for the formula else text.
|
||||
"""
|
||||
enough_bands = (self.mband > self.nspinor * self.nelect // 2)
|
||||
dg_name, fg_name = "direct gap", "fundamental gap"
|
||||
if with_latex:
|
||||
dg_name, fg_name = "$E^{dir}_{gap}$", "$E^{fund}_{gap}$"
|
||||
formula = self.structure.latex_formula
|
||||
else:
|
||||
dg_name, fg_name = "direct gap", "fundamental gap"
|
||||
formula = self.structure.formula
|
||||
|
||||
if unicode:
|
||||
import re
|
||||
numl=re.findall(r'\d', formula)
|
||||
for s in numl:
|
||||
formula = formula.replace(s,SUBSCRIPT_UNICODE[s])
|
||||
|
||||
if enough_bands and not self.has_metallic_scheme:
|
||||
if self.nsppol == 1:
|
||||
s = "%s: %s = %.2f, %s = %.2f (eV)" % (
|
||||
self.structure.latex_formula,
|
||||
formula,
|
||||
dg_name, self.direct_gaps[0].energy,
|
||||
fg_name, self.fundamental_gaps[0].energy)
|
||||
else:
|
||||
dgs = [t.energy for t in self.direct_gaps]
|
||||
fgs = [t.energy for t in self.fundamental_gaps]
|
||||
s = "%s: %s = %.2f (%.2f), %s = %.2f (%.2f) (eV)" % (
|
||||
self.structure.latex_formula,
|
||||
formula,
|
||||
dg_name, dgs[0], dgs[1],
|
||||
fg_name, fgs[0], fgs[1])
|
||||
else:
|
||||
|
@ -1412,7 +1459,11 @@ class ElectronBands(Has_Structure):
|
|||
k0_list.append(k)
|
||||
effmass_bands_f90.append(v)
|
||||
|
||||
|
||||
# Set small values to zero.
|
||||
k0_list = np.reshape(k0_list, (-1, 3))
|
||||
k0_list = np.where(np.abs(k0_list) > 1e-12, k0_list, 0.0)
|
||||
|
||||
effmass_bands_f90 = np.reshape(effmass_bands_f90, (-1, 2))
|
||||
#print("k0_list:\n", k0_list, "\neffmass_bands_f90:\n", effmass_bands_f90)
|
||||
|
||||
|
@ -2001,6 +2052,145 @@ class ElectronBands(Has_Structure):
|
|||
|
||||
return fig
|
||||
|
||||
@add_plotly_fig_kwargs
|
||||
def plotly(self, spin=None, band_range=None, klabels=None, e0="fermie", fig=None, ylims=None,
|
||||
points=None, with_gaps=False, max_phfreq=None, fontsize=12, **kwargs):
|
||||
r"""
|
||||
Plot the electronic band structure with plotly.
|
||||
|
||||
Args:
|
||||
spin: Spin index. None to plot both spins.
|
||||
band_range: Tuple specifying the minimum and maximum band to plot (default: all bands are plotted)
|
||||
klabels: dictionary whose keys are tuple with the reduced
|
||||
coordinates of the k-points. The values are the labels. e.g.
|
||||
``klabels = {(0.0,0.0,0.0): "$\Gamma$", (0.5,0,0):"L"}``.
|
||||
e0: Option used to define the zero of energy in the band structure plot. Possible values:
|
||||
- ``fermie``: shift all eigenvalues to have zero energy at the Fermi energy (``self.fermie``).
|
||||
- Number e.g e0=0.5: shift all eigenvalues to have zero energy at 0.5 eV
|
||||
- None: Don't shift energies, equivalent to e0=0
|
||||
fig: plotly figure or None if a new figure should be created.
|
||||
ylims: Set the data limits for the y-axis. Accept tuple e.g. ``(left, right)``
|
||||
points: Marker object with the position and the size of the marker.
|
||||
Used for plotting purpose e.g. QP energies, energy derivatives.
|
||||
with_gaps: True to add markers and arrows showing the fundamental and the direct gap.
|
||||
IMPORTANT: If the gaps are now showed correctly in a non-magnetic semiconductor,
|
||||
call `ebands.set_fermie_to_vbm()` to align the Fermi level at the top of the valence
|
||||
bands before executing `ebands.plot().
|
||||
The Fermi energy stored in the object, indeed, comes from the GS calculation
|
||||
that produced the DEN file. If the k-mesh used for the GS and the CBM is e.g. at Gamma,
|
||||
the Fermi energy will be underestimated and a manual aligment is needed.
|
||||
max_phfreq: Max phonon frequency in eV to activate scatterplot showing
|
||||
possible phonon absorption/emission processes based on energy-conservation alone.
|
||||
All final states whose energy is within +- max_phfreq of the initial state are included.
|
||||
By default, the four electronic states defining the fundamental and the direct gaps
|
||||
are considered as initial state (not available for metals).
|
||||
fontsize: fontsize for legends and titles
|
||||
kwargs: Passed to go.Scatter
|
||||
|
||||
Returns: |plotly.graph_objects.Figure|
|
||||
"""
|
||||
# Select spins
|
||||
spin_list = self.spins if spin is None else [spin]
|
||||
|
||||
# Select the band range.
|
||||
if band_range is None:
|
||||
band_list = list(range(self.mband))
|
||||
else:
|
||||
band_list = list(range(band_range[0], band_range[1], 1))
|
||||
|
||||
e0 = self.get_e0(e0)
|
||||
fig, go = get_fig_plotly(fig=fig)
|
||||
|
||||
# Decorate the axis (e.g add ticks and labels).
|
||||
self.decorate_plotly(fig, klabels=klabels)
|
||||
plotly_set_lims(fig, ylims, "y")
|
||||
|
||||
# Plot the band energies.
|
||||
for spin in spin_list:
|
||||
lw = kwargs.pop("lw", 2.0)
|
||||
line_opts = {"color": "black", "width": lw} if spin == 0 else {"color": "red", "width": lw}
|
||||
|
||||
for ib, band in enumerate(band_list):
|
||||
if ib != 0: kwargs.pop("label", None)
|
||||
self.plotly_traces(fig, e0, spin=spin, band=band, line_opts=line_opts, **kwargs)
|
||||
|
||||
if points is not None:
|
||||
fig.add_trace(go.Scatter(x=points.x, y=np.array(points.y) - e0, mode='markers', showlegend=False,
|
||||
marker=dict(color='blue', size=np.abs(points.s), opacity=0.6, line_width=0)))
|
||||
|
||||
if with_gaps and (self.mband > self.nspinor * self.nelect // 2):
|
||||
# Show fundamental and direct gaps for each spin.
|
||||
from plotly.figure_factory import create_quiver
|
||||
for spin in self.spins:
|
||||
f_gap = self.fundamental_gaps[spin]
|
||||
d_gap = self.direct_gaps[spin]
|
||||
# Need arrows only if fundamental and direct gaps for this spin are different.
|
||||
need_arrows = f_gap != d_gap
|
||||
|
||||
arrow_opts = {"color": "gray"} if spin == 0 else {"color": "orange"}
|
||||
scatter_opts = {"color": "blue"} if spin == 0 else {"color": "green"}
|
||||
scatter_opts.update(opacity=0.9, size=12, line_width=2)
|
||||
|
||||
# Fundamental gap.
|
||||
mgap = -1
|
||||
for ik1, ik2 in f_gap.all_kinds:
|
||||
posA = (ik1, f_gap.in_state.eig - e0)
|
||||
posB = (ik2, f_gap.out_state.eig - e0)
|
||||
mgap = max(mgap, posA[1], posB[1])
|
||||
fig.add_trace(go.Scatter(x=[posA[0], posB[0]], y=[posA[1], posB[1]], mode='markers', name='',
|
||||
showlegend=False, marker=scatter_opts))
|
||||
if need_arrows:
|
||||
figcq = create_quiver(x=[posA[0]], y=[posA[1]], u=[posB[0]-posA[0]], v=[posB[1]-posA[1]],
|
||||
name='', scale=1, arrow_scale=0.2, showlegend=False, hoverinfo='none',
|
||||
marker=arrow_opts, line=dict(width=2))
|
||||
fig.add_trace(figcq.data[-1])
|
||||
if d_gap != f_gap:
|
||||
# Direct gap.
|
||||
for ik1, ik2 in d_gap.all_kinds:
|
||||
posA = (ik1, d_gap.in_state.eig - e0)
|
||||
posB = (ik2, d_gap.out_state.eig - e0)
|
||||
mgap = max(mgap, posA[1], posB[1])
|
||||
fig.add_trace(go.Scatter(x=[posA[0],posB[0]], y=[posA[1],posB[1]], mode='markers', name='',
|
||||
showlegend=False, marker=scatter_opts))
|
||||
if need_arrows:
|
||||
figcq = create_quiver(x=[posA[0]], y=[posA[1]], u=[posB[0]-posA[0]], v=[posB[1]-posA[1]],
|
||||
name='', scale=1, arrow_scale=0.2, showlegend=False, hoverinfo='none',
|
||||
marker=arrow_opts, line=dict(width=2))
|
||||
fig.add_trace(figcq.data[-1])
|
||||
|
||||
# Try to set nice limits if not given by user.
|
||||
if ylims is None:
|
||||
plotly_set_lims(fig, (-mgap - 5, +mgap + 5), "y")
|
||||
|
||||
gaps_string = self.get_gaps_string(with_latex=False, unicode=True)
|
||||
if gaps_string:
|
||||
fig.layout.title = dict(text=gaps_string, font=dict(size=fontsize))
|
||||
|
||||
if max_phfreq is not None and (self.mband > self.nspinor * self.nelect // 2):
|
||||
# Add markers showing phonon absorption/emission processes.
|
||||
for spin in self.spins:
|
||||
#scatter_opts = {"color": "steelblue"} if spin == 0 else {"color": "teal"}
|
||||
scatter_opts = dict(opacity=0.4, size=8)
|
||||
items = (["fundamental_gaps", "direct_gaps"], ["in_state", "out_state"])
|
||||
items = list(enumerate(itertools.product(*items)))
|
||||
for i, (gap_name, state_name) in items:
|
||||
# Use getattr to extract gaps, equivalent to:
|
||||
# gap = self.fundamental_gaps[spin]
|
||||
# e_start = gap.out_state.eig
|
||||
gap = getattr(self, gap_name)[spin]
|
||||
e_start = getattr(gap, state_name).eig
|
||||
scatter_opts["color"] = i/len(items)
|
||||
scatter_opts["colorscale"] = "dense" if spin == 0 else "Burgyl"
|
||||
|
||||
for band in range(self.mband):
|
||||
eks = self.eigens[spin, :, band]
|
||||
where = np.where(np.abs(e_start - eks) <= max_phfreq)[0]
|
||||
if not np.any(where): continue
|
||||
fig.add_trace(go.Scatter(x=where, y=eks[where] - e0, mode='markers',
|
||||
marker=scatter_opts, showlegend=False))
|
||||
|
||||
return fig
|
||||
|
||||
@add_fig_kwargs
|
||||
def plot_scatter3d(self, band, spin=0, e0="fermie", colormap="jet", ax=None, **kwargs):
|
||||
r"""
|
||||
|
@ -2013,7 +2203,7 @@ class ElectronBands(Has_Structure):
|
|||
e0: Option used to define the zero of energy in the band structure plot. Possible values:
|
||||
- ``fermie``: shift all eigenvalues to have zero energy at the Fermi energy (``self.fermie``).
|
||||
- Number e.g ``e0 = 0.5``: shift all eigenvalues to have zero energy at 0.5 eV
|
||||
- None: Don't shift energies, equivalent to ``e0 = 0``
|
||||
- None: Don't shift energies, equivalent to ``e0 = 0``.
|
||||
colormap: Have a look at the colormaps here and decide which one you like:
|
||||
<http://matplotlib.sourceforge.net/examples/pylab_examples/show_colormaps.html>
|
||||
ax: matplotlib :class:`Axes3D` or None if a new figure should be created.
|
||||
|
@ -2071,6 +2261,31 @@ class ElectronBands(Has_Structure):
|
|||
#print("ticks", len(ticks), ticks)
|
||||
ax.set_xlim(ticks[0], ticks[-1])
|
||||
|
||||
def decorate_plotly(self, fig, **kwargs):
|
||||
"""
|
||||
Add q-labels and unit name to figure ``fig``.
|
||||
Use units="" to add k-labels without unit name.
|
||||
Args:
|
||||
klabels:
|
||||
klabel_size:
|
||||
iax: An int, use iax=n to decorate the nth axis when the fig has subplots.
|
||||
"""
|
||||
iax = kwargs.pop("iax", 1)
|
||||
xaxis = 'xaxis%u' % iax
|
||||
|
||||
fig.layout[xaxis].title.text = "Wave Vector"
|
||||
fig.layout['yaxis%u' % iax].title.text = "Energy (eV)"
|
||||
|
||||
# Set ticks and labels.
|
||||
klabels = kwargs.pop("klabels", None)
|
||||
ticks, labels = self._make_ticks_and_labels(klabels)
|
||||
if ticks:
|
||||
labels = plotly_klabels(labels)
|
||||
fig.layout[xaxis].tickvals = ticks
|
||||
fig.layout[xaxis].ticktext = labels
|
||||
fig.layout[xaxis].tickfont.size = kwargs.pop("klabel_size", 16)
|
||||
fig.layout[xaxis].range = (ticks[0], ticks[-1])
|
||||
|
||||
def get_e0(self, e0):
|
||||
"""
|
||||
e0: Option used to define the zero of energy in the band structure plot. Possible values:
|
||||
|
@ -2132,6 +2347,50 @@ class ElectronBands(Has_Structure):
|
|||
|
||||
return lines
|
||||
|
||||
def plotly_traces(self, fig, e0, spin=None, band=None, showlegend=False, line_opts=None, **kwargs):
|
||||
"""
|
||||
Helper function to plot the energies for (spin, band) on figure ``fig``.
|
||||
|
||||
Args:
|
||||
fig: |plotly.graph_objects.Figure|.
|
||||
e0: Option used to define the zero of energy in the band structure plot.
|
||||
spin: Spin index. If None, all spins are plotted.
|
||||
band: Band index, If None, all bands are plotted.
|
||||
showlegend: Determines whether or not an item corresponding to this trace is shown in the legend.
|
||||
kwargs: Passed to go.Scatter
|
||||
"""
|
||||
import plotly.graph_objects as go
|
||||
spin_range = range(self.nsppol) if spin is None else [spin]
|
||||
band_range = range(self.mband) if band is None else [band]
|
||||
|
||||
label = kwargs.pop("label", '')
|
||||
# Handle linewidths
|
||||
with_linewidths = kwargs.pop("with_linewidths", True) and self.has_linewidths
|
||||
if with_linewidths:
|
||||
lw_opts = kwargs.pop("lw_opts", dict(opacity=0.6))
|
||||
lw_fact = lw_opts.pop("fact", 2.0)
|
||||
|
||||
xx = np.arange(self.nkpt)
|
||||
e0 = self.get_e0(e0)
|
||||
for spin in spin_range:
|
||||
for band in band_range:
|
||||
yy = self.eigens[spin, :, band] - e0
|
||||
|
||||
# Set label only at the first iteration
|
||||
fig.add_trace(go.Scatter(x=xx, y=yy, mode="lines", name=label, showlegend=showlegend, line=line_opts, **kwargs))
|
||||
label = ''
|
||||
showlegend=False
|
||||
|
||||
if with_linewidths:
|
||||
w = self.linewidths[spin, :, band] * lw_fact / 2
|
||||
lw_color = lines[-1].get_color()
|
||||
raise NotImplementedError
|
||||
# solution 1: Use scater points to fill
|
||||
# solution 2: add two traces and fill the area between
|
||||
# color problem
|
||||
#!! ax.fill_between(xx, yy - w, yy + w, facecolor=lw_color, **lw_opts)
|
||||
#, alpha=self.alpha, facecolor=self.l2color[l])
|
||||
|
||||
def _make_ticks_and_labels(self, klabels):
|
||||
"""Return ticks and labels from the mapping qlabels."""
|
||||
if klabels is not None:
|
||||
|
@ -2481,7 +2740,7 @@ class ElectronBands(Has_Structure):
|
|||
Args:
|
||||
lpratio: Ratio between the number of star functions and the number of ab-initio k-points.
|
||||
The default should be OK in many systems, larger values may be required for accurate derivatives.
|
||||
knames: List of strings with the k-point labels for the k-path. Has precedence over vertices_names.
|
||||
knames: List of strings with the k-point labels for the k-path. Has precedence over ``vertices_names``.
|
||||
vertices_names: Used to specify the k-path for the interpolated band structure
|
||||
It's a list of tuple, each tuple is of the form (kfrac_coords, kname) where
|
||||
kfrac_coords are the reduced coordinates of the k-point and kname is a string with the name of
|
||||
|
@ -2489,6 +2748,7 @@ class ElectronBands(Has_Structure):
|
|||
the density of the sampling. If None, the k-path is automatically generated according
|
||||
to the point group of the system.
|
||||
line_density: Number of points in the smallest segment of the k-path.
|
||||
If 0, use list of k-points given in vertices_names
|
||||
kmesh: Used to activate the interpolation on the homogeneous mesh for DOS (uses spglib_ API).
|
||||
kmesh is given by three integers and specifies mesh numbers along reciprocal primitive axis.
|
||||
is_shift: three integers (spglib_ API). When is_shift is not None, the kmesh is shifted along
|
||||
|
@ -2518,8 +2778,7 @@ class ElectronBands(Has_Structure):
|
|||
|
||||
# Build interpolator.
|
||||
from abipy.core.skw import SkwInterpolator
|
||||
cell = (self.structure.lattice.matrix, self.structure.frac_coords,
|
||||
self.structure.atomic_numbers)
|
||||
cell = (self.structure.lattice.matrix, self.structure.frac_coords, self.structure.atomic_numbers)
|
||||
|
||||
skw = SkwInterpolator(lpratio, self.kpoints.frac_coords, self.eigens[:,:,bstart:bstop], self.fermie, self.nelect,
|
||||
cell, fm_symrel, self.has_timrev,
|
||||
|
@ -2542,7 +2801,7 @@ class ElectronBands(Has_Structure):
|
|||
self.nelect, self.nspinor, self.nspden, smearing=self.smearing)
|
||||
ebands_kmesh = None
|
||||
if kmesh is not None:
|
||||
# Get kpts and weights in IBZ.
|
||||
# Get kpts and weights in the IBZ.
|
||||
kdos = Ktables(self.structure, kmesh, is_shift, self.has_timrev)
|
||||
eigens_kmesh = skw.interp_kpts(kdos.ibz).eigens
|
||||
|
||||
|
@ -2747,6 +3006,13 @@ class ElectronBandsPlotter(NotebookWriter):
|
|||
for mname in ("gridplot", "boxplot"):
|
||||
yield getattr(self, mname)(show=False)
|
||||
|
||||
#def yield_plotly_figs(self, **kwargs): # pragma: no cover
|
||||
# """
|
||||
# This function *generates* a predefined list of matplotlib figures with minimal input from the user.
|
||||
# """
|
||||
# for mname in ("gridplot", "boxplot"):
|
||||
# yield getattr(self, mname)(show=False)
|
||||
|
||||
@add_fig_kwargs
|
||||
def combiplot(self, e0="fermie", ylims=None, width_ratios=(2, 1), fontsize=8,
|
||||
linestyle_dict=None, **kwargs):
|
||||
|
@ -2756,7 +3022,6 @@ class ElectronBandsPlotter(NotebookWriter):
|
|||
|
||||
Args:
|
||||
e0: Option used to define the zero of energy in the band structure plot. Possible values::
|
||||
|
||||
- `fermie`: shift all eigenvalues to have zero energy at the Fermi energy (ebands.fermie)
|
||||
Note that, by default, the Fermi energy is taken from the band structure object
|
||||
i.e. the Fermi energy computed at the end of the SCF file that produced the density.
|
||||
|
@ -2767,7 +3032,6 @@ class ElectronBandsPlotter(NotebookWriter):
|
|||
Available only if plotter contains dos objects.
|
||||
- Number e.g e0=0.5: shift all eigenvalues to have zero energy at 0.5 eV
|
||||
- None: Don't shift energies, equivalent to e0=0
|
||||
|
||||
ylims: Set the data limits for the y-axis. Accept tuple e.g. `(left, right)`
|
||||
or scalar e.g. `left`. If left (right) is None, default values are used
|
||||
width_ratios: Defines the ratio between the band structure plot and the dos plot.
|
||||
|
@ -2842,11 +3106,8 @@ class ElectronBandsPlotter(NotebookWriter):
|
|||
|
||||
return fig
|
||||
|
||||
def plot(self, *args, **kwargs):
|
||||
"""An alias for combiplot."""
|
||||
if "align" in kwargs or "xlim" in kwargs or "ylim" in kwargs:
|
||||
raise ValueError("align|xlim|ylim options are not supported anymore.")
|
||||
return self.combiplot(*args, **kwargs)
|
||||
# An alias for combiplot.
|
||||
plot = combiplot
|
||||
|
||||
@add_fig_kwargs
|
||||
def gridplot(self, e0="fermie", with_dos=True, with_gaps=False, max_phfreq=None,
|
||||
|
|
|
@ -231,19 +231,26 @@ class GsrFile(AbinitNcFile, Has_Header, Has_Structure, Has_ElectronBands, Notebo
|
|||
return ComputedEntry(self.structure.composition, self.energy,
|
||||
parameters=parameters, data=data)
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, **kwargs):
|
||||
"""
|
||||
Build panel with widgets to interact with the |GsrFile| either in a notebook or in panel app.
|
||||
"""
|
||||
from abipy.panels.gsr import GsrFilePanel
|
||||
return GsrFilePanel(self).get_panel()
|
||||
return GsrFilePanel(self).get_panel(**kwargs)
|
||||
|
||||
def yield_figs(self, **kwargs): # pragma: no cover
|
||||
"""
|
||||
This function *generates* a predefined list of matplotlib figures with minimal input from the user.
|
||||
"""
|
||||
for fig in self.yield_structure_figs(**kwargs): yield fig
|
||||
for fig in self.yield_ebands_figs(**kwargs): yield fig
|
||||
for fig in self.yield_structure_figs(**kwargs): yield fig
|
||||
|
||||
def yield_plotly_figs(self, **kwargs): # pragma: no cover
|
||||
"""
|
||||
This function *generates* a predefined list of plotly figures with minimal input from the user.
|
||||
"""
|
||||
for fig in self.yield_ebands_plotly_figs(**kwargs): yield fig
|
||||
for fig in self.yield_structure_plotly_figs(**kwargs): yield fig
|
||||
|
||||
def write_notebook(self, nbpath=None):
|
||||
"""
|
||||
|
@ -251,10 +258,21 @@ class GsrFile(AbinitNcFile, Has_Header, Has_Structure, Has_ElectronBands, Notebo
|
|||
working directory is created. Return path to the notebook.
|
||||
"""
|
||||
nbformat, nbv, nb = self.get_nbformat_nbv_nb(title=None)
|
||||
first_char = "" if self.has_panel() else "#"
|
||||
|
||||
nb.cells.extend([
|
||||
nbv.new_code_cell("gsr = abilab.abiopen('%s')" % self.filepath),
|
||||
nbv.new_code_cell("print(gsr)"),
|
||||
|
||||
# Add panel GUI but comment the python code if panel is not available.
|
||||
nbv.new_markdown_cell("## Panel dashboard"),
|
||||
nbv.new_code_cell(f"""\
|
||||
# Execute this cell to display the panel GUI (requires panel package).
|
||||
# To display the dashboard inside the browser use `abiopen.py FILE --panel`.
|
||||
|
||||
{first_char}abilab.abipanel()
|
||||
{first_char}gsr.get_panel()
|
||||
"""),
|
||||
nbv.new_code_cell("gsr.ebands.plot();"),
|
||||
nbv.new_code_cell("gsr.ebands.kpoints.plot();"),
|
||||
nbv.new_code_cell("# gsr.ebands.plot_transitions(omega_ev=3.0, qpt=(0, 0, 0), atol_ev=0.1);"),
|
||||
|
@ -505,7 +523,7 @@ class GsrRobot(Robot, RobotWithEbands):
|
|||
|
||||
def get_energyterms_dataframe(self, iref=None):
|
||||
"""
|
||||
Build and return with the different contributions to the total energy in eV
|
||||
Build and return dataframe with the different contributions to the total energy in eV
|
||||
|
||||
Args:
|
||||
iref: Index of the abifile used as reference: the energies of the
|
||||
|
@ -584,7 +602,7 @@ class GsrRobot(Robot, RobotWithEbands):
|
|||
|
||||
Returns: |matplotlib-Figure|
|
||||
|
||||
Example:
|
||||
Example::
|
||||
|
||||
robot.plot_gsr_convergence(sortby="nkpt", hue="tsmear")
|
||||
"""
|
||||
|
@ -606,12 +624,12 @@ class GsrRobot(Robot, RobotWithEbands):
|
|||
yield self.plot_gsr_convergence(show=False)
|
||||
for fig in self.get_ebands_plotter().yield_figs(): yield fig
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, **kwargs):
|
||||
"""
|
||||
Build panel with widgets to interact with the |GsrRobot| either in a notebook or in panel app.
|
||||
"""
|
||||
from abipy.panels.gsr import GsrRobotPanel
|
||||
return GsrRobotPanel(self).get_panel()
|
||||
return GsrRobotPanel(self).get_panel(**kwargs)
|
||||
|
||||
def write_notebook(self, nbpath=None):
|
||||
"""
|
||||
|
|
|
@ -1556,9 +1556,6 @@ class SigresReader(ETSF_Reader):
|
|||
|
||||
# Self-consistent case
|
||||
self._en_qp_diago = self.read_value("en_qp_diago")
|
||||
# <KS|QPState>
|
||||
self._eigvec_qp = self.read_value("eigvec_qp", cmode="c")
|
||||
|
||||
#self._mlda_to_qp
|
||||
|
||||
#def is_selfconsistent(self, mode):
|
||||
|
@ -1717,10 +1714,13 @@ class SigresReader(ETSF_Reader):
|
|||
If band is None, <KS_b|QP_{b'}> is returned.
|
||||
"""
|
||||
ik = self.kpt2fileindex(kpoint)
|
||||
# <KS|QPState>
|
||||
# TODO
|
||||
eigvec_qp = self.read_value("eigvec_qp", cmode="c")
|
||||
if band is not None:
|
||||
return self._eigvec_qp[spin, ik, :, band]
|
||||
return eigvec_qp[spin, ik, :, band]
|
||||
else:
|
||||
return self._eigvec_qp[spin, ik, :, :]
|
||||
return eigvec_qp[spin, ik, :, :]
|
||||
|
||||
def read_params(self):
|
||||
"""
|
||||
|
@ -1877,6 +1877,79 @@ class SigresRobot(Robot, RobotWithEbands):
|
|||
row_names = row_names if not abspath else self._to_relpaths(row_names)
|
||||
return pd.DataFrame(rows, index=row_names, columns=list(rows[0].keys()))
|
||||
|
||||
def get_fit_gaps_vs_ecuteps(self, spin, kpoint, plot_qpmks=True, slice_data=None, fontsize=12):
|
||||
"""
|
||||
Fit QP direct gaps as a function of ecuteps using Eq. 16 of http://dx.doi.org/10.1063/1.4900447
|
||||
to extrapolate results for ecutsp --> +oo.
|
||||
|
||||
Args:
|
||||
spin: Spin index (0 or 1)
|
||||
kpoint: K-point in self-energy. Accepts |Kpoint|, vector or index.
|
||||
plot_qpmks: If False, plot QP_gap, KS_gap else (QP_gap - KS_gap)
|
||||
slice_data: Python slice object. Used to downsample data points.
|
||||
None to use all files of the SigResRobot.
|
||||
fontsize: legend and label fontsize.
|
||||
|
||||
Return: TODO
|
||||
"""
|
||||
# Make sure that nsppol, sigma_kpoints are consistent.
|
||||
self._check_dims_and_params()
|
||||
|
||||
# Get dimensions and index of the k-point in the sigma_nk array.
|
||||
nc0 = self.abifiles[0]
|
||||
nsppol, sigma_kpoints = nc0.nsppol, nc0.sigma_kpoints
|
||||
ik = nc0.reader.gwkpt2seqindex(kpoint)
|
||||
kgw = nc0.sigma_kpoints[ik]
|
||||
|
||||
# Order files by ecuteps
|
||||
labels, ncfiles, params = self.sortby("ecuteps", unpack=True)
|
||||
ecuteps_vals = np.array(params)
|
||||
|
||||
# Get QP and KS gaps ordered by ecuteps_vals.
|
||||
qp_gaps, ks_gaps = map(np.array, zip(*[ncfile.get_qpgap(spin, kgw, with_ksgap=True)
|
||||
for ncfile in ncfiles]))
|
||||
ydata = qp_gaps if not plot_qpmks else qp_gaps - ks_gaps
|
||||
|
||||
# Fig results as a function of ecuteps
|
||||
from scipy.optimize import curve_fit
|
||||
def func(x, a, b, c):
|
||||
return a * x**(-1.5) + b * x**(-2.5) + c
|
||||
|
||||
if slice_data is not None:
|
||||
# Allow user to select a subset of data points via python slice
|
||||
ecuteps_vals = ecuteps_vals[slice_data]
|
||||
ydata = ydata[slice_data]
|
||||
|
||||
popt, pcov = curve_fit(func, ecuteps_vals, ydata)
|
||||
|
||||
ax, fig, plt = get_ax_fig_plt(ax=None)
|
||||
ax.plot(ecuteps_vals, ydata, 'ro', label='ab-initio data')
|
||||
min_ecuteps, max_ecuteps = ecuteps_vals.min(), ecuteps_vals.max() + 20
|
||||
xs = np.linspace(min_ecuteps, max_ecuteps, num=50)
|
||||
# Change label depending on plot_qpmks
|
||||
what = r"\Delta E_g" if plot_qpmks else r"E_g"
|
||||
ax.plot(xs, func(xs, *popt), 'b-',
|
||||
label=f'fit: $B_3$=%5.3f, $B_5$=%5.3f, ${what} (\infty)$=%5.3f' % tuple(popt))
|
||||
ax.hlines(popt[-1], min_ecuteps, max_ecuteps, color="k")
|
||||
ax.legend(loc="best", fontsize=fontsize, shadow=True)
|
||||
ax.grid(True)
|
||||
ax.set_xlabel('ecuteps (Ha)')
|
||||
ax.set_ylabel(f'${what}$ (eV)')
|
||||
#ax.set_ylabel('$\Delta E(E_c^{\chi})$ (eV)')
|
||||
#ax.title(r'$\Delta E(E_c^{\chi}) = \Delta E_g (\infty) + B_3 * E_c^{\chi (-3/2)} + B_5* E_c^{\chi (-5/2)} $')
|
||||
|
||||
#if show:
|
||||
plt.show()
|
||||
|
||||
return dict2namedtuple(
|
||||
fig=fig,
|
||||
func=func,
|
||||
ecuteps_vals=ecuteps_vals,
|
||||
ydata=ydata,
|
||||
popt=popt,
|
||||
pcov=pcov,
|
||||
)
|
||||
|
||||
# An alias to have a common API for robots.
|
||||
get_dataframe = get_qpgaps_dataframe
|
||||
|
||||
|
@ -1906,6 +1979,7 @@ class SigresRobot(Robot, RobotWithEbands):
|
|||
|
||||
nc0 = self.abifiles[0]
|
||||
nsppol, sigma_kpoints = nc0.nsppol, nc0.sigma_kpoints
|
||||
|
||||
# Build grid with (nkpt, 1) plots.
|
||||
ncols, nrows = 1, len(sigma_kpoints)
|
||||
ax_list, fig, plt = get_axarray_fig_plt(None, nrows=nrows, ncols=ncols,
|
||||
|
|
|
@ -451,6 +451,10 @@ class ElectronBandsTest(AbipyTest):
|
|||
# Export it in BXSF format.
|
||||
r.ebands_kmesh.to_bxsf(self.get_tmpname(text=True))
|
||||
|
||||
# This just to call interpolate with line_density 0
|
||||
r = si_ebands_kmesh.interpolate(lpratio=5, vertices_names=vertices_names, line_density=0,
|
||||
verbose=1)
|
||||
|
||||
def test_derivatives(self):
|
||||
"""Testing computation of effective masses."""
|
||||
ebands = ElectronBands.from_file(abidata.ref_file("si_nscf_GSR.nc"))
|
||||
|
@ -593,6 +597,11 @@ class ElectronDosPlotterTest(AbipyTest):
|
|||
"""Testing ElelectronDosPlotter API."""
|
||||
gsr_path = abidata.ref_file("si_scf_GSR.nc")
|
||||
gs_bands = ElectronBands.from_file(gsr_path)
|
||||
|
||||
with open(gsr_path, "rb") as fh:
|
||||
same_gsr_bands = ElectronBands.from_binary_string(fh.read())
|
||||
assert same_gsr_bands.structure == gs_bands.structure
|
||||
|
||||
si_edos = gs_bands.get_edos()
|
||||
|
||||
plotter = ElectronDosPlotter()
|
||||
|
|
|
@ -67,8 +67,15 @@ class GSRFileTestCase(AbipyTest):
|
|||
|
||||
def test_gsr_silicon(self):
|
||||
"""spin unpolarized GSR file"""
|
||||
filepath = abidata.ref_file("si_scf_GSR.nc")
|
||||
|
||||
with GsrFile(abidata.ref_file("si_scf_GSR.nc")) as gsr:
|
||||
# Init GSR from binary string.
|
||||
with open(filepath, "rb") as fh:
|
||||
same_gsr = GsrFile.from_binary_string(fh.read())
|
||||
same_structure = same_gsr.structure
|
||||
same_gsr.close()
|
||||
|
||||
with GsrFile(filepath) as gsr:
|
||||
assert gsr.basename == "si_scf_GSR.nc"
|
||||
assert gsr.relpath == os.path.relpath(abidata.ref_file("si_scf_GSR.nc"))
|
||||
assert gsr.filetype
|
||||
|
@ -86,6 +93,8 @@ class GSRFileTestCase(AbipyTest):
|
|||
self.assert_almost_equal(gsr.energy.to("Ha"), -8.86527676798556)
|
||||
self.assert_almost_equal(gsr.energy_per_atom * len(gsr.structure), gsr.energy)
|
||||
|
||||
assert gsr.structure == same_structure
|
||||
|
||||
assert gsr.params["nband"] == 8
|
||||
assert gsr.params["nkpt"] == 29
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ class WrNcFile(AbinitNcFile, Has_Structure, NotebookWriter):
|
|||
@add_fig_kwargs
|
||||
def plot_maxw(self, scale="semilogy", ax=None, fontsize=8, **kwargs):
|
||||
"""
|
||||
Plot the decay of max_{r,idir,ipert} |W(R,r,idir,ipert)|
|
||||
Plot the decay of max_{r,idir,ipert} `|W(R,r,idir,ipert)|`
|
||||
for the long-range and the short-range part.
|
||||
|
||||
Args:
|
||||
|
|
|
@ -55,7 +55,7 @@ def main():
|
|||
root = os.path.join(os.path.dirname(__file__), "plot")
|
||||
scripts = []
|
||||
for fname in os.listdir(root):
|
||||
if fname.endswith(".py") and fname.startswith("plot_"):
|
||||
if fname.endswith(".py") and fname.startswith("plot"):
|
||||
scripts.append(os.path.join(root, fname))
|
||||
|
||||
# Run scripts according to mode.
|
||||
|
|
|
@ -9,7 +9,7 @@ Run the scripts to generate the directory with the flow, then use the :ref:`abir
|
|||
Alternatively, one can use the ``-s`` option to generate the flow and run it immediately with the scheduler.
|
||||
Use ``--help`` for further information on the available options.
|
||||
|
||||
Note that the figures can only show the initial configuration of the Flow.
|
||||
Note that the figures can only show the **initial configuration of the Flow**.
|
||||
Additional Works generated at runtime won't be displayed.
|
||||
To visualize the entire Flow, you need to run the script and then use::
|
||||
|
||||
|
@ -21,5 +21,5 @@ where `FLOWDIR` is the directory of the Flow.
|
|||
|
||||
The following examples show how to use python and the AbiPy API to generate and run
|
||||
Abinit calculations in a semi-automatic way.
|
||||
These examples are not supposed to produce physically meaningful results
|
||||
These examples **are not supposed to produce physically meaningful results**
|
||||
as input parameters are usually underconverged.
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
#!/usr/bin/env python
|
||||
import sys
|
||||
import os
|
||||
import abipy.abilab as abilab
|
||||
import abipy.data as abidata
|
||||
|
||||
from abipy import flowtk
|
||||
|
||||
#def make_scf_input(scf_ngkpt, paral_kgb=0):
|
||||
# """
|
||||
# This function constructs the input file for the GS calculation:
|
||||
# on a scf_ngkpt Gamma-centered k-mesh.
|
||||
# """
|
||||
# structure = abilab.Structure.from_abivars(
|
||||
# acell=[7.7030079150, 7.7030079150, 7.7030079150],
|
||||
# rprim=[0.0000000000, 0.5000000000, 0.5000000000,
|
||||
# 0.5000000000, 0.0000000000, 0.5000000000,
|
||||
# 0.5000000000, 0.5000000000, 0.0000000000],
|
||||
# natom=2,
|
||||
# ntypat=2,
|
||||
# typat=[1, 2],
|
||||
# znucl=[3, 9],
|
||||
# xred=[0.0000000000, 0.0000000000, 0.0000000000,
|
||||
# 0.5000000000, 0.5000000000, 0.5000000000]
|
||||
# )
|
||||
#
|
||||
# pseudos = ["03-Li.LDA.TM.pspnc", "09-F.LDA.TM.pspnc"]
|
||||
#
|
||||
# gs_inp = abilab.AbinitInput(structure, pseudos=pseudos)
|
||||
#
|
||||
# gs_inp.set_vars(
|
||||
# ecut=50.0,
|
||||
# ngkpt=scf_ngkpt,
|
||||
# shiftk=[0, 0, 0],
|
||||
# nband=10,
|
||||
# paral_kgb=paral_kgb,
|
||||
# tolvrs=1.0e-10,
|
||||
# prtpot=1, # This is required for the Sternheimer method in the EPH part.
|
||||
# )
|
||||
#
|
||||
# return gs_inp
|
||||
|
||||
def make_scf_input((scf_ngkpt, paral_kgb=0):
|
||||
"""
|
||||
This function constructs the input file for the GS calculation:
|
||||
"""
|
||||
|
||||
# Initialize MgO structure from abinit variables.
|
||||
structure = abilab.Structure.from_abivars(
|
||||
acell=3 * [4.252718 * abilab.units.ang_to_bohr],
|
||||
rprim=[0.0000000000, 0.5000000000, 0.5000000000,
|
||||
0.5000000000, 0.0000000000, 0.5000000000,
|
||||
0.5000000000, 0.5000000000, 0.0000000000],
|
||||
natom=2,
|
||||
ntypat=2,
|
||||
typat=[1, 2],
|
||||
znucl=[12, 8],
|
||||
xred=[0.0000000000, 0.0000000000, 0.0000000000,
|
||||
0.5000000000, 0.5000000000, 0.5000000000]
|
||||
)
|
||||
|
||||
# Input for GS part.
|
||||
# NC pseudos assumed in currect working directory.
|
||||
#pseudos = ["Mg-sp-gw.psp8", "O.psp8"]
|
||||
pseudos = abidata.pseudos("12mg.pspnc", "O.psp8")
|
||||
|
||||
gs_inp = abilab.AbinitInput(structure, pseudos=pseudos)
|
||||
|
||||
gs_inp.set_vars(
|
||||
nband=12,
|
||||
paral_kgb=paral_kgb,
|
||||
ecut=35.0, # Too low. Should be ~50
|
||||
ngkpt=scf_ngkpt, # Too coarse
|
||||
nshiftk=1, # Gamma-centered mesh. Important to have the CBM/VBM!
|
||||
shiftk=[0, 0, 0],
|
||||
tolvrs=1.0e-10,
|
||||
diemac=9.0,
|
||||
nstep=150,
|
||||
nbdbuf=4,
|
||||
prtpot=1, # Print potential for Sternheimer
|
||||
iomode=3, # Produce output files in netcdf format.
|
||||
)
|
||||
|
||||
return gs_inp
|
||||
|
||||
def build_flow(options):
|
||||
"""
|
||||
Create a `Flow` for ZPR calculations.
|
||||
"""
|
||||
# Working directory (default is the name of the script with '.py' removed and "run_" replaced by "flow_")
|
||||
if not options.workdir:
|
||||
options.workdir = os.path.basename(__file__).replace(".py", "").replace("run_", "flow_")
|
||||
|
||||
flow = flowtk.Flow(workdir=options.workdir)
|
||||
|
||||
# Build input for the GS calculation and register the first GS ScfTask.
|
||||
gs_inp = make_scf_input(scf_ngkpt=[4, 4, 4])
|
||||
work = flow.register_scf_task(gs_inp)
|
||||
scf_task = work[0]
|
||||
|
||||
# Build input for NSCF calculation along k-path (automatically selected by AbiPy)
|
||||
nscf_kpath_inp = gs_inp.make_ebands_input()
|
||||
work.register_nscf_task(nscf_kpath_inp, deps={scf_task: "DEN"})
|
||||
|
||||
# This is the ab-initio q-mesh that should be COMMENSURATE with scf_ngkpt
|
||||
ddb_ngqpt = [2, 2, 2]
|
||||
|
||||
# Now we build the NSCF tasks with different k-meshes and empty states.
|
||||
# Each NSCF task generates one of the WFK files used to build the EPH self-energy.
|
||||
# These WFK files are then used to erform convergece tests with respect to
|
||||
# the interpolated fine q-mesh.
|
||||
# NOTE that in the EPH we are gonna use k_mesh = q_mesh
|
||||
ngkpt_fine_list = [
|
||||
[8, 8, 8],
|
||||
#[12, 12, 12],
|
||||
#[32, 32, 32],
|
||||
]
|
||||
|
||||
nscf_empty_states_tasks = []
|
||||
for ngkpt_fine in ngkpt_fine_list:
|
||||
nscf_empty_kmesh_inp = gs_inp.new_with_vars(
|
||||
ngkpt=ngkpt_fine,
|
||||
#nband=630, # Too low. ~300
|
||||
#nbdbuf=30, # Reduces considerably the time needed to converge empty states!
|
||||
nband=40, # Too low. ~300
|
||||
nbdbuf=5, # Reduces considerably the time needed to converge empty states!
|
||||
tolwfr=1e-18,
|
||||
iscf=-2,
|
||||
)
|
||||
t = work.register_nscf_task(nscf_empty_kmesh_inp, deps={scf_task: "DEN"})
|
||||
nscf_empty_states_tasks.append(t)
|
||||
|
||||
# Create work for phonon calculation on the coarse ddb_ngqpt q-mesh.
|
||||
# Electric field and Born effective charges are computed.
|
||||
ph_work = flowtk.PhononWfkqWork.from_scf_task(scf_task, ngqpt=ddb_ngqpt, with_becs=True)
|
||||
#for task in ph_work:
|
||||
# task.input.set_vars(prtwf=-1)
|
||||
flow.register_work(ph_work)
|
||||
|
||||
# Build template for e-ph self-energy calculation (real + imag part)
|
||||
# The k-points must be in the WFK file
|
||||
eph_template = gs_inp.new_with_vars(
|
||||
optdriver=7, # Enter EPH driver.
|
||||
eph_task=4, # Activate computation of EPH self-energy.
|
||||
ddb_ngqpt=ddb_ngqpt, # Ab-initio q-mesh used to produce the DDB file.
|
||||
#nkptgw=2,
|
||||
#kptgw=[0, 0, 0,
|
||||
# 0.5, 5, 0],
|
||||
#bdgw=[1, 8, 1, 8],
|
||||
#gw_qprange=1,
|
||||
tmesh=[0, 200, 1], # (start, step, num)
|
||||
zcut="0.01 eV",
|
||||
mixprec=1,
|
||||
boxcutmin=1.1,
|
||||
)
|
||||
|
||||
# Set q-path for Fourier interpolation of phonons.
|
||||
eph_template.set_qpath(10)
|
||||
# Set q-mesh for phonons DOS.
|
||||
eph_template.set_phdos_qmesh(nqsmall=16, method="tetra")
|
||||
|
||||
# Now we use the EPH template to perform a convergence study in which
|
||||
# we change the q-mesh used to integrate the self-energy and the number of bands.
|
||||
# The code will activate the Fourier interpolation of the DFPT potentials
|
||||
# if eph_ngqpt_fine != ddb_ngqpt
|
||||
|
||||
# Create empty work to contain EPH tasks with this value of eph_ngqpt_fine
|
||||
eph_work = flow.new_work()
|
||||
|
||||
for ngkpt_fine, nscf_task in zip(ngkpt_fine_list, nscf_empty_states_tasks):
|
||||
new_inp = eph_template.new_with_vars(
|
||||
ngkpt=ngkpt_fine,
|
||||
eph_ngqpt_fine=eph_ngqpt_fine
|
||||
) #, nband=nband)
|
||||
|
||||
# The EPH code requires the GS WFK, the DDB file with all perturbations
|
||||
# and the DVDB file with the DFPT potentials (already merged by ph_work)
|
||||
deps = {nscf_task: "WFK", ph_work: ["DDB", "DVDB"]}
|
||||
eph_work.register_eph_task(new_inp, deps=deps)
|
||||
|
||||
#flow.allocate()
|
||||
return flow
|
||||
|
||||
|
||||
@flowtk.flow_main
|
||||
def main(options):
|
||||
"""
|
||||
This is our main function that will be invoked by the script.
|
||||
flow_main is a decorator implementing the command line interface.
|
||||
Command line args are stored in `options`.
|
||||
"""
|
||||
return build_flow(options)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
|
@ -6,7 +6,7 @@ Flow for Born effective charges and dielectric tensors with DFPT
|
|||
This example shows how to compute the Born effective charges and
|
||||
the dielectric tensors (e0, einf) of AlAs with AbiPy flows.
|
||||
We perform multiple calculations by varying the number of k-points
|
||||
to analyze the convergence of the results wrt nkpt
|
||||
in order to analyze the convergence of the results wrt nkpt
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
|
@ -15,7 +15,6 @@ import abipy.data as abidata
|
|||
|
||||
from abipy import flowtk
|
||||
|
||||
|
||||
def make_scf_input(ngkpt, paral_kgb=0):
|
||||
"""
|
||||
This function constructs the input file for the GS calculation for a given IBZ sampling.
|
||||
|
@ -62,7 +61,7 @@ def build_flow(options):
|
|||
flow = flowtk.Flow(workdir=options.workdir)
|
||||
|
||||
for ngkpt in [(2, 2, 2), (4, 4, 4), (8, 8, 8)]:
|
||||
# Build input for GS calculation
|
||||
# Build input for GS calculation with different k-meshes
|
||||
scf_input = make_scf_input(ngkpt=ngkpt)
|
||||
flow.register_scf_task(scf_input, append=True)
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Effective masses with finite difference
|
||||
=======================================
|
||||
Conductivity in metals
|
||||
======================
|
||||
|
||||
Flow to compute effective masses with finite difference method.
|
||||
Derivatives are computed along lines in k-space.
|
||||
Flow to compute conductivity in metals
|
||||
"""
|
||||
|
||||
import os
|
||||
|
|
|
@ -6,7 +6,8 @@ Effective masses with DFPT
|
|||
Flow to compute effective masses with DFPT.
|
||||
Two options are available:
|
||||
|
||||
- EffMassDFPTWork --> Run DFPT calculation directly assuming the location of the band edges is already known.
|
||||
- EffMassDFPTWork --> Run DFPT calculation directly assuming the location
|
||||
of the band edges is already known.
|
||||
- EffMassAutoDFPTWork --> Run NSCF calculation to find band edges, then use DFPT.
|
||||
"""
|
||||
|
||||
|
@ -24,7 +25,7 @@ def make_scf_input(usepaw=0, nspinor=1):
|
|||
else:
|
||||
pseudos = abidata.pseudos("Si_r.psp8") if usepaw == 0 else abidata.pseudos("Si.GGA_PBE-JTH-paw.xml")
|
||||
|
||||
# https://docs.abinit.org/tests/v7/Input/t82.in
|
||||
# See https://docs.abinit.org/tests/v7/Input/t82.in
|
||||
structure = dict(
|
||||
ntypat=1,
|
||||
natom=2,
|
||||
|
@ -76,7 +77,8 @@ def build_flow(options):
|
|||
# effmass_bands_f90 defines the band range for each k in k0_list
|
||||
# Here we are interested in the effective masses at the Gamma point for the valence bands
|
||||
effmass_bands_f90 = [1, 4] if scf_input["nspinor"] == 1 else [1, 8]
|
||||
work = EffMassDFPTWork.from_scf_input(scf_input, k0_list=(0, 0, 0), effmass_bands_f90=effmass_bands_f90)
|
||||
work = EffMassDFPTWork.from_scf_input(scf_input, k0_list=(0, 0, 0),
|
||||
effmass_bands_f90=effmass_bands_f90)
|
||||
flow.register_work(work)
|
||||
|
||||
# or use this Work to detect band edges automatically but increase ndivsm and decrease tolwfr!
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Flow for Equation of State
|
||||
Flow for equation of state
|
||||
==========================
|
||||
|
||||
Flow to compute the equation of state by fitting E(V) at T = 0.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Estimate the ZPR at band edges with the generalized Frohlich model
|
||||
==================================================================
|
||||
Estimate the ZPR at the band edges with the generalized Frohlich model
|
||||
======================================================================
|
||||
|
||||
Flow to estimate the zero-point renormalization at the band edges
|
||||
using the generalized Frohlich model. The flow uses DFPT to compute
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Estimate the ZPR of band edges with generalized Frohlich mode
|
||||
=============================================================
|
||||
Estimate the ZPR of band edges with generalized Frohlich model
|
||||
==============================================================
|
||||
|
||||
Flow to estimate the zero-point renormalization at the band edges
|
||||
using the generalized Frohlich model. The flow uses DFPT to compute
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Band structure with/without spin-orbit
|
||||
======================================
|
||||
Band structure with/without SOC
|
||||
================================
|
||||
|
||||
This example shows how to compute the band structure of GaAs with and without spin-orbit term.
|
||||
We essentially build two BandStructureWork inside a loop over nspinor in [1, 2]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Flow for Non-linear optic with DFPT
|
||||
Flow for non-linear optic with DFPT
|
||||
===================================
|
||||
|
||||
Flow to compute non-linear optical properties with DFPT (static limit).
|
||||
|
@ -78,8 +78,6 @@ def main(options):
|
|||
flow_main is a decorator implementing the command line interface.
|
||||
Command line args are stored in `options`.
|
||||
"""
|
||||
# Temporarily disabled in v8.8.2
|
||||
#return 0
|
||||
return build_flow(options)
|
||||
|
||||
|
||||
|
|
|
@ -3,8 +3,10 @@ r"""
|
|||
Phonopy + Abinit Flow
|
||||
=====================
|
||||
|
||||
This example shows how to compute phonon frequencies with phonopy (supercells and finite-difference method).
|
||||
This approach could be useful to obtain vibrational properties with XC functionals for which DFPT is not yet implemented.
|
||||
This example shows how to compute phonon frequencies with phonopy
|
||||
(supercells and finite-difference method).
|
||||
This approach could be useful to obtain vibrational properties with XC functionals
|
||||
for which DFPT is not yet implemented.
|
||||
|
||||
.. warning:
|
||||
|
||||
|
|
|
@ -3,16 +3,29 @@
|
|||
AbiPy Gallery
|
||||
=============
|
||||
|
||||
There are a variety of ways to use the AbiPy post-processing tools,
|
||||
and most of them are illustrated in the examples in this directory.
|
||||
|
||||
Remember that one can also generate a jupyter notebook directly from the command line with
|
||||
the :ref:`abiopen.py` script and the command::
|
||||
|
||||
abiopen.py FILE -nb
|
||||
|
||||
issue
|
||||
There are a variety of ways to use the AbiPy post-processing tools,
|
||||
and some of them are illustrated in the examples in this directory.
|
||||
These examples represent an excellent starting point if you need to implement
|
||||
a customized script to solve your particular problem.
|
||||
Keep in mind, however, that simple visualization tasks can be easily
|
||||
automated by just issuing in the terminal::
|
||||
|
||||
abiopen.py FILE --expose
|
||||
|
||||
to generate plots automatically or use one of the options of :ref:`abiview.py` to plot the results automatically.
|
||||
to generate a predefined list of **matplotlib** plots.
|
||||
To activate the plotly version use:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
abiopen.py FILE --plotly
|
||||
|
||||
although at the time of writing not all the files support this protocol.
|
||||
|
||||
Note also that one can generate jupyter-lab notebooks directly from the command line with
|
||||
abiopen.py_ and the command::
|
||||
|
||||
abiopen.py FILE -nb
|
||||
|
||||
Add `--classic-notebook` if you prefer classic jupyter notebooks.
|
||||
|
||||
Finally, use one of the options of the abiview.py_ script to plot the results automatically.
|
||||
|
|
|
@ -4,28 +4,29 @@ Eliashberg function
|
|||
===================
|
||||
|
||||
This example shows how to plot the Eliashberg function a2F(w)
|
||||
and the e-ph coupling strenght in metals.
|
||||
and the total e-ph coupling strenght in metals.
|
||||
"""
|
||||
from abipy import abilab
|
||||
import abipy.data as abidata
|
||||
|
||||
phdos_path = abidata.ref_file("al_161616q_PHDOS.nc")
|
||||
|
||||
with abilab.abiopen(abidata.ref_file("al_888k_161616q_A2F.nc")) as ncfile:
|
||||
print(ncfile)
|
||||
#ncfile.phbands.plot()
|
||||
#ncfile.a2f_qintp.plot()
|
||||
#with_lambda = False
|
||||
#fig = ncfile.a2f_qcoarse.plot_nuterms(with_lambda=with_lambda, show=False)
|
||||
#ncfile.a2f_qintp.plot_nuterms(axmat=fig.axes, with_lambda=with_lambda)
|
||||
ncfile = abilab.abiopen(abidata.ref_file("al_888k_161616q_A2F.nc"))
|
||||
print(ncfile)
|
||||
|
||||
#ncfile.plot()
|
||||
ncfile.plot_with_a2f(phdos=phdos_path)
|
||||
#ncfile.phbands.plot()
|
||||
#ncfile.a2f_qintp.plot()
|
||||
#with_lambda = False
|
||||
#fig = ncfile.a2f_qcoarse.plot_nuterms(with_lambda=with_lambda, show=False)
|
||||
#ncfile.a2f_qintp.plot_nuterms(axmat=fig.axes, with_lambda=with_lambda)
|
||||
|
||||
ncfile.plot_eph_strength(what="gamma")
|
||||
#ncfile.plot_eph_strength(what="lambda")
|
||||
#ncfile.plot()
|
||||
ncfile.plot_with_a2f(phdos=phdos_path)
|
||||
|
||||
ncfile.plot_a2f_interpol()
|
||||
ncfile.plot_eph_strength(what="gamma")
|
||||
#ncfile.plot_eph_strength(what="lambda")
|
||||
|
||||
# Grid with 3 plots (a2F, F, a2F) with F taken from PHDOS file.
|
||||
#ncfile.a2f_qintp.plot_a2(phdos_path)
|
||||
ncfile.plot_a2f_interpol()
|
||||
|
||||
# Grid with 3 plots (a2F, F, a2F) with F taken from PHDOS file.
|
||||
#ncfile.a2f_qintp.plot_a2(phdos_path)
|
||||
|
|
|
@ -15,8 +15,10 @@ wfk_file = abiopen(abidata.ref_file("si_scf_WFK.nc"))
|
|||
# Extract the crystalline structure.
|
||||
structure = wfk_file.structure
|
||||
|
||||
# Visualize the BZ.
|
||||
#%%
|
||||
# To visualize the BZ with matplotlib, use:
|
||||
structure.plot_bz()
|
||||
|
||||
# Close the wfk file
|
||||
#%%
|
||||
# Remember to close the wfk file with:
|
||||
wfk_file.close()
|
||||
|
|
|
@ -1,25 +1,61 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Phonon Bands with/without ASR
|
||||
=============================
|
||||
Phonon bands with/without the ASR
|
||||
=================================
|
||||
|
||||
This example shows how to plot a phonon band structure
|
||||
with and without imposing the acoustic sum rule at the Gamma point.
|
||||
with and without enforcing the acoustic sum rule (ASR).
|
||||
Both matplotlib and plotly are supported.
|
||||
|
||||
.. important::
|
||||
|
||||
Note that a **manager.yml** configuration file and an abinit installation are required
|
||||
to run this script as AbiPy needs to invoke anaddb to compute phonons from the DDB file.
|
||||
"""
|
||||
|
||||
#%%
|
||||
# Open the DDB file with:
|
||||
|
||||
from abipy import abilab
|
||||
import abipy.data as abidata
|
||||
|
||||
# Open DDB file
|
||||
filepath = abidata.ref_file("mp-1009129-9x9x10q_ebecs_DDB")
|
||||
ddb = abilab.abiopen(filepath)
|
||||
|
||||
# This method computes the phonon bands and DOS by calling anaddb
|
||||
# with different values of asr and returns a PhononBandsPlotter object.
|
||||
plotter = ddb.anacompare_asr(asr_list=(0, 2))
|
||||
#%%
|
||||
# The ``ddb.anacompare_asr`` method computes the phonon bands and the DOS by calling anaddb
|
||||
# with different values of asr and returns a PhononBandsPlotter object:
|
||||
# To make the computation faster, we use the **advanced** options dipdip -1.
|
||||
# This option should produce results similar to dipdip 1 yet make sure to test
|
||||
# the effect of this variable before using it in production.
|
||||
|
||||
plotter = ddb.anacompare_asr(asr_list=(0, 2), dipdip=-1)
|
||||
print(plotter)
|
||||
|
||||
#%%
|
||||
# To plot the bands on the same figure with matplotlib, use:
|
||||
|
||||
plotter.combiplot()
|
||||
|
||||
# Set nqsmall to 0 to disable DOS computation.
|
||||
plotter = ddb.anacompare_asr(asr_list=(0, 2), nqsmall=0, ndivsm=10)
|
||||
#%%
|
||||
# For the plotly version, use:
|
||||
|
||||
plotter.combiplotly()
|
||||
|
||||
#%%
|
||||
# To disable the DOS computation, set ``nqsmall` to 0:
|
||||
|
||||
plotter = ddb.anacompare_asr(asr_list=(0, 2), nqsmall=0, ndivsm=10, dipdip=-1)
|
||||
|
||||
#%%
|
||||
# To plot the bands on different subplots with matplotlib, use:
|
||||
|
||||
plotter.gridplot()
|
||||
|
||||
#%%
|
||||
# For the plotly version, use:
|
||||
plotter.gridplotly()
|
||||
|
||||
#%%
|
||||
# Finally, remember to close the file with:
|
||||
|
||||
ddb.close()
|
||||
|
|
|
@ -15,8 +15,9 @@ ncfile = abiopen(abidata.ref_file("si_DEN.nc"))
|
|||
# The DEN file has a `Density`, a `Structure` and an `ElectronBands` object
|
||||
print(ncfile.structure)
|
||||
|
||||
#%%
|
||||
# To plot the KS eigenvalues.
|
||||
#ncfile.ebands.plot()
|
||||
ncfile.ebands.plot()
|
||||
|
||||
density = ncfile.density
|
||||
print(density)
|
||||
|
@ -24,14 +25,17 @@ print(density)
|
|||
# To visualize the total charge wih vesta
|
||||
#visu = density.visualize("vesta"); visu()
|
||||
|
||||
#%%
|
||||
# To plot the density along the line connecting
|
||||
# the first and the second in the structure:
|
||||
density.plot_line(point1=0, point2=1)
|
||||
|
||||
#%%
|
||||
# alternatively, one can define the line in terms of two points
|
||||
# in fractional coordinates:
|
||||
density.plot_line(point1=[0, 0, 0], point2=[2.25, 2.25, 2.25], num=300)
|
||||
|
||||
#%%
|
||||
# To plot the density along the lines connect the firt atom in the structure
|
||||
# and all the neighbors within a sphere of radius 3 Angstrom:
|
||||
density.plot_line_neighbors(site_index=0, radius=3)
|
||||
|
|
|
@ -10,21 +10,37 @@ produced at the end of the GS run.
|
|||
from abipy.abilab import abiopen
|
||||
import abipy.data as abidata
|
||||
|
||||
#%%
|
||||
# Here we use one of the GSR files shipped with abipy.
|
||||
# Replace filename with the path to your GSR file or your WFK file.
|
||||
|
||||
filename = abidata.ref_file("si_nscf_GSR.nc")
|
||||
|
||||
#%%
|
||||
# Open the GSR file and extract the band structure.
|
||||
# (alternatively one can use the shell and `abiopen.py OUT_GSR.nc -nb`
|
||||
# to open the file in a jupyter notebook.
|
||||
|
||||
with abiopen(filename) as ncfile:
|
||||
ebands = ncfile.ebands
|
||||
|
||||
# Plot the band energies. Note that the labels for the k-points
|
||||
# are found automatically in an internal database.
|
||||
# Show fundamental and direct gaps.
|
||||
#ebands.plot(with_gaps="fd", title="Silicon band structure")
|
||||
#%%
|
||||
# Plot the band energies with matplotlib.
|
||||
# Note that the labels for the k-points are found automatically in an internal database.
|
||||
# Use `with_gaps` to show fundamental and direct gaps.
|
||||
|
||||
ebands.plot(with_gaps=True, title="Silicon band structure")
|
||||
|
||||
# Plot the BZ and the k-point path.
|
||||
#%%
|
||||
# For the plotly version, use:
|
||||
|
||||
ebands.plotly(with_gaps=True)
|
||||
|
||||
# .. warning:
|
||||
#
|
||||
# Note that, for the time being, ``with_gaps`` is incompatible with the ``title`` argument.
|
||||
|
||||
#%%
|
||||
# Plot the BZ and the k-point path with matplotlib
|
||||
|
||||
ebands.kpoints.plot()
|
||||
|
|
|
@ -14,7 +14,8 @@ import abipy.data as abidata
|
|||
with abiopen(abidata.ref_file("si_scf_GSR.nc")) as gsr:
|
||||
ebands = gsr.ebands
|
||||
|
||||
#%%
|
||||
import matplotlib.pyplot as plt
|
||||
# `swarm=True` to show the datapoints on top of the boxes
|
||||
# Use `swarm=True` to show the datapoints on top of the boxes
|
||||
ebands.boxplot(swarm=True)
|
||||
plt.show()
|
||||
|
|
|
@ -19,10 +19,12 @@ with abiopen(abidata.ref_file("si_nscf_GSR.nc")) as nscf_file:
|
|||
with abiopen(abidata.ref_file("si_scf_GSR.nc")) as gs_file:
|
||||
gs_ebands = gs_file.ebands
|
||||
|
||||
#%%
|
||||
# Compute the DOS with the Gaussian method (use default values for
|
||||
# the broadening and the step of the linear mesh.
|
||||
edos = gs_ebands.get_edos()
|
||||
|
||||
#%%
|
||||
# Plot bands and DOS.
|
||||
nscf_ebands.plot_with_edos(edos, e0=None, with_gaps=True)
|
||||
|
||||
|
|
|
@ -22,17 +22,22 @@ plotter.add_ebands("k-path", ref_file("si_nscf_GSR.nc"))
|
|||
frame = plotter.get_ebands_frame()
|
||||
print(frame)
|
||||
|
||||
plotter.gridplot(with_gaps=True)
|
||||
#plotter.animate()
|
||||
#%%
|
||||
# To create a grid plot use:
|
||||
|
||||
plotter.gridplot(with_gaps=True)
|
||||
|
||||
#%%
|
||||
# To plot a grid with band structures + DOS, use the optional argument `edos_objects`
|
||||
# The first subplot gets the band dispersion from eb_objects[0] and the DOS from edos_objects[0]
|
||||
# edos_kwargs is an optional dictionary passed to `get_dos` to compute the DOS.
|
||||
#
|
||||
|
||||
eb_objects = 2 * [ref_file("si_nscf_GSR.nc")]
|
||||
edos_objects = 2 * [ref_file("si_scf_GSR.nc")]
|
||||
|
||||
# sphinx_gallery_thumbnail_number = 2
|
||||
plotter = ElectronBandsPlotter()
|
||||
plotter.add_ebands("Si", ref_file("si_nscf_GSR.nc"), edos=ref_file("si_scf_GSR.nc"))
|
||||
plotter.add_ebands("Same data", ref_file("si_nscf_GSR.nc"), edos=ref_file("si_scf_GSR.nc"))
|
||||
# sphinx_gallery_thumbnail_number = 2
|
||||
plotter.gridplot()
|
||||
|
|
|
@ -4,15 +4,14 @@ Gruneisen parameters
|
|||
====================
|
||||
|
||||
This example shows how to analyze the Gruneisen parameters
|
||||
computed by anaddb via finite difference. See also v8/Input/t45.in
|
||||
computed by anaddb via finite difference.
|
||||
See also v8/Input/t45.in
|
||||
"""
|
||||
from __future__ import print_function, division
|
||||
|
||||
import abipy.data as abidata
|
||||
from abipy import abilab
|
||||
|
||||
# Open the file with abiopen
|
||||
# (alternatively one can use the shell and `abiopen.py OUT_GRUNS.nc -nb`
|
||||
# Alternatively one can use the shell and `abiopen.py OUT_GRUNS.nc -nb`
|
||||
# to open the file in a jupyter notebook.
|
||||
ncfile = abilab.abiopen(abidata.ref_file("mg2si_GRUNS.nc"))
|
||||
|
||||
|
@ -25,7 +24,8 @@ ncfile.plot_phbands_with_gruns(title="Phonon bands with markers proportional to
|
|||
|
||||
ncfile.plot_gruns_bs(title="Gruneisen along high-symmetry path.")
|
||||
|
||||
ncfile.plot_phbands_with_gruns(fill_with="gruns_fd", title="Gruneisen parameters with finite differences.", with_doses=None)
|
||||
ncfile.plot_phbands_with_gruns(fill_with="gruns_fd",
|
||||
title="Gruneisen parameters with finite differences.", with_doses=None)
|
||||
|
||||
ncfile.plot_gruns_scatter(units='cm-1',title="Scatter plot with Gruneisen parameters")
|
||||
|
||||
|
|
|
@ -1,33 +1,54 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Phonon Band structures
|
||||
======================
|
||||
Phonon band structures with LO-TO
|
||||
=================================
|
||||
|
||||
This example shows how to plot the phonon band structure of AlAs.
|
||||
without the LO-TO splitting.
|
||||
See tutorial/lesson_rf2.html
|
||||
"""
|
||||
|
||||
#%%
|
||||
# Open the PHBST file produced by anaddb and get the phonon bands.
|
||||
# Note that the treatment of the LO-TO splitting for q--> 0 requires
|
||||
# additional steps. See `plot_phonons_lo_to.py`.
|
||||
|
||||
from abipy.abilab import abiopen
|
||||
import abipy.data as abidata
|
||||
|
||||
# Open the PHBST file produced by anaddb and get the phonon bands.
|
||||
with abiopen(abidata.ref_file("trf2_5.out_PHBST.nc")) as ncfile:
|
||||
phbands = ncfile.phbands
|
||||
|
||||
#%%
|
||||
# Read the Phonon DOS from the netcd file produced by anaddb (prtdos 2)
|
||||
|
||||
with abiopen(abidata.ref_file("trf2_5.out_PHDOS.nc")) as ncfile:
|
||||
phdos = ncfile.phdos
|
||||
|
||||
# plot phonon bands and DOS with LO-TO.
|
||||
# `plot_phonons_lo_to.py` shows how to treat the LO-TO splitting.
|
||||
#%%
|
||||
# Plot phonon bands and DOS with matplotib:
|
||||
|
||||
phbands.plot(title="AlAs Phonon bands and DOS in eV")
|
||||
|
||||
# plot phonon bands with DOS.
|
||||
#%%
|
||||
# For the plotly version use:
|
||||
|
||||
phbands.plotly(title="AlAs Phonon bands and DOS in eV")
|
||||
|
||||
#%%
|
||||
# To plot phonon bands and phonon DOS with matplotlib use:
|
||||
|
||||
phbands.plot_with_phdos(phdos, units="cm-1",
|
||||
title="AlAs Phonon bands + DOS in cm-1")
|
||||
|
||||
# plot phonon DOS.
|
||||
phdos.plot(units="cm-1", title="Phonon DOS and IDOS in cm-1")
|
||||
#%%
|
||||
# For the plotly version use:
|
||||
|
||||
phbands.plotly_with_phdos(phdos, units="cm-1",
|
||||
title="AlAs Phonon bands + DOS in cm-1")
|
||||
|
||||
#%%
|
||||
# Plot the phonon band structure with different color for each line (matplotlib version).
|
||||
|
||||
# Plot the phonon band structure with different color for each line.
|
||||
phbands.plot_colored_matched(units="cm-1",
|
||||
title="AlAs with different color for each line.")
|
||||
|
|
|
@ -12,23 +12,40 @@ We use two files produced by anaddb:
|
|||
|
||||
See also tutorial/lesson_rf2.html
|
||||
"""
|
||||
|
||||
#%%
|
||||
# We start by defining a list with the paths to the PHBST.nc files
|
||||
# In this case, for simplicity, we use the same file but we must
|
||||
# use different labels when adding them to the plotter with the add_phbands method.
|
||||
|
||||
from abipy import abilab
|
||||
import abipy.data as abidata
|
||||
|
||||
# To plot a grid with two band structures:
|
||||
phbst_paths = 2 * [abidata.ref_file("trf2_5.out_PHBST.nc")]
|
||||
|
||||
plotter = abilab.PhononBandsPlotter()
|
||||
plotter.add_phbands("AlAs", phbst_paths[0])
|
||||
plotter.add_phbands("Same AlAs", phbst_paths[1])
|
||||
|
||||
#plotter.combiplot(title="CombiPlot in eV")
|
||||
#%%
|
||||
# At this point, we can use the plotter methods to plot the data:
|
||||
# To produce a grid plot:
|
||||
|
||||
plotter.gridplot(units="eV", title="GridPlot in eV")
|
||||
|
||||
#%%
|
||||
# At this point, we can use the plotter methods to plot the data:
|
||||
|
||||
plotter.boxplot(units="cm-1", title="BoxPlot in cm-1")
|
||||
|
||||
plotter.combiboxplot(units="Ha", title="CombiboxPlot in Ha")
|
||||
|
||||
#plotter.combiplot(title="CombiPlot in eV")
|
||||
|
||||
#%%
|
||||
# To plot a grid with band structures + DOS, use the optional argument `phdos` of add_phbands
|
||||
# The first subplot gets the band dispersion from phbst_paths[0] and the dos from phdos_paths[0]
|
||||
|
||||
phbst_paths = 3 * [abidata.ref_file("trf2_5.out_PHBST.nc")]
|
||||
phdos_paths = 3 * [abidata.ref_file("trf2_5.out_PHDOS.nc")]
|
||||
|
||||
|
@ -37,5 +54,6 @@ plotter.add_phbands("AlAs phbands + DOS", phbst_paths[0], phdos=phdos_paths[0])
|
|||
plotter.add_phbands("Same-data", phbst_paths[1], phdos=phdos_paths[1])
|
||||
plotter.add_phbands("Same-data2", phbst_paths[2], phdos=phdos_paths[2])
|
||||
|
||||
#plotter.combiplot(title="Bands + DOS in eV with combiplot")
|
||||
plotter.gridplot(units="cm-1", tight_layout=True, title="Bands + DOS in cm-1 with gridplot")
|
||||
|
||||
#plotter.combiplot(title="Bands + DOS in eV with combiplot")
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Multiple phonon bands
|
||||
=========================
|
||||
Multiple phonon bands with DDB robot
|
||||
====================================
|
||||
|
||||
This example shows how to plot several phonon band structures on a grid.
|
||||
|
||||
We use two files produced by anaddb:
|
||||
.. important::
|
||||
|
||||
trf2_5.out_PHBST.nc: phonon frequencies on a q-path in the BZ (used to plot the band dispersion)
|
||||
trf2_5.out_PHDOS.nc: phonon DOS compute with anaddb.
|
||||
Note that a **manager.yml** file and an abinit installation are required
|
||||
to run this script as AbiPy needs to invoke anaddb to compute phonons from the DDB file.
|
||||
"""
|
||||
|
||||
#%%
|
||||
# We start by defining a list of DDB files:
|
||||
# obtained with the same structure but different k-mesh and tmear:
|
||||
|
||||
from abipy import abilab
|
||||
import abipy.data as abidata
|
||||
|
||||
import os
|
||||
|
||||
paths = [
|
||||
#"mgb2_444k_0.01tsmear_DDB",
|
||||
#"mgb2_444k_0.02tsmear_DDB",
|
||||
|
@ -28,18 +33,37 @@ paths = [
|
|||
|
||||
paths = [os.path.join(abidata.dirpath, "refs", "mgb2_phonons_nkpt_tsmear", f) for f in paths]
|
||||
|
||||
robot = abilab.DdbRobot()
|
||||
for i, path in enumerate(paths):
|
||||
robot.add_file(path, path)
|
||||
#%%
|
||||
# Now we initialize the DdbRobot from this list of paths:
|
||||
|
||||
robot = abilab.DdbRobot.from_files(paths)
|
||||
print(robot.keys())
|
||||
|
||||
#%%
|
||||
# Now we change the keys associated to the different files
|
||||
# by defining a function that computes the new label from the
|
||||
# info reported in the ddb object.
|
||||
# These lables are then used to generate the legend in the matplotlib plot.
|
||||
|
||||
robot.remap_labels(lambda ddb: "nkpt: %s, tsmear: %.2f" % (ddb.header["nkpt"], ddb.header["tsmear"]))
|
||||
print(robot.keys())
|
||||
|
||||
#%%
|
||||
# Invoke anaddb to build a PhononBands plotter.
|
||||
# We use a small q-mesh for the ph-DOS to speedup the computation:
|
||||
|
||||
r = robot.anaget_phonon_plotters(nqsmall=2)
|
||||
|
||||
#%%
|
||||
# To group the results by tsmear use:
|
||||
|
||||
r.phbands_plotter.gridplot_with_hue("tsmear")
|
||||
|
||||
#%%
|
||||
# If Phonon DOSes are wanted, use:
|
||||
|
||||
r.phbands_plotter.gridplot_with_hue("tsmear", with_dos=True)
|
||||
|
||||
#r.phbands_plotter.gridplot_with_hue("nkpt")
|
||||
#r.phbands_plotter.gridplot()
|
||||
|
||||
robot.close()
|
||||
|
|
|
@ -3,23 +3,41 @@ r"""
|
|||
Projected phonon DOS
|
||||
====================
|
||||
|
||||
This example shows how to plot the projected phonon DOS of AlAs.
|
||||
This example shows how to plot the projected phonon DOS (PJDOS) of AlAs.
|
||||
See tutorial/lesson_rf2.html
|
||||
"""
|
||||
from abipy.abilab import abiopen
|
||||
import abipy.data as abidata
|
||||
|
||||
#%%
|
||||
# Read the Phonon DOS from the netcdf file produced by anaddb with prtdos 2
|
||||
# (alternatively one can use the shell and `abiopen.py OUT_PHDOS.nc -nb`
|
||||
# to open the file in a jupyter notebook.
|
||||
with abiopen(abidata.ref_file("trf2_5.out_PHDOS.nc")) as phdos_file:
|
||||
|
||||
# Plot PJDOS.
|
||||
phdos_file.plot_pjdos_type(units="cm-1", title="AlAs type-projected phonon DOS")
|
||||
from abipy.abilab import abiopen
|
||||
import abipy.data as abidata
|
||||
|
||||
# To have the projection along the cartesian directions (summed over atomic types)
|
||||
phdos_file.plot_pjdos_cartdirs_type(units="Thz", stacked=True,
|
||||
title="Type-projected ph-DOS decomposed along the three Cartesian directions.")
|
||||
phdos_file = abiopen(abidata.ref_file("trf2_5.out_PHDOS.nc"))
|
||||
|
||||
# To plot the PJDOS for all the inequivalent sites.
|
||||
phdos_file.plot_pjdos_cartdirs_site(view="inequivalent", stacked=True)
|
||||
#%%
|
||||
# To plot the PJDOS with matplotlib, use:
|
||||
|
||||
phdos_file.plot_pjdos_type(units="cm-1", title="AlAs type-projected phonon DOS")
|
||||
|
||||
#%%
|
||||
# For the plotly version, use:
|
||||
|
||||
phdos_file.plotly_pjdos_type(units="cm-1", title="AlAs type-projected phonon DOS")
|
||||
|
||||
#%%
|
||||
# To have the projection along the cartesian directions (summed over atomic types), use
|
||||
|
||||
phdos_file.plot_pjdos_cartdirs_type(units="Thz", stacked=True,
|
||||
title="Type-projected ph-DOS decomposed along the three Cartesian directions.")
|
||||
|
||||
#%%
|
||||
# To plot the PJDOS for all the inequivalent sites, use:
|
||||
|
||||
phdos_file.plot_pjdos_cartdirs_site(view="inequivalent", stacked=True)
|
||||
|
||||
#%%
|
||||
# Remember to close the file
|
||||
phdos_file.close()
|
||||
|
|
|
@ -30,7 +30,9 @@ gamma_ev = 1e-3
|
|||
tgen.plot_all(gamma_ev=gamma_ev, title="Diagonal and off-diagonal components")
|
||||
|
||||
tgen.plot(component="diag", reim="re", gamma_ev=gamma_ev, title="Real part, diagonal components")
|
||||
tgen.plotly(component="diag", reim="re", gamma_ev=gamma_ev, title="Real part, diagonal components")
|
||||
|
||||
tgen.plot(component="diag", reim="im", gamma_ev=gamma_ev, title="Imaginary part, diagonal components")
|
||||
tgen.plotly(component="diag", reim="im", gamma_ev=gamma_ev, title="Imaginary part, diagonal components")
|
||||
|
||||
ddb.close()
|
||||
|
|
|
@ -1,28 +1,40 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Phonon Bands with LO-TO
|
||||
=======================
|
||||
Phonon bands with LO-TO from PHBST.nc
|
||||
=====================================
|
||||
|
||||
This example shows how to plot the phonon band structure of AlAs
|
||||
including the LO-TO splitting. See tutorial/lesson_rf2.html
|
||||
including the LO-TO splitting.
|
||||
These resultas tutorial/lesson_rf2.html
|
||||
"""
|
||||
from abipy.abilab import abiopen
|
||||
import abipy.data as abidata
|
||||
|
||||
#%%
|
||||
# Open PHBST file produced by anaddb and extract the phonon bands object.
|
||||
# (alternatively one can use the shell and `abiopen.py OUT_PHBST.nc -nb`
|
||||
# to open the file in a jupyter notebook.
|
||||
|
||||
from abipy.abilab import abiopen
|
||||
import abipy.data as abidata
|
||||
|
||||
with abiopen(abidata.ref_file("ZnSe_hex_886.out_PHBST.nc")) as ncfile:
|
||||
phbands = ncfile.phbands
|
||||
|
||||
#%%
|
||||
# Phonon frequencies with non analytical contributions, if calculated, are saved
|
||||
# in the anaddb.nc file produced by anaddb. The results should be fetched from there
|
||||
# and added to the phonon bands.
|
||||
phbands.read_non_anal_from_file(abidata.ref_file("ZnSe_hex_886.anaddb.nc"))
|
||||
|
||||
# Notice that all the directions starting from or arriving at gamma that are used
|
||||
# in the path should explicitely calculated, even if the values are the same.
|
||||
|
||||
phbands.read_non_anal_from_file(abidata.ref_file("ZnSe_hex_886.anaddb.nc"))
|
||||
|
||||
#%%
|
||||
# Plot the phonon frequencies. Note that the labels for the q-points
|
||||
# are found automatically by searching in an internal database.
|
||||
|
||||
phbands.plot(title="ZnSe with LO-TO splitting")
|
||||
|
||||
#%%
|
||||
# For the plotly version, use:
|
||||
|
||||
phbands.plotly(title="ZnSe with LO-TO splitting")
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Projected phonon DOS
|
||||
====================
|
||||
Debye-Waller and generalized phonon DOS
|
||||
=======================================
|
||||
|
||||
This example shows how to plot the generalized phonon DOS with the mean square
|
||||
displacement tensor in cartesian coords and how to calculate Debye Waller factors
|
||||
as a function of temperature.
|
||||
|
||||
See :cite:`Lee1995` for the further details about the internal implementation and
|
||||
:cite:`Trueblood1996` for the different conventions used by crystallographers.
|
||||
"""
|
||||
|
|
|
@ -6,8 +6,6 @@ Thermodinamic properties
|
|||
This example shows how to compute and plot thermodinamic properties within
|
||||
the harmonic approximation using the phonon DOS produced by anaddb.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from abipy.abilab import abiopen
|
||||
import abipy.data as abidata
|
||||
|
||||
|
@ -20,14 +18,22 @@ print(ncfile.structure)
|
|||
zpe = phdos.zero_point_energy
|
||||
print("Zero point energy:", zpe, zpe.to("J"), zpe.to("Ha"))
|
||||
|
||||
#%%
|
||||
# Compute free energy from 2 to 300 K (20 points)
|
||||
# By default, energies are is eV and thermodynamic quantities are given
|
||||
# on a per-unit-cell basis.
|
||||
f = phdos.get_free_energy(tstart=2, tstop=300, num=20)
|
||||
#f.plot()
|
||||
|
||||
#%%
|
||||
# Plot U, F, S, Cv as a function of T.
|
||||
# Use J/mol units, results are divided by formula_units.
|
||||
phdos.plot_harmonic_thermo(units="Jmol", formula_units=1)
|
||||
|
||||
#%%
|
||||
# Plotly version:
|
||||
phdos.plotly_harmonic_thermo(units="Jmol", formula_units=1)
|
||||
|
||||
#%%
|
||||
# Remember to close the file:
|
||||
ncfile.close()
|
||||
|
|
|
@ -27,3 +27,4 @@ abilab.print_dataframe(df)
|
|||
|
||||
# Plot fit
|
||||
sv.plot()
|
||||
sv.plotly()
|
||||
|
|
|
@ -8,13 +8,18 @@ This example shows how to display the unit cell with matplotlib.
|
|||
from abipy.abilab import abiopen
|
||||
import abipy.data as abidata
|
||||
|
||||
# Extract structure from netcdf file.
|
||||
#%%
|
||||
# Extract structure from the netcdf file:
|
||||
|
||||
with abiopen(abidata.ref_file("sio2_kpath_GSR.nc")) as gsr:
|
||||
structure = gsr.structure
|
||||
|
||||
# Visualize sites structure.
|
||||
#%%
|
||||
# To visualize the structure with matplotlib, use:
|
||||
structure.plot(color_scheme="Jmol")
|
||||
|
||||
# Wrap sites into first unit cell.
|
||||
#%%
|
||||
# To wrap sites into first unit cell, use:
|
||||
|
||||
# sphinx_gallery_thumbnail_number = 2
|
||||
structure.plot(to_unit_cell=True)
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env python
|
||||
r"""
|
||||
Phonon Band structures (Plotly version)
|
||||
=======================================
|
||||
|
||||
This example shows how to plot the phonon band structure of AlAs with plotly.
|
||||
See tutorial/lesson_rf2.html
|
||||
"""
|
||||
from abipy.abilab import abiopen
|
||||
import abipy.data as abidata
|
||||
|
||||
# Open the PHBST file produced by anaddb and get the phonon bands.
|
||||
with abiopen(abidata.ref_file("trf2_5.out_PHBST.nc")) as ncfile:
|
||||
phbands = ncfile.phbands
|
||||
|
||||
# Read the Phonon DOS from the netcd file produced by anaddb (prtdos 2)
|
||||
with abiopen(abidata.ref_file("trf2_5.out_PHDOS.nc")) as ncfile:
|
||||
phdos = ncfile.phdos
|
||||
|
||||
#%%
|
||||
# plot phonon bands and DOS.
|
||||
# `plot_phonons_lo_to.py` shows how to treat the LO-TO splitting.
|
||||
|
||||
phbands.plotly(title="AlAs Phonon bands and DOS in eV")
|
||||
|
||||
#%%
|
||||
# plot phonon bands with DOS.
|
||||
|
||||
phbands.plotly_with_phdos(phdos, units="cm-1", title="AlAs Phonon bands + DOS in cm-1")
|
||||
|
||||
#%%
|
||||
# plot phonon DOS.
|
||||
|
||||
phdos.plotly(units="cm-1", title="Phonon DOS and IDOS in cm-1")
|
||||
|
||||
# Plot the phonon band structure with different color for each line.
|
||||
#phbands.plot_colored_matched(units="cm-1",
|
||||
# title="AlAs with different color for each line.")
|
||||
|
||||
# sphinx_gallery_thumbnail_path = '_static/plotly_logo.png'
|
|
@ -125,6 +125,7 @@ class NscfDdksWork(Work):
|
|||
def from_scf_task(cls, scf_task, ddk_ngkpt, ddk_shiftk, ddk_nband, manager=None):
|
||||
"""
|
||||
Build NscfDdksWork from a scf_task.
|
||||
|
||||
Args:
|
||||
scf_task: GS task. Must produce the DEN file required for the NSCF run.
|
||||
ddk_ngkpt: k-mesh used for the NSCF run and the non self-consistent DDK tasks.
|
||||
|
|
|
@ -85,7 +85,7 @@ class EffMassDFPTWork(Work):
|
|||
"""
|
||||
|
||||
@classmethod
|
||||
def from_scf_input(cls, scf_input, k0_list, effmass_bands_f90, den_node=None, manager=None):
|
||||
def from_scf_input(cls, scf_input, k0_list, effmass_bands_f90, ngfft=None, den_node=None, manager=None):
|
||||
"""
|
||||
Build the Work from an |AbinitInput| representing a GS-SCF calculation.
|
||||
|
||||
|
@ -94,12 +94,13 @@ class EffMassDFPTWork(Work):
|
|||
k0_list: List with the reduced coordinates of the k-points where effective masses are wanted.
|
||||
effmass_bands_f90: (nkpt, 2) array with band range for effmas computation.
|
||||
WARNING: Assumes Fortran convention with indices starting from 1.
|
||||
ngfft: FFT divisions (3 integers). Used to enforce the same FFT mesh in the NSCF run as the one used for GS.
|
||||
den_node: Path to the DEN file or Task object producing a DEN file.
|
||||
Can be used to avoid the initial SCF calculation if a DEN file is already available.
|
||||
If None, a GS calculation is performed.
|
||||
manager: |TaskManager| instance. Use default if None.
|
||||
"""
|
||||
multi = scf_input.make_dfpt_effmass_inputs(k0_list, effmass_bands_f90)
|
||||
multi = scf_input.make_dfpt_effmass_inputs(k0_list, effmass_bands_f90, ngfft=ngfft)
|
||||
nscf_input, effmass_input = multi[0], multi[1]
|
||||
|
||||
new = cls(manager=manager)
|
||||
|
@ -177,10 +178,12 @@ class EffMassAutoDFPTWork(Work):
|
|||
ebands.set_fermie_to_vbm()
|
||||
# Find k0_list and effmass_bands_f90
|
||||
k0_list, effmass_bands_f90 = ebands.get_kpoints_and_band_range_for_edges()
|
||||
den_ngfft = gsr.reader.read_ngfft3()
|
||||
|
||||
# Create the work for effective mass computation with DFPT and add it to the flow.
|
||||
# Keep a reference in generated_effmass_dfpt_work.
|
||||
work = EffMassDFPTWork.from_scf_input(self.scf_input, k0_list, effmass_bands_f90, den_node=self.den_node)
|
||||
work = EffMassDFPTWork.from_scf_input(self.scf_input, k0_list, effmass_bands_f90,
|
||||
ngfft=den_ngfft, den_node=self.den_node)
|
||||
|
||||
self.generated_effmass_dfpt_work = work
|
||||
self.flow.register_work(work)
|
||||
|
|
|
@ -347,10 +347,10 @@ class Flow(Node, NodeContainer, MSONable):
|
|||
flow = pmg_pickle_load(strio)
|
||||
return flow
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, **kwargs):
|
||||
"""Build panel with widgets to interact with the |Flow| either in a notebook or in panel app."""
|
||||
from abipy.panels.flows import FlowPanel
|
||||
return FlowPanel(self).get_panel()
|
||||
return FlowPanel(self).get_panel(**kwargs)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.works)
|
||||
|
@ -2008,9 +2008,28 @@ Use the `abirun.py FLOWDIR history` command to print the log files of the differ
|
|||
|
||||
return work
|
||||
|
||||
def new_work(self, deps=None, manager=None, workdir=None):
|
||||
"""
|
||||
Helper function to add a new empty |Work| and add it to the internal list.
|
||||
Client code is responsible for filling the new work.
|
||||
|
||||
Args:
|
||||
deps: List of :class:`Dependency` objects specifying the dependency of this node.
|
||||
An empy list of deps implies that this node has no dependencies.
|
||||
manager: The |TaskManager| responsible for the submission of the task.
|
||||
If manager is None, we use the `TaskManager` specified during the creation of the work.
|
||||
workdir: The name of the directory used for the |Work|.
|
||||
|
||||
Returns:
|
||||
The registered |Work|.
|
||||
"""
|
||||
work = Work()
|
||||
return self.register_work(work, deps=deps, manager=manager, workdir=workdir)
|
||||
|
||||
def register_work(self, work, deps=None, manager=None, workdir=None):
|
||||
"""
|
||||
Register a new |Work| and add it to the internal list, taking into account possible dependencies.
|
||||
Register a new |Work| and add it to the internal list, taking into account
|
||||
possible dependencies.
|
||||
|
||||
Args:
|
||||
work: |Work| object.
|
||||
|
@ -2392,7 +2411,7 @@ Use the `abirun.py FLOWDIR history` command to print the log files of the differ
|
|||
|
||||
def single_shot(self, check_status=True, **kwargs):
|
||||
"""
|
||||
Use :class:`PyLauncher` to submits one task.
|
||||
Use :class:`PyLauncher` to submit one task.
|
||||
kwargs contains the options passed to the launcher.
|
||||
|
||||
Return: Number of tasks submitted.
|
||||
|
|
|
@ -968,13 +968,15 @@ class Node(metaclass=abc.ABCMeta):
|
|||
def write_json_in_outdir(self, filename, data):
|
||||
"""
|
||||
Write data to json file of basename filename inside the outdir directory of the node.
|
||||
Support MSONable objects.
|
||||
Support MSONable objects. Return path of json file.
|
||||
"""
|
||||
from monty.json import jsanitize
|
||||
data = jsanitize(data, strict=False)
|
||||
path = self.outdir.path_in(filename)
|
||||
json_pretty_dump(data, path)
|
||||
|
||||
return path
|
||||
|
||||
##########################
|
||||
### Abstract protocol ####
|
||||
##########################
|
||||
|
|
|
@ -1018,7 +1018,7 @@ limits:
|
|||
# stderr is redirected to mods.err file.
|
||||
# module load 2>> mods.err
|
||||
se.add_comment("Load Modules")
|
||||
se.add_line("module purge")
|
||||
se.add_line("module --force purge")
|
||||
se.load_modules(self.modules)
|
||||
se.add_emptyline()
|
||||
|
||||
|
|
|
@ -1213,9 +1213,12 @@ class AbinitBuild(object):
|
|||
# Temporary hack for abinit v9
|
||||
return True
|
||||
|
||||
print("self.info", self.info)
|
||||
|
||||
# Parse info.
|
||||
# flavor options were used in Abinit v8
|
||||
for line in self.info.splitlines():
|
||||
print(line)
|
||||
if "Version" in line: self.version = line.split()[-1]
|
||||
if "TRIO flavor" in line:
|
||||
self.has_netcdf = "netcdf" in line
|
||||
|
@ -1240,7 +1243,7 @@ class AbinitBuild(object):
|
|||
# Temporary hack for abinit v9
|
||||
#from abipy.core.testing import cmp_version
|
||||
#if cmp_version(self.version, "9.0.0", op=">="):
|
||||
# self.has_netcdf = True
|
||||
self.has_netcdf = True
|
||||
|
||||
def __str__(self):
|
||||
lines = []
|
||||
|
|
|
@ -302,13 +302,17 @@ class FlowTest(FlowUnitTest):
|
|||
hello_flow = flowtk.Flow(workdir=self.mkdtemp())
|
||||
hello_flow.register_scf_task(scf_input, append=True)
|
||||
hello_flow.register_nscf_task(nscf_input, deps={hello_flow[0][0]: "DEN"}, append=True)
|
||||
|
||||
#flow[0].get_graphviz_dirtree()
|
||||
#abilab.print_doc(flowtk.PhononWork)
|
||||
|
||||
hello_flow = flowtk.Flow(workdir=self.mkdtemp())
|
||||
hello_flow.register_scf_task(scf_input, append=True)
|
||||
assert len(hello_flow) == 1
|
||||
hello_flow.register_nscf_task(nscf_input, deps={hello_flow[0][0]: "DEN"}, append=False)
|
||||
assert len(hello_flow) == 2
|
||||
empty_work = hello_flow.new_work()
|
||||
assert len(empty_work) == 0
|
||||
assert len(hello_flow) == 3
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -461,9 +461,10 @@ class NodeContainer(metaclass=abc.ABCMeta):
|
|||
"""Register an electron-phonon task."""
|
||||
kwargs["task_class"] = EphTask
|
||||
eph_inp = args[0]
|
||||
seq_manager = TaskManager.from_user_config().new_with_fixed_mpi_omp(1, 1)
|
||||
if eph_inp.get("eph_frohlichm", 0) != 0 or abs(eph_inp.get("eph_task", 0)) == 15:
|
||||
# FIXME: Hack to run task in sequential if calculation does not support MPI with nprocs > 1.
|
||||
# FIXME: Hack to run task in sequential since this calculation does
|
||||
# not support MPI with nprocs > 1.
|
||||
seq_manager = TaskManager.from_user_config().new_with_fixed_mpi_omp(1, 1)
|
||||
kwargs.update({"manager": seq_manager})
|
||||
|
||||
if eph_inp.get("eph_task",0) == -4:
|
||||
|
@ -1115,7 +1116,7 @@ class RelaxWork(Work):
|
|||
|
||||
class G0W0Work(Work):
|
||||
"""
|
||||
Work for general G0W0 calculations.
|
||||
Work for generic G0W0 calculations.
|
||||
All input can be either single inputs or lists of inputs
|
||||
|
||||
.. rubric:: Inheritance Diagram
|
||||
|
@ -1484,8 +1485,8 @@ class PhononWork(Work, MergeDdb):
|
|||
This work consists of nirred Phonon tasks where nirred is
|
||||
the number of irreducible atomic perturbations for a given set of q-points.
|
||||
It provides the callback method (on_all_ok) that calls mrgddb (mrgdv) to merge
|
||||
all the partial DDB (POT) files produced. The two files are available in the
|
||||
output directory of the Work.
|
||||
all the partial DDB (POT) files produced.
|
||||
The two files are available in the output directory of the Work.
|
||||
|
||||
.. rubric:: Inheritance Diagram
|
||||
.. inheritance-diagram:: PhononWork
|
||||
|
@ -1493,7 +1494,7 @@ class PhononWork(Work, MergeDdb):
|
|||
|
||||
@classmethod
|
||||
def from_scf_task(cls, scf_task, qpoints, is_ngqpt=False, tolerance=None, with_becs=False,
|
||||
ddk_tolerance=None, manager=None):
|
||||
ddk_tolerance=None, prtwf=-1, manager=None):
|
||||
"""
|
||||
Construct a `PhononWork` from a |ScfTask| object.
|
||||
The input file for phonons is automatically generated from the input of the ScfTask.
|
||||
|
@ -1509,6 +1510,11 @@ class PhononWork(Work, MergeDdb):
|
|||
with_becs: Activate calculation of Electric field and Born effective charges.
|
||||
ddk_tolerance: dict {"varname": value} with the tolerance used in the DDK run if with_becs.
|
||||
None to use AbiPy default.
|
||||
prtwf: Controls the output of the first-order WFK.
|
||||
By default we set it to -1 when q != 0 so that AbiPy is still able
|
||||
to restart the DFPT task if the calculation is not converged (worst case scenario)
|
||||
but we avoid the output of the 1-st WFK if the calculation converged successfully.
|
||||
Non-linear DFT applications should not be affected since they assume q == 0.
|
||||
manager: |TaskManager| object.
|
||||
"""
|
||||
if not isinstance(scf_task, ScfTask):
|
||||
|
@ -1523,16 +1529,19 @@ class PhononWork(Work, MergeDdb):
|
|||
new.add_becs_from_scf_task(scf_task, ddk_tolerance, ph_tolerance=tolerance)
|
||||
|
||||
for qpt in qpoints:
|
||||
if with_becs and np.sum(qpt ** 2) < 1e-12: continue
|
||||
is_gamma = np.sum(qpt ** 2) < 1e-12
|
||||
if with_becs and is_gamma: continue
|
||||
multi = scf_task.input.make_ph_inputs_qpoint(qpt, tolerance=tolerance)
|
||||
for ph_inp in multi:
|
||||
# Here we set the value of prtwf for the DFPT tasks if q != Gamma.
|
||||
if not is_gamma: ph_inp.set_vars(prtwf=prtwf)
|
||||
new.register_phonon_task(ph_inp, deps={scf_task: "WFK"})
|
||||
|
||||
return new
|
||||
|
||||
@classmethod
|
||||
def from_scf_input(cls, scf_input, qpoints, is_ngqpt=False, tolerance=None,
|
||||
with_becs=False, ddk_tolerance=None, manager=None):
|
||||
with_becs=False, ddk_tolerance=None, prtwf=-1, manager=None):
|
||||
"""
|
||||
Similar to `from_scf_task`, the difference is that this method requires
|
||||
an input for SCF calculation. A new |ScfTask| is created and added to the Work.
|
||||
|
@ -1551,9 +1560,12 @@ class PhononWork(Work, MergeDdb):
|
|||
new.add_becs_from_scf_task(scf_task, ddk_tolerance, ph_tolerance=tolerance)
|
||||
|
||||
for qpt in qpoints:
|
||||
if with_becs and np.sum(qpt ** 2) < 1e-12: continue
|
||||
is_gamma = np.sum(qpt ** 2) < 1e-12
|
||||
if with_becs and is_gamma: continue
|
||||
multi = scf_task.input.make_ph_inputs_qpoint(qpt, tolerance=tolerance)
|
||||
for ph_inp in multi:
|
||||
# Here we set the value of prtwf for the DFPT tasks if q != Gamma.
|
||||
if not is_gamma: ph_inp.set_vars(prtwf=prtwf)
|
||||
new.register_phonon_task(ph_inp, deps={scf_task: "WFK"})
|
||||
|
||||
return new
|
||||
|
@ -1562,7 +1574,7 @@ class PhononWork(Work, MergeDdb):
|
|||
def on_all_ok(self):
|
||||
"""
|
||||
This method is called when all the q-points have been computed.
|
||||
Ir runs `mrgddb` in sequential on the local machine to produce
|
||||
It runs `mrgddb` in sequential on the local machine to produce
|
||||
the final DDB file in the outdir of the |Work|.
|
||||
"""
|
||||
# Merge DDB files.
|
||||
|
@ -2006,12 +2018,14 @@ class ConducWork(Work):
|
|||
"""
|
||||
Workflow for the computation of electrical conductivity.
|
||||
|
||||
Can be called from :
|
||||
Can be called from:
|
||||
1. MultiDataset and PhononWork
|
||||
2. MultiDataset, DDB filepath and DVDB filepath.
|
||||
|
||||
Can use Kerange Capability using withKerange=True
|
||||
|
||||
This work consists of 3 tasks or 5 tasks with kerange :
|
||||
This work consists of 3 tasks or 5 tasks with kerange:
|
||||
|
||||
1. SCF GS
|
||||
2. NSCF
|
||||
3. Kerange (Kerange only)
|
||||
|
@ -2023,7 +2037,7 @@ class ConducWork(Work):
|
|||
def from_phwork(cls, phwork, multi, nbr_proc=None, flow=None, with_kerange=False,
|
||||
omp_nbr_thread=1, manager=None):
|
||||
"""
|
||||
Construct a |ConducWork| from a |PhononWork| and |MultiDataset|.
|
||||
Construct a ConducWork from a |PhononWork| and |MultiDataset|.
|
||||
|
||||
Args:
|
||||
phwork: a |PhononWork| object calculating the DDB and DVDB files.
|
||||
|
@ -2081,7 +2095,7 @@ class ConducWork(Work):
|
|||
def from_filepath(cls, ddb_path, dvdb_path, multi, nbr_proc=None, flow=None,
|
||||
with_kerange=False, omp_nbr_thread=1, manager=None):
|
||||
"""
|
||||
Construct a |ConducWork| from previously calculated DDB/DVDB file and |MultiDataset|.
|
||||
Construct a ConducWork from previously calculated DDB/DVDB file and |MultiDataset|.
|
||||
|
||||
Args:
|
||||
multi: a |MultiDataset| object containing a list of 3 datasets or 5 with Kerange.
|
||||
|
|
|
@ -2,6 +2,28 @@ TODO list:
|
|||
|
||||
## High priority
|
||||
|
||||
* Add new section to manager.yml that allows users to customize limits according
|
||||
to task.__class__.__name__.
|
||||
Possible Yaml syntax for `task_class_limits`:
|
||||
|
||||
limits:
|
||||
min_cores: 1
|
||||
max_cores: 1000
|
||||
timelimit: 2:0:0
|
||||
|
||||
task_class_limits:
|
||||
# TaskClassName --> dict with new limits
|
||||
# Accept absolute values or `scale_name` syntax to scale `name` (mutually exclusive)
|
||||
# If a new limit is not specified, the global value is used.
|
||||
#
|
||||
NscfTask: {scale_max_cores: 0.5, scale_timelimit: 0.2}
|
||||
KerangeTask: {max_cores: 2, timelimit: 0:5:0}
|
||||
|
||||
* Implement Task modifier i.e. operations that change the input file if some condition occurs.
|
||||
This extra logic is require to handle problematic cases in which for instance the ScfTask does not converge
|
||||
and modification in the input file are required
|
||||
For instance, one may need to increase nline and/or diemac before restarting.
|
||||
|
||||
* Use angdeg instead of rprimd in structure_to_abivars if hex or rhomboedral lattice
|
||||
(tricky because input settings should be preserved)
|
||||
|
||||
|
@ -26,14 +48,12 @@ TODO list:
|
|||
* Refactor wrappers for mrgddb and mrgdvdb (problems with subprocess when
|
||||
merging large number of partial files (likely due to Popen with large stderr/stdout)
|
||||
|
||||
* Move to new version of APSscheduler
|
||||
|
||||
* BECS: 3x3 Tensor is not symmetric. Remove get_voigt_dataframe
|
||||
|
||||
* Parse stderr to detect runtime errors such as
|
||||
* Parse stderr to detect runtime errors such as
|
||||
|
||||
forrtl: severe (24): end-of-file during read, unit 5, file /proc/59090/fd/0
|
||||
Image PC Routine Line Source
|
||||
Image PC Routine Line Source
|
||||
abinit 0000000008914AC2 for__io_return Unknown Unknown
|
||||
abinit 000000000894378D for_read_seq_fmt Unknown Unknown
|
||||
abinit 000000000194409E Unknown Unknown Unknown
|
||||
|
@ -45,13 +65,15 @@ TODO list:
|
|||
|
||||
and kill the scheduler else the code gets stuck here (issue reported on lemaitre3)
|
||||
|
||||
* Remove/check the usage of line_density. Use ndivsm < 0 to activate line_density a la pymatgen.
|
||||
|
||||
|
||||
## Medium priority
|
||||
|
||||
* Add support for PSML/UPF format
|
||||
|
||||
* Add support for new Abinit9 interface (getden_path, getwfk_path, pp_dirpath and pseudos)
|
||||
but remember that strings in the input should not be too long.
|
||||
but remember that strings in the input should not be too long.
|
||||
Use common root for pseudos, what about getwfk_path? Need to refactor treatment of string lengths in Abinit!
|
||||
|
||||
* Interface abitk with AbiPy to compute DOS with tetra.
|
||||
|
|
|
@ -133,7 +133,7 @@ def itest_phonon_flow(fwp, tvars):
|
|||
assert atask.status == atask.S_OK
|
||||
|
||||
# These output files should be produced in the task workdir.
|
||||
# Actually they should be in outdir but anaddb uses different conventions.
|
||||
# Actually they should be in the outdir but anaddb uses different conventions.
|
||||
assert len(atask.wdir.list_filepaths(wildcard="*PHBST.nc")) == 1
|
||||
assert len(atask.wdir.list_filepaths(wildcard="*PHDOS.nc")) == 1
|
||||
|
||||
|
@ -160,7 +160,8 @@ def itest_phonon_restart(fwp):
|
|||
tolvrs=1.0e-5,
|
||||
)
|
||||
|
||||
multi = abilab.MultiDataset(structure=structure, pseudos=abidata.pseudos("13al.981214.fhi", "33as.pspnc"),
|
||||
multi = abilab.MultiDataset(structure=structure,
|
||||
pseudos=abidata.pseudos("13al.981214.fhi", "33as.pspnc"),
|
||||
ndtset=1 + len(qpoints))
|
||||
|
||||
multi.set_vars(global_vars)
|
||||
|
@ -179,7 +180,7 @@ def itest_phonon_restart(fwp):
|
|||
#kptopt 2 # Automatic generation of k points, taking
|
||||
|
||||
# i == 0 --> restart from WFK
|
||||
if i == 1: multi[i+1].set_vars(prtwf=-1, nstep=5) # Restart with WFK and smart- io.
|
||||
if i == 1: multi[i+1].set_vars(prtwf=-1, nstep=5) # Restart with WFK and smart-io.
|
||||
if i == 2: multi[i+1].set_vars(prtwf=0, nstep=8) # Restart from 1DEN. Too long --> disabled.
|
||||
|
||||
all_inps = multi.split_datasets()
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,44 +1,50 @@
|
|||
""""Panels for DDB files."""
|
||||
|
||||
import sys
|
||||
import param
|
||||
import panel as pn
|
||||
import panel.widgets as pnw
|
||||
import bokeh.models.widgets as bkw
|
||||
|
||||
from abipy.panels.core import AbipyParameterized, ButtonContext, mpl, ply, df
|
||||
from abipy.panels.core import (AbipyParameterized, HasStructureParams, BaseRobotPanel,
|
||||
mpl, ply, dfc, depends_on_btn_click)
|
||||
from abipy.dfpt.ddb import PhononBandsPlotter
|
||||
|
||||
|
||||
class HasAnaddbParams(AbipyParameterized):
|
||||
class HasAnaddbParams(param.Parameterized):
|
||||
"""
|
||||
Base class for panel classes requiring widgets to invoke Anaddb via AbiPy.
|
||||
Mixin for panel classes requiring widgets to invoke Anaddb via AbiPy.
|
||||
Used, for instance, by DdbFilePanel and DdbRobotPanel so that we don't have to
|
||||
repeat the same widget stuff over and over agains.
|
||||
repeat the same parameters over and over again.
|
||||
"""
|
||||
verbose = param.Integer(0, bounds=(0, None), doc="Verbosity level")
|
||||
mpi_procs = param.Integer(1, bounds=(1, None), doc="Number of MPI processes used in anaddb")
|
||||
|
||||
nqsmall = param.Integer(10, bounds=(1, None), doc="Number of divisions for smallest vector to generate Q-mesh")
|
||||
ndivsm = param.Integer(5, bounds=(None, None), doc="Number of divisions for smallest segment in q-path")
|
||||
ndivsm = param.Integer(5, bounds=(None, None), doc="Number of divisions for smallest vector to generate Q-path")
|
||||
lo_to_splitting = param.ObjectSelector(default="automatic", objects=["automatic", True, False])
|
||||
chneut = param.ObjectSelector(default=1, objects=[0, 1, 2], doc="Abinit variable")
|
||||
dipdip = param.ObjectSelector(default=1, objects=[0, 1, -1], doc="Abinit variable")
|
||||
# TODO: Add this widget, need to update anaget API.
|
||||
#dipquad = param.ObjectSelector(default=0, objects=[0, 1], doc="Abinit variable")
|
||||
#quadquad = param.ObjectSelector(default=0, objects=[0, 1], doc="Abinit variable")
|
||||
asr = param.ObjectSelector(default=2, objects=[0, 1, 2], doc="Abinit variable")
|
||||
units = param.ObjectSelector(default="eV", objects=["eV", "meV", "Ha", "cm-1", "Thz"], doc="Energy units")
|
||||
|
||||
dos_method = param.ObjectSelector(default="tetra", objects=["tetra", "gaussian"], doc="Integration method for DOS")
|
||||
temp_range = pnw.RangeSlider(name="T-range", start=0.0, end=1000, value=(0.0, 300.0), step=20)
|
||||
temp_range = param.Range(default=(0.0, 300.0), bounds=(0, 1000), doc="Temperature range in K.")
|
||||
|
||||
gamma_ev = param.Number(1e-4, bounds=(1e-20, None), doc="Phonon linewidth in eV")
|
||||
w_range = pnw.RangeSlider(name="Frequency range (eV)", start=0.0, end=1.0,
|
||||
value=(0.0, 0.1), step=0.001)
|
||||
w_range = param.Range(default=(0.0, 0.1), bounds=(0.0, 1.0), doc="Frequency range (eV)")
|
||||
|
||||
# FIXME
|
||||
nqsmall_list = pnw.LiteralInput(name='nsmalls (python list)', value=[10, 20, 30], type=list)
|
||||
#nqqpt = pnw.LiteralInput(name='nsmalls (list)', value=[10, 20, 30], type=list)
|
||||
|
||||
warning_md = pn.pane.Markdown(
|
||||
# Base buttons
|
||||
plot_check_asr_dipdip_btn = pnw.Button(name="Compute phonons with/wo ASR and DIPDIP", button_type='primary')
|
||||
|
||||
warning = pn.pane.Markdown(
|
||||
"""
|
||||
Refresh the page if plotly figures are not shown.
|
||||
|
||||
Note that widgets for input variables such as *asr*, *chneut*, *dipdip*, *dos_method*, *etc.*
|
||||
are **shared by the different tabs**.
|
||||
|
||||
|
@ -51,10 +57,6 @@ the results/figures are stil computed with the **old input variables** and you w
|
|||
recompute the new results by clicking the button.
|
||||
""", name="warning")
|
||||
|
||||
|
||||
# Base buttons
|
||||
plot_check_asr_dipdip_btn = pnw.Button(name="Compute phonons with/wo ASR and DIPDIP", button_type='primary')
|
||||
|
||||
def kwargs_for_anaget_phbst_and_phdos_files(self, **extra_kwargs):
|
||||
"""
|
||||
Return the parameters require to invoke anaget_phbst_and_phdos_files
|
||||
|
@ -70,323 +72,324 @@ recompute the new results by clicking the button.
|
|||
return d
|
||||
|
||||
|
||||
class DdbFilePanel(HasAnaddbParams):
|
||||
class DdbFilePanel(HasStructureParams, HasAnaddbParams):
|
||||
"""
|
||||
A panel to analyze a |DdbFile|. Provides widgets to invoke anaddb and visualize the results.
|
||||
A panel to analyze a |DdbFile|.
|
||||
Provides widgets to invoke anaddb and visualize the results.
|
||||
"""
|
||||
|
||||
# Buttons
|
||||
get_epsinf_btn = pnw.Button(name="Compute", button_type='primary')
|
||||
plot_phbands_btn = pnw.Button(name="Plot Bands and DOS", button_type='primary')
|
||||
plot_eps0w_btn = pnw.Button(name="Plot eps0(omega)", button_type='primary')
|
||||
plot_vsound_btn = pnw.Button(name="Calculate speed of sound", button_type='primary')
|
||||
|
||||
plot_ifc_btn = pnw.Button(name="Compute IFC(R)", button_type='primary')
|
||||
plot_phbands_quad_btn = pnw.Button(name="Plot PHbands with/without quadrupoles", button_type='primary')
|
||||
plot_dos_vs_qmesh_btn = pnw.Button(name="Plot PHDos vs Qmesh", button_type='primary')
|
||||
|
||||
def __init__(self, ddb, **params):
|
||||
super().__init__(**params)
|
||||
self.ddb = ddb
|
||||
|
||||
@param.depends('get_epsinf_btn.clicks')
|
||||
# Add buttons
|
||||
self.get_epsinf_btn = pnw.Button(name="Compute", button_type='primary')
|
||||
self.plot_phbands_btn = pnw.Button(name="Plot Bands and DOS", button_type='primary')
|
||||
self.plot_eps0w_btn = pnw.Button(name="Plot eps0(omega)", button_type='primary')
|
||||
self.plot_vsound_btn = pnw.Button(name="Calculate speed of sound", button_type='primary')
|
||||
self.plot_ifc_btn = pnw.Button(name="Compute IFC(R)", button_type='primary')
|
||||
self.plot_phbands_quad_btn = pnw.Button(name="Plot PHbands with/without quadrupoles", button_type='primary')
|
||||
self.plot_dos_vs_qmesh_btn = pnw.Button(name="Plot PHDos vs Qmesh", button_type='primary')
|
||||
|
||||
self.stacked_pjdos = pnw.Checkbox(name="Stacked PJDOS", value=True)
|
||||
|
||||
super().__init__(**params)
|
||||
|
||||
@property
|
||||
def structure(self):
|
||||
"""Structure object provided by subclass."""
|
||||
return self.ddb.structure
|
||||
|
||||
@depends_on_btn_click('get_epsinf_btn')
|
||||
def get_epsinf(self):
|
||||
"""Compute eps_infinity and Born effective charges from DDB."""
|
||||
if self.get_epsinf_btn.clicks == 0: return
|
||||
|
||||
with ButtonContext(self.get_epsinf_btn):
|
||||
epsinf, becs = self.ddb.anaget_epsinf_and_becs(chneut=self.chneut,
|
||||
mpi_procs=self.mpi_procs, verbose=self.verbose)
|
||||
epsinf, becs = self.ddb.anaget_epsinf_and_becs(chneut=self.chneut,
|
||||
mpi_procs=self.mpi_procs, verbose=self.verbose)
|
||||
|
||||
gen, inp = self.ddb.anaget_dielectric_tensor_generator(asr=self.asr, chneut=self.chneut, dipdip=self.dipdip,
|
||||
mpi_procs=self.mpi_procs, verbose=self.verbose,
|
||||
return_input=True)
|
||||
gen, inp = self.ddb.anaget_dielectric_tensor_generator(asr=self.asr, chneut=self.chneut, dipdip=self.dipdip,
|
||||
mpi_procs=self.mpi_procs, verbose=self.verbose,
|
||||
return_input=True)
|
||||
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
#df_kwargs = dict(auto_edit=False, autosize_mode="fit_viewport")
|
||||
df_kwargs = {}
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
#df_kwargs = dict(auto_edit=False, autosize_mode="fit_viewport")
|
||||
df_kwargs = {}
|
||||
|
||||
eps0 = gen.tensor_at_frequency(w=0, gamma_ev=self.gamma_ev)
|
||||
ca(r"## $\epsilon^0$ in Cart. coords (computed with Gamma_eV):")
|
||||
ca(df(eps0.get_dataframe(cmode="real"), **df_kwargs))
|
||||
ca(r"## $\epsilon^\infty$ in Cart. coords:")
|
||||
ca(df(epsinf.get_dataframe(), **df_kwargs))
|
||||
ca("## Born effective charges in Cart. coords:")
|
||||
ca(df(becs.get_voigt_dataframe(), **df_kwargs))
|
||||
ca("## Anaddb input file.")
|
||||
ca(pn.pane.HTML(inp._repr_html_()))
|
||||
eps0 = gen.tensor_at_frequency(w=0, gamma_ev=self.gamma_ev)
|
||||
ca(r"## $\epsilon^0$ in Cart. coords (computed with Gamma_eV):")
|
||||
ca(dfc(eps0.get_dataframe(cmode="real"), **df_kwargs))
|
||||
ca(r"## $\epsilon^\infty$ in Cart. coords:")
|
||||
ca(dfc(epsinf.get_dataframe(), **df_kwargs))
|
||||
ca("## Born effective charges in Cart. coords:")
|
||||
ca(dfc(becs.get_voigt_dataframe(), **df_kwargs))
|
||||
ca("## Anaddb input file.")
|
||||
ca(pn.pane.HTML(inp._repr_html_()))
|
||||
|
||||
return col
|
||||
return col
|
||||
|
||||
@param.depends('plot_eps0w_btn.clicks')
|
||||
@depends_on_btn_click('plot_eps0w_btn')
|
||||
def plot_eps0w(self):
|
||||
"""Compute eps0(omega) from DDB and plot the results."""
|
||||
if self.plot_eps0w_btn.clicks == 0: return
|
||||
gen, inp = self.ddb.anaget_dielectric_tensor_generator(asr=self.asr, chneut=self.chneut, dipdip=self.dipdip,
|
||||
mpi_procs=self.mpi_procs, verbose=self.verbose,
|
||||
return_input=True)
|
||||
ws = self.w_range
|
||||
w_max = ws[1]
|
||||
if w_max == 1.0: w_max = None # Will compute w_max in plot routine from ph freqs.
|
||||
|
||||
with ButtonContext(self.plot_eps0w_btn):
|
||||
gen, inp = self.ddb.anaget_dielectric_tensor_generator(asr=self.asr, chneut=self.chneut, dipdip=self.dipdip,
|
||||
mpi_procs=self.mpi_procs, verbose=self.verbose,
|
||||
return_input=True)
|
||||
ws = self.w_range.value
|
||||
w_max = ws[1]
|
||||
if w_max == 1.0: w_max = None # Will compute w_max in plot routine from ph freqs.
|
||||
def p(component, reim):
|
||||
# Matplotlib
|
||||
#fig = gen.plot(w_min=ws[0], w_max=w_max, gamma_ev=self.gamma_ev, num=500, component=component,
|
||||
# reim=reim, units=self.units, **self.mpl_kwargs)
|
||||
#return mpl(fig)
|
||||
fig = gen.plotly(w_min=ws[0], w_max=w_max, gamma_ev=self.gamma_ev, num=500, component=component,
|
||||
reim=reim, units=self.units, show=False)
|
||||
return ply(fig, with_help=False)
|
||||
|
||||
def p(component, reim):
|
||||
return gen.plot(w_min=ws[0], w_max=w_max, gamma_ev=self.gamma_ev, num=500, component=component,
|
||||
reim=reim, units=self.units, **self.fig_kwargs)
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
|
||||
# Build grid
|
||||
gspec = pn.GridSpec(sizing_mode='scale_width')
|
||||
gspec[0, 0] = p("diag", "re")
|
||||
gspec[0, 1] = p("diag", "im")
|
||||
gspec[1, 0] = p("offdiag", "re")
|
||||
gspec[1, 1] = p("offdiag", "im")
|
||||
gspec[2, :] = gen.get_oscillator_dataframe(reim="all", tol=1e-6)
|
||||
# Add HTML pane with input.
|
||||
gspec[3, 0] = pn.pane.HTML(inp._repr_html_())
|
||||
# Add figures
|
||||
ca("## epsilon(w):")
|
||||
ca(p("diag", "re"))
|
||||
ca(p("diag", "im"))
|
||||
ca(p("offdiag", "re"))
|
||||
ca(p("offdiag", "im"))
|
||||
|
||||
return gspec
|
||||
#gspec[2, :] = gen.get_oscillator_dataframe(reim="all", tol=1e-6)
|
||||
# TODO: FIX
|
||||
# TypeError: Object of type complex is not JSON serializable
|
||||
#dfc(gen.get_oscillator_dataframe(reim="all", tol=1e-6))
|
||||
ca("## Oscillator matrix elements:")
|
||||
ca(gen.get_oscillator_dataframe(reim="all", tol=1e-6))
|
||||
# Add HTML pane with input.
|
||||
ca("## Anaddb input file:")
|
||||
ca(pn.pane.HTML(inp._repr_html_()))
|
||||
|
||||
@param.depends('plot_phbands_btn.clicks')
|
||||
def plot_phbands_and_phdos(self, event=None):
|
||||
#return gspec
|
||||
return col
|
||||
|
||||
@depends_on_btn_click('plot_phbands_btn')
|
||||
def plot_phbands_and_phdos(self):
|
||||
"""Compute phonon bands and DOSes from DDB and plot the results."""
|
||||
if self.plot_phbands_btn.clicks == 0: return
|
||||
|
||||
with ButtonContext(self.plot_phbands_btn):
|
||||
# Computing phbands
|
||||
kwargs = self.kwargs_for_anaget_phbst_and_phdos_files(return_input=True)
|
||||
# Computing phbands
|
||||
kwargs = self.kwargs_for_anaget_phbst_and_phdos_files(return_input=True)
|
||||
|
||||
with self.ddb.anaget_phbst_and_phdos_files(**kwargs) as g:
|
||||
phbst_file, phdos_file = g
|
||||
phbands, phdos = phbst_file.phbands, phdos_file.phdos
|
||||
with self.ddb.anaget_phbst_and_phdos_files(**kwargs) as g:
|
||||
phbst_file, phdos_file = g
|
||||
phbands, phdos = phbst_file.phbands, phdos_file.phdos
|
||||
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
|
||||
ca("## Phonon band structure and DOS:")
|
||||
ca(ply(phbands.plotly_with_phdos(phdos, units=self.units, show=False)))
|
||||
#ca(mpl(phbands.plot_with_phdos(phdos, units=self.units, **self.fig_kwargs)))
|
||||
#ca(mpl(phdos_file.plot_pjdos_type(units=self.units, exchange_xy=True, **self.fig_kwargs)))
|
||||
#ca(mpl(phdos_file.msqd_dos.plot(units=self.units, **self.fig_kwargs)))
|
||||
temps = self.temp_range.value
|
||||
ca("## Thermodynamic properties in the harmonic approximation:")
|
||||
#ca(phdos.plot_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, **self.fig_kwargs))
|
||||
ca(ply(phdos.plotly_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, show=False)))
|
||||
#msqd_dos.plot_tensor(**self.fig_kwargs)
|
||||
#ca(mpl(phbands.plot_with_phdos(phdos, units=self.units, **self.mpl_kwargs)))
|
||||
|
||||
# Add HTML pane with input
|
||||
ca("## Brillouin zone and q-path:")
|
||||
#qpath_pane = mpl(phbands.qpoints.plot(**self.mpl_kwargs), with_divider=False)
|
||||
qpath_pane = ply(phbands.qpoints.plotly(show=False), with_divider=False)
|
||||
df_qpts = phbands.qpoints.get_highsym_datataframe()
|
||||
ca(pn.Row(qpath_pane, df_qpts))
|
||||
ca(pn.layout.Divider())
|
||||
|
||||
ca("## Type-projected phonon DOS:")
|
||||
#ca(mpl(phdos_file.plot_pjdos_type(units=self.units, **self.mpl_kwargs)))
|
||||
ca(ply(phdos_file.plotly_pjdos_type(units=self.units, stacked=self.stacked_pjdos.value, show=False)))
|
||||
#ca(mpl(phdos_file.msqd_dos.plot(units=self.units, **self.mpl_kwargs)))
|
||||
ca("## Thermodynamic properties in the harmonic approximation:")
|
||||
temps = self.temp_range
|
||||
#ca(phdos.plot_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, **self.mpl_kwargs))
|
||||
ca(ply(phdos.plotly_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, show=False)))
|
||||
#msqd_dos.plot_tensor(**self.mpl_kwargs)
|
||||
|
||||
# Add Anaddb input file
|
||||
ca("## Anaddb input file:")
|
||||
ca(pn.pane.HTML(g.input._repr_html_()))
|
||||
ca(self.html_with_clipboard_btn(g.input._repr_html_()))
|
||||
|
||||
return col
|
||||
|
||||
@param.depends('plot_vsound_btn.clicks')
|
||||
@depends_on_btn_click('plot_vsound_btn')
|
||||
def plot_vsound(self):
|
||||
"""
|
||||
Compute the speed of sound by fitting phonon frequencies
|
||||
along selected directions by linear least-squares fit.
|
||||
"""
|
||||
if self.plot_vsound_btn.clicks == 0: return
|
||||
col = pn.Column(sizing_mode="stretch_width"); ca = col.append
|
||||
|
||||
with ButtonContext(self.plot_vsound_btn):
|
||||
from abipy.dfpt.vsound import SoundVelocity
|
||||
sv = SoundVelocity.from_ddb(self.ddb.filepath, num_points=20, qpt_norm=0.1,
|
||||
ignore_neg_freqs=True, asr=self.asr, chneut=self.chneut, dipdip=self.dipdip,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs)
|
||||
from abipy.dfpt.vsound import SoundVelocity
|
||||
sv = SoundVelocity.from_ddb(self.ddb.filepath, num_points=20, qpt_norm=0.1,
|
||||
ignore_neg_freqs=True, asr=self.asr, chneut=self.chneut, dipdip=self.dipdip,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs)
|
||||
|
||||
# Insert results in grid.
|
||||
gspec = pn.GridSpec(sizing_mode='scale_width')
|
||||
gspec[0, :1] = sv.get_dataframe()
|
||||
gspec[1, :1] = sv.plot(**self.fig_kwargs)
|
||||
ca("## Linear least-squares fit:")
|
||||
#ca(mpl(sv.plot(**self.mpl_kwargs)))
|
||||
ca(ply(sv.plotly(show=False)))
|
||||
ca("## Speed of sound computed along different q-directions in reduced coords:")
|
||||
ca(dfc(sv.get_dataframe()))
|
||||
|
||||
return gspec
|
||||
return col
|
||||
|
||||
@param.depends('plot_check_asr_dipdip_btn.clicks')
|
||||
@depends_on_btn_click('plot_check_asr_dipdip_btn')
|
||||
def plot_without_asr_dipdip(self):
|
||||
"""
|
||||
Compare phonon bands and DOSes computed with/without the acoustic sum rule
|
||||
and the treatment of the dipole-dipole interaction in the dynamical matrix.
|
||||
Requires DDB file with eps_inf, BECS.
|
||||
"""
|
||||
if self.plot_check_asr_dipdip_btn.clicks == 0: return
|
||||
asr_plotter = self.ddb.anacompare_asr(asr_list=(0, 2), chneut_list=(1, ), dipdip=1,
|
||||
lo_to_splitting=self.lo_to_splitting,
|
||||
nqsmall=self.nqsmall, ndivsm=self.ndivsm,
|
||||
dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs)
|
||||
|
||||
with ButtonContext(self.plot_check_asr_dipdip_btn):
|
||||
asr_plotter = self.ddb.anacompare_asr(asr_list=(0, 2), chneut_list=(1, ), dipdip=1,
|
||||
lo_to_splitting=self.lo_to_splitting,
|
||||
nqsmall=self.nqsmall, ndivsm=self.ndivsm,
|
||||
dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs)
|
||||
dipdip_plotter = self.ddb.anacompare_dipdip(chneut_list=(1,), asr=2, lo_to_splitting=self.lo_to_splitting,
|
||||
nqsmall=self.nqsmall, ndivsm=self.ndivsm,
|
||||
dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs)
|
||||
|
||||
dipdip_plotter = self.ddb.anacompare_dipdip(chneut_list=(1,), asr=2, lo_to_splitting=self.lo_to_splitting,
|
||||
nqsmall=self.nqsmall, ndivsm=self.ndivsm,
|
||||
dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs)
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
ca("## Phonon bands and DOS with/wo acoustic sum rule:")
|
||||
#ca(mpl(asr_plotter.plot(**self.mpl_kwargs)))
|
||||
ca(ply(asr_plotter.combiplotly(show=False)))
|
||||
ca("## Phonon bands and DOS with/without the treatment of the dipole-dipole interaction:")
|
||||
#ca(mpl(dipdip_plotter.plot(**self.mpl_kwargs)))
|
||||
ca(ply(dipdip_plotter.combiplotly(show=False)))
|
||||
|
||||
ca("## Phonon bands and DOS with/wo acoustic sum rule:")
|
||||
#ca(mpl(asr_plotter.plot(**self.fig_kwargs)))
|
||||
ca(ply(asr_plotter.combiplotly(show=False)))
|
||||
ca("## Phonon bands and DOS with/without the treatment of the dipole-dipole interaction:")
|
||||
#ca(mpl(dipdip_plotter.plot(**self.fig_kwargs)))
|
||||
ca(ply(dipdip_plotter.combiplotly(show=False)))
|
||||
return col
|
||||
|
||||
return col
|
||||
|
||||
@param.depends('plot_dos_vs_qmesh_btn.clicks')
|
||||
@depends_on_btn_click('plot_dos_vs_qmesh_btn')
|
||||
def plot_dos_vs_qmesh(self):
|
||||
"""
|
||||
Compare phonon DOSes computed with/without the inclusion
|
||||
of the dipole-quadrupole and quadrupole-quadrupole terms in the dynamical matrix.
|
||||
Requires DDB file with eps_inf, BECS and dynamical quadrupoles.
|
||||
"""
|
||||
if self.plot_dos_vs_qmesh_btn.clicks == 0: return
|
||||
num_cpus = 1
|
||||
#print(self.nqsmall_list.value)
|
||||
r = self.ddb.anacompare_phdos(self.nqsmall_list.value, asr=self.asr, chneut=self.chneut, dipdip=self.dipdip,
|
||||
dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, num_cpus=num_cpus, stream=sys.stdout)
|
||||
|
||||
with ButtonContext(self.plot_dos_vs_qmesh_btn):
|
||||
num_cpus = 1
|
||||
#print(self.nqsmall_list.value)
|
||||
r = self.ddb.anacompare_phdos(self.nqsmall_list.value, asr=self.asr, chneut=self.chneut, dipdip=self.dipdip,
|
||||
dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, num_cpus=num_cpus, stream=sys.stdout)
|
||||
#r.phdoses: List of |PhononDos| objects
|
||||
|
||||
#r.phdoses: List of |PhononDos| objects
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
ca("## Phonon DOSes obtained with different q-meshes:")
|
||||
ca(ply(r.plotter.combiplotly(show=False)))
|
||||
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
ca("## Phonon DOSes obtained with different q-meshes:")
|
||||
ca(ply(r.plotter.combiplotly(show=False)))
|
||||
ca("## Convergence of termodynamic properties.")
|
||||
temps = self.temp_range
|
||||
ca(mpl(r.plotter.plot_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50,
|
||||
units=self.units, **self.mpl_kwargs)))
|
||||
|
||||
ca("## Convergence of termodynamic properties.")
|
||||
temps = self.temp_range.value
|
||||
ca(mpl(r.plotter.plot_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50,
|
||||
units=self.units, **self.fig_kwargs)))
|
||||
return col
|
||||
|
||||
return col
|
||||
|
||||
@param.depends('plot_phbands_quad_btn.clicks')
|
||||
@depends_on_btn_click('plot_phbands_quad_btn')
|
||||
def plot_phbands_quad(self):
|
||||
"""
|
||||
Compare phonon bands and DOSes computed with/without the inclusion
|
||||
of the dipole-quadrupole and quadrupole-quadrupole terms in the dynamical matrix.
|
||||
Requires DDB file with eps_inf, BECS and dynamical quadrupoles.
|
||||
"""
|
||||
if self.plot_phbands_quad_btn.clicks == 0: return
|
||||
plotter = self.ddb.anacompare_quad(asr=self.asr, chneut=self.chneut, dipdip=self.dipdip,
|
||||
lo_to_splitting=self.lo_to_splitting,
|
||||
nqsmall=0, ndivsm=self.ndivsm, dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs)
|
||||
|
||||
with ButtonContext(self.plot_dos_vs_qmesh_btn):
|
||||
plotter = self.ddb.anacompare_quad(asr=self.asr, chneut=self.chneut, dipdip=self.dipdip,
|
||||
lo_to_splitting=self.lo_to_splitting,
|
||||
nqsmall=0, ndivsm=self.ndivsm, dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs)
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
ca("## Phonon Bands obtained with different q-meshes:")
|
||||
ca(ply(plotter.combiplotly(show=False)))
|
||||
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
ca("## Phonon Bands obtained with different q-meshes:")
|
||||
ca(ply(plotter.combiplotly(show=False)))
|
||||
return col
|
||||
|
||||
return col
|
||||
|
||||
@param.depends('plot_ifc_btn.clicks')
|
||||
@depends_on_btn_click('plot_ifc_btn')
|
||||
def plot_ifc(self):
|
||||
if self.plot_ifc_btn.clicks == 0: return
|
||||
|
||||
ifc = self.ddb.anaget_ifc(asr=self.asr, chneut=self.chneut, dipdip=self.dipdip)
|
||||
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
ca(mpl(ifc.plot_longitudinal_ifc(title="Longitudinal IFCs", **self.fig_kwargs)))
|
||||
ca(mpl(ifc.plot_longitudinal_ifc_short_range(title="Longitudinal IFCs short range", **self.fig_kwargs)))
|
||||
ca(mpl(ifc.plot_longitudinal_ifc_ewald(title="Longitudinal IFCs Ewald", **self.fig_kwargs)))
|
||||
ca(mpl(ifc.plot_longitudinal_ifc(title="Longitudinal IFCs", **self.mpl_kwargs)))
|
||||
ca(mpl(ifc.plot_longitudinal_ifc_short_range(title="Longitudinal IFCs short range", **self.mpl_kwargs)))
|
||||
ca(mpl(ifc.plot_longitudinal_ifc_ewald(title="Longitudinal IFCs Ewald", **self.mpl_kwargs)))
|
||||
|
||||
return col
|
||||
|
||||
def get_panel(self):
|
||||
"""Return tabs with widgets to interact with the DDB file."""
|
||||
def get_panel(self, as_dict=False, **kwargs):
|
||||
"""
|
||||
Return tabs with widgets to interact with the DDB file.
|
||||
"""
|
||||
d = {}
|
||||
d["Summary"] = pn.Row(
|
||||
bkw.PreText(text=self.ddb.to_string(verbose=self.verbose), sizing_mode="scale_both")
|
||||
)
|
||||
#if self.ddb.has_phonons
|
||||
d["PH-bands"] = pn.Row(
|
||||
self.pws_col(["### PH-bands options", "nqsmall", "ndivsm", "asr", "chneut", "dipdip",
|
||||
"lo_to_splitting", "dos_method", "stacked_pjdos", "temp_range", "plot_phbands_btn",
|
||||
self.helpc("plot_phbands_and_phdos")]),
|
||||
self.plot_phbands_and_phdos
|
||||
)
|
||||
#if self.ddb.has_becs
|
||||
d["BECs"] = pn.Row(
|
||||
self.pws_col(["### Born effective charges options", "asr", "chneut", "dipdip", "gamma_ev",
|
||||
"get_epsinf_btn", self.helpc("get_epsinf")]),
|
||||
self.get_epsinf
|
||||
)
|
||||
#if self.ddb.has_e0
|
||||
d["eps0"] = pn.Row(
|
||||
self.pws_col(["### epsilon_0", "asr", "chneut", "dipdip", "gamma_ev", "w_range", "plot_eps0w_btn",
|
||||
self.helpc("plot_eps0w")]),
|
||||
self.plot_eps0w
|
||||
)
|
||||
#if self.ddb.has_phonons
|
||||
d["Speed of sound"] = pn.Row(
|
||||
self.pws_col(["### Speed of sound options", "asr", "chneut", "dipdip", "plot_vsound_btn",
|
||||
self.helpc("plot_vsound")]),
|
||||
self.plot_vsound
|
||||
)
|
||||
#if self.ddb.has_phonons
|
||||
d["ASR & DIPDIP"] = pn.Row(
|
||||
self.pws_col(["### ASR & DIPDIP options", "nqsmall", "ndivsm", "dos_method", "plot_check_asr_dipdip_btn",
|
||||
self.helpc("plot_without_asr_dipdip")]),
|
||||
self.plot_without_asr_dipdip
|
||||
)
|
||||
d["DOS vs q-mesh"] = pn.Row(
|
||||
self.pws_col(["### DOS vs q-mesh options", "asr", "chneut", "dipdip", "dos_method", "nqsmall_list",
|
||||
"temp_range", "plot_dos_vs_qmesh_btn", self.helpc("plot_dos_vs_qmesh")]),
|
||||
self.plot_dos_vs_qmesh
|
||||
)
|
||||
#if self.ddb.has_dynamical_quadrupoles
|
||||
d["Quadrupoles"] = pn.Row(
|
||||
self.pws_col(["### Quadrupoles options", "asr", "chneut", "dipdip", "lo_to_splitting", "ndivsm", "dos_method",
|
||||
"plot_phbands_quad_btn", self.helpc("plot_phbands_quad")]),
|
||||
self.plot_phbands_quad
|
||||
)
|
||||
#if self.ddb.has_phonons
|
||||
d["IFCs"] = pn.Row(
|
||||
self.pws_col(["### IFCs options", "asr", "dipdip", "chneut", "plot_ifc_btn", self.helpc("plot_ifc")]),
|
||||
self.plot_ifc
|
||||
)
|
||||
d["Structure"] = self.get_struct_view_tab_entry()
|
||||
d["Global"] = pn.Row(
|
||||
self.pws_col(["### Global options", "units", "mpi_procs", "verbose"]),
|
||||
self.get_software_stack()
|
||||
)
|
||||
|
||||
def info(method_name):
|
||||
# Add accordion with brief desciption and warning after the button.
|
||||
# The description of the tool is taken from the docstring of the callback.
|
||||
col = pn.Column(); ca = col.append
|
||||
acc = pn.Accordion(("Help", pn.pane.Markdown(getattr(self, method_name).__doc__)))
|
||||
acc.append(("Warning", self.warning_md))
|
||||
ca(pn.layout.Divider())
|
||||
ca(acc)
|
||||
return col
|
||||
if as_dict: return d
|
||||
|
||||
tabs = pn.Tabs(); app = tabs.append
|
||||
|
||||
app(("Summary", pn.Row(
|
||||
bkw.PreText(text=self.ddb.to_string(verbose=self.verbose), sizing_mode="scale_both"))
|
||||
))
|
||||
app(("PH-bands", pn.Row(
|
||||
pn.Column("# PH-bands options",
|
||||
*self.pws("nqsmall", "ndivsm", "asr", "chneut", "dipdip",
|
||||
"lo_to_splitting", "dos_method", "temp_range", "plot_phbands_btn",
|
||||
info("plot_phbands_and_phdos")),
|
||||
),
|
||||
self.plot_phbands_and_phdos)
|
||||
))
|
||||
app(("BECs", pn.Row(
|
||||
pn.Column("# Born effective charges options",
|
||||
*self.pws("asr", "chneut", "dipdip", "gamma_ev", "get_epsinf_btn", info("get_epsinf")),
|
||||
),
|
||||
self.get_epsinf)
|
||||
))
|
||||
app(("eps0", pn.Row(
|
||||
pn.Column("# epsilon_0",
|
||||
*self.pws("asr", "chneut", "dipdip", "gamma_ev", "w_range", "plot_eps0w_btn",
|
||||
info("plot_eps0w")),
|
||||
),
|
||||
self.plot_eps0w)
|
||||
))
|
||||
app(("Speed of sound", pn.Row(
|
||||
pn.Column("# Speed of sound options",
|
||||
*self.pws("asr", "chneut", "dipdip", "plot_vsound_btn", info("plot_vsound")),
|
||||
),
|
||||
self.plot_vsound)
|
||||
))
|
||||
app(("ASR & DIPDIP", pn.Row(
|
||||
pn.Column("# ASR & DIPDIP options",
|
||||
*self.pws("nqsmall", "ndivsm", "dos_method", "plot_check_asr_dipdip_btn",
|
||||
info("plot_without_asr_dipdip")),
|
||||
),
|
||||
self.plot_without_asr_dipdip)
|
||||
))
|
||||
app(("DOS vs q-mesh", pn.Row(
|
||||
pn.Column("# DOS vs q-mesh options",
|
||||
*self.pws("asr", "chneut", "dipdip", "dos_method", "nqsmall_list",
|
||||
"temp_range", "plot_dos_vs_qmesh_btn", info("plot_dos_vs_qmesh")),
|
||||
),
|
||||
self.plot_dos_vs_qmesh)
|
||||
))
|
||||
app(("Quadrupoles", pn.Row(
|
||||
pn.Column("# Quadrupoles options",
|
||||
*self.pws("asr", "chneut", "dipdip", "lo_to_splitting", "ndivsm", "dos_method",
|
||||
"plot_phbands_quad_btn", info("plot_phbands_quad")),
|
||||
),
|
||||
self.plot_phbands_quad)
|
||||
))
|
||||
app(("IFCs", pn.Row(
|
||||
pn.Column("# IFCs options",
|
||||
*self.pws("asr", "dipdip", "chneut", "plot_ifc_btn", info("plot_ifc")),
|
||||
),
|
||||
self.plot_ifc)
|
||||
))
|
||||
app(("Global options",
|
||||
pn.Column("# Global options",
|
||||
*self.pws("units", "mpi_procs", "verbose"),
|
||||
)))
|
||||
|
||||
return tabs
|
||||
tabs = pn.Tabs(*d.items())
|
||||
return self.get_template_from_tabs(tabs, template=kwargs.get("template", None))
|
||||
|
||||
|
||||
class DdbRobotPanel(HasAnaddbParams):
|
||||
class DdbRobotPanel(BaseRobotPanel, HasAnaddbParams):
|
||||
"""
|
||||
A panel to analyze multiple |DdbFile| via the low-level API provided by DdbRobot.
|
||||
Provides widgets to invoke anaddb and visualize the results.
|
||||
"""
|
||||
|
||||
# Buttons
|
||||
plot_combiplot_btn = pnw.Button(name="Compute", button_type='primary')
|
||||
combiplot_check_btn = pnw.CheckButtonGroup(name='Check Button Group',
|
||||
|
@ -408,36 +411,34 @@ class DdbRobotPanel(HasAnaddbParams):
|
|||
|
||||
return kwargs
|
||||
|
||||
@param.depends('plot_combiplot_btn.clicks')
|
||||
def plot_combiplot(self):
|
||||
@depends_on_btn_click('plot_combiplot_btn')
|
||||
def plot_combiplot(self, **kwargs):
|
||||
"""Plot phonon band structures."""
|
||||
if self.plot_combiplot_btn.clicks == 0: return
|
||||
|
||||
kwargs = self.kwargs_for_anaget_phbst_and_phdos_files()
|
||||
|
||||
with ButtonContext(self.plot_combiplot_btn):
|
||||
#TODO: Recheck lo-to automatic.
|
||||
r = self.robot.anaget_phonon_plotters(**kwargs)
|
||||
#r = self.robot.anaget_phonon_plotters()
|
||||
#TODO: Recheck lo-to automatic.
|
||||
r = self.robot.anaget_phonon_plotters(**kwargs)
|
||||
#r = self.robot.anaget_phonon_plotters()
|
||||
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
if "combiplot" in self.combiplot_check_btn.value:
|
||||
ca("## Phonon band structure and DOS:")
|
||||
ca(ply(r.phbands_plotter.combiplotly(units=self.units, show=False)))
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_both'); ca = col.append
|
||||
|
||||
if "gridplot" in self.combiplot_check_btn.value:
|
||||
ca("## Phonon band structure and DOS:")
|
||||
ca(ply(r.phbands_plotter.gridplotly(units=self.units, show=False)))
|
||||
if "combiplot" in self.combiplot_check_btn.value:
|
||||
ca("## Combiplot:")
|
||||
ca(ply(r.phbands_plotter.combiplotly(units=self.units, show=False)))
|
||||
|
||||
#if "temp_range" in self.combiplot_check_btn.value:
|
||||
#temps = self.temp_range.value
|
||||
#ca("## Thermodynamic properties in the harmonic approximation:")
|
||||
##ca(phdos.plot_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, **self.fig_kwargs))
|
||||
#ca(ply(phdos.plotly_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, show=False)))
|
||||
if "gridplot" in self.combiplot_check_btn.value:
|
||||
ca("## Gridplot:")
|
||||
# FIXME implement with_dos = True
|
||||
ca(ply(r.phbands_plotter.gridplotly(units=self.units, with_dos=False, show=False)))
|
||||
|
||||
#if "temp_range" in self.combiplot_check_btn.value:
|
||||
#temps = self.temp_range.value
|
||||
#ca("## Thermodynamic properties in the harmonic approximation:")
|
||||
##ca(phdos.plot_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, **self.mpl_kwargs))
|
||||
#ca(ply(phdos.plotly_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, show=False)))
|
||||
|
||||
return col
|
||||
return col
|
||||
|
||||
#@param.depends('get_epsinf_btn.clicks')
|
||||
#def get_epsinf(self):
|
||||
|
@ -459,11 +460,11 @@ class DdbRobotPanel(HasAnaddbParams):
|
|||
|
||||
# eps0 = gen.tensor_at_frequency(w=0, gamma_ev=self.gamma_ev)
|
||||
# ca(r"## $\epsilon^0$ in Cart. coords (computed with Gamma_eV):")
|
||||
# ca(df(eps0.get_dataframe(cmode="real"), **df_kwargs))
|
||||
# ca(dfc(eps0.get_dataframe(cmode="real"), **df_kwargs))
|
||||
# ca(r"## $\epsilon^\infty$ in Cart. coords:")
|
||||
# ca(df(epsinf.get_dataframe(), **df_kwargs))
|
||||
# ca(dfc(epsinf.get_dataframe(), **df_kwargs))
|
||||
# ca("## Born effective charges in Cart. coords:")
|
||||
# ca(df(becs.get_voigt_dataframe(), **df_kwargs))
|
||||
# ca(dfc(becs.get_voigt_dataframe(), **df_kwargs))
|
||||
# ca("## Anaddb input file.")
|
||||
# ca(pn.pane.HTML(inp._repr_html_()))
|
||||
|
||||
|
@ -478,13 +479,13 @@ class DdbRobotPanel(HasAnaddbParams):
|
|||
# gen, inp = self.ddb.anaget_dielectric_tensor_generator(asr=self.asr, chneut=self.chneut, dipdip=self.dipdip,
|
||||
# mpi_procs=self.mpi_procs, verbose=self.verbose,
|
||||
# return_input=True)
|
||||
# ws = self.w_range.value
|
||||
# ws = self.w_range
|
||||
# w_max = ws[1]
|
||||
# if w_max == 1.0: w_max = None # Will compute w_max in plot routine from ph freqs.
|
||||
|
||||
# def p(component, reim):
|
||||
# return gen.plot(w_min=ws[0], w_max=w_max, gamma_ev=self.gamma_ev, num=500, component=component,
|
||||
# reim=reim, units=self.units, **self.fig_kwargs)
|
||||
# reim=reim, units=self.units, **self.mpl_kwargs)
|
||||
|
||||
# # Build grid
|
||||
# gspec = pn.GridSpec(sizing_mode='scale_width')
|
||||
|
@ -519,14 +520,14 @@ class DdbRobotPanel(HasAnaddbParams):
|
|||
|
||||
# ca("## Phonon band structure and DOS:")
|
||||
# ca(ply(phbands.plotly_with_phdos(phdos, units=self.units, show=False)))
|
||||
# #ca(mpl(phbands.plot_with_phdos(phdos, units=self.units, **self.fig_kwargs)))
|
||||
# #ca(mpl(phdos_file.plot_pjdos_type(units=self.units, exchange_xy=True, **self.fig_kwargs)))
|
||||
# #ca(mpl(phdos_file.msqd_dos.plot(units=self.units, **self.fig_kwargs)))
|
||||
# #ca(mpl(phbands.plot_with_phdos(phdos, units=self.units, **self.mpl_kwargs)))
|
||||
# #ca(mpl(phdos_file.plot_pjdos_type(units=self.units, exchange_xy=True, **self.mpl_kwargs)))
|
||||
# #ca(mpl(phdos_file.msqd_dos.plot(units=self.units, **self.mpl_kwargs)))
|
||||
# temps = self.temp_range.value
|
||||
# ca("## Thermodynamic properties in the harmonic approximation:")
|
||||
# #ca(phdos.plot_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, **self.fig_kwargs))
|
||||
# #ca(phdos.plot_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, **self.mpl_kwargs))
|
||||
# ca(ply(phdos.plotly_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, show=False)))
|
||||
# #msqd_dos.plot_tensor(**self.fig_kwargs)
|
||||
# #msqd_dos.plot_tensor(**self.mpl_kwargs)
|
||||
# #self.plot_phbands_btn.button_type = "primary"
|
||||
|
||||
# # Add HTML pane with input
|
||||
|
@ -552,148 +553,126 @@ class DdbRobotPanel(HasAnaddbParams):
|
|||
# # Insert results in grid.
|
||||
# gspec = pn.GridSpec(sizing_mode='scale_width')
|
||||
# gspec[0, :1] = sv.get_dataframe()
|
||||
# gspec[1, :1] = sv.plot(**self.fig_kwargs)
|
||||
# gspec[1, :1] = sv.plot(**self.mpl_kwargs)
|
||||
|
||||
# return gspec
|
||||
|
||||
# THIS OK but I don't think it's very useful
|
||||
@param.depends('plot_check_asr_dipdip_btn.clicks')
|
||||
@depends_on_btn_click('plot_check_asr_dipdip_btn')
|
||||
def plot_without_asr_dipdip(self):
|
||||
"""
|
||||
Compare phonon bands and DOSes computed with/without the acoustic sum rule
|
||||
and the treatment of the dipole-dipole interaction in the dynamical matrix.
|
||||
Requires DDB file with eps_inf, BECS.
|
||||
"""
|
||||
if self.plot_check_asr_dipdip_btn.clicks == 0: return
|
||||
|
||||
asr_plotter = PhononBandsPlotter()
|
||||
dipdip_plotter = PhononBandsPlotter()
|
||||
|
||||
with ButtonContext(self.plot_check_asr_dipdip_btn):
|
||||
for label, ddb in self.robot.items():
|
||||
asr_p = ddb.anacompare_asr(asr_list=(0, 2), chneut_list=(1, ), dipdip=1,
|
||||
lo_to_splitting=self.lo_to_splitting,
|
||||
nqsmall=self.nqsmall, ndivsm=self.ndivsm,
|
||||
dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs,
|
||||
pre_label=label)
|
||||
for label, ddb in self.robot.items():
|
||||
asr_p = ddb.anacompare_asr(asr_list=(0, 2), chneut_list=(1, ), dipdip=1,
|
||||
lo_to_splitting=self.lo_to_splitting,
|
||||
nqsmall=self.nqsmall, ndivsm=self.ndivsm,
|
||||
dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs,
|
||||
pre_label=label)
|
||||
|
||||
asr_plotter.append_plotter(asr_p)
|
||||
asr_plotter.append_plotter(asr_p)
|
||||
|
||||
dipdip_p = ddb.anacompare_dipdip(chneut_list=(1,), asr=2, lo_to_splitting=self.lo_to_splitting,
|
||||
nqsmall=self.nqsmall, ndivsm=self.ndivsm,
|
||||
dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs,
|
||||
pre_label=label)
|
||||
dipdip_p = ddb.anacompare_dipdip(chneut_list=(1,), asr=2, lo_to_splitting=self.lo_to_splitting,
|
||||
nqsmall=self.nqsmall, ndivsm=self.ndivsm,
|
||||
dos_method=self.dos_method, ngqpt=None,
|
||||
verbose=self.verbose, mpi_procs=self.mpi_procs,
|
||||
pre_label=label)
|
||||
|
||||
dipdip_plotter.append_plotter(dipdip_p)
|
||||
dipdip_plotter.append_plotter(dipdip_p)
|
||||
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
# Fill column
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
|
||||
ca("## Phonon bands and DOS with/wo acoustic sum rule:")
|
||||
ca(ply(asr_plotter.combiplotly(show=False)))
|
||||
ca("## Phonon bands and DOS with/without the treatment of the dipole-dipole interaction:")
|
||||
ca(ply(dipdip_plotter.combiplotly(show=False)))
|
||||
ca("## Phonon bands and DOS with/wo acoustic sum rule:")
|
||||
ca(ply(asr_plotter.combiplotly(show=False)))
|
||||
ca("## Phonon bands and DOS with/without the treatment of the dipole-dipole interaction:")
|
||||
ca(ply(dipdip_plotter.combiplotly(show=False)))
|
||||
|
||||
return col
|
||||
return col
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, as_dict=False, **kwargs):
|
||||
"""Return tabs with widgets to interact with the DDB file."""
|
||||
|
||||
robot = self.robot
|
||||
|
||||
def info(method_name):
|
||||
# Add accordion after the button with warning and help taken from the docstring of the callback
|
||||
col = pn.Column(); ca = col.append
|
||||
ca(pn.pane.Alert("Refresh the page if the plotly figure is not shown.", alert_type="danger"))
|
||||
acc = pn.Accordion(("Help", pn.pane.Markdown(getattr(self, method_name).__doc__)))
|
||||
acc.append(("Warning", self.warning_md))
|
||||
ca(pn.layout.Divider())
|
||||
ca(acc)
|
||||
return col
|
||||
d["Summary"] = pn.Row(
|
||||
bkw.PreText(text=robot.to_string(verbose=self.verbose), sizing_mode="scale_both")
|
||||
)
|
||||
|
||||
tabs = pn.Tabs(); app = tabs.append
|
||||
d["Params"] = self.get_compare_params_widgets()
|
||||
|
||||
app(("Summary", pn.Row(
|
||||
bkw.PreText(text=robot.to_string(verbose=self.verbose), sizing_mode="scale_both"))
|
||||
))
|
||||
|
||||
dfs = robot.get_structure_dataframes()
|
||||
app(("Structures",
|
||||
pn.Column("# Lattice daframe", self._df(dfs.lattice),
|
||||
"# Atomic positions", self._df(dfs.coords),)
|
||||
))
|
||||
|
||||
app(("Combiplot", pn.Row(
|
||||
d["Combiplot"] = pn.Row(
|
||||
pn.Column("# PH-bands options",
|
||||
*self.pws("nqsmall", "ndivsm", "asr", "chneut", "dipdip",
|
||||
"lo_to_splitting", "dos_method", "temp_range",
|
||||
"combiplot_check_btn", "plot_combiplot_btn",
|
||||
info("plot_combiplot")),
|
||||
self.helpc("plot_combiplot")),
|
||||
),
|
||||
self.plot_combiplot)
|
||||
))
|
||||
self.plot_combiplot
|
||||
)
|
||||
#app(("PH-bands", pn.Row(
|
||||
# pn.Column("# PH-bands options",
|
||||
# *self.pws("nqsmall", "ndivsm", "asr", "chneut", "dipdip",
|
||||
# "lo_to_splitting", "dos_method", "temp_range", "plot_phbands_btn",
|
||||
# info("plot_phbands_and_phdos")),
|
||||
# self.helpc("plot_phbands_and_phdos")),
|
||||
# ),
|
||||
# self.plot_phbands_and_phdos)
|
||||
#))
|
||||
#app(("BECs", pn.Row(
|
||||
# pn.Column("# Born effective charges options",
|
||||
# *self.pws("asr", "chneut", "dipdip", "gamma_ev", "get_epsinf_btn",
|
||||
# info("get_epsinf")),
|
||||
# self.helpc("get_epsinf")),
|
||||
# ),
|
||||
# self.get_epsinf)
|
||||
#))
|
||||
#app(("eps0", pn.Row(
|
||||
# pn.Column("# epsilon_0",
|
||||
# *self.pws("asr", "chneut", "dipdip", "gamma_ev", "w_range", "plot_eps0w_btn",
|
||||
# info("plot_eps0w")),
|
||||
# self.helpc("plot_eps0w")),
|
||||
# ),
|
||||
# self.plot_eps0w)
|
||||
#))
|
||||
#app(("Speed of sound", pn.Row(
|
||||
# pn.Column("# Speed of sound options",
|
||||
# *self.pws("asr", "chneut", "dipdip", "plot_vsound_btn",
|
||||
# info("plot_vsound")),
|
||||
# self.helpc("plot_vsound")),
|
||||
# ),
|
||||
# self.plot_vsound)
|
||||
#))
|
||||
app(("ASR & DIPDIP", pn.Row(
|
||||
pn.Column("# ASR & DIPDIP options",
|
||||
*self.pws("nqsmall", "ndivsm", "dos_method", "plot_check_asr_dipdip_btn",
|
||||
info("plot_without_asr_dipdip")),
|
||||
),
|
||||
self.plot_without_asr_dipdip)
|
||||
))
|
||||
d["ASR & DIPDIP"] = pn.Row(
|
||||
self.pws_col(["### ASR & DIPDIP options", "nqsmall", "ndivsm", "dos_method", "plot_check_asr_dipdip_btn",
|
||||
self.helpc("plot_without_asr_dipdip")]),
|
||||
self.plot_without_asr_dipdip
|
||||
)
|
||||
#app(("DOS vs q-mesh", pn.Row(
|
||||
# pn.Column("# DOS vs q-mesh options",
|
||||
# *self.pws("asr", "chneut", "dipdip", "dos_method", "nqsmall_list", "plot_dos_vs_qmesh_btn",
|
||||
# info("plot_dos_vs_qmesh")),
|
||||
# self.helpc("plot_dos_vs_qmesh")),
|
||||
# ),
|
||||
# self.plot_dos_vs_qmesh)
|
||||
#))
|
||||
#app(("Quadrupoles", pn.Row(
|
||||
# pn.Column("# Quadrupoles options",
|
||||
# *self.pws("asr", "chneut", "dipdip", "lo_to_splitting", "ndivsm", "dos_method", "plot_phbands_quad_btn",
|
||||
# info("plot_phbands_quad")),
|
||||
# self.helpc("plot_phbands_quad")),
|
||||
# ),
|
||||
# self.plot_phbands_quad)
|
||||
#))
|
||||
#app(("IFCs", pn.Row(
|
||||
# pn.Column("# IFCs options",
|
||||
# *self.pws("asr", "dipdip", "chneut", "plot_ifc_btn",
|
||||
# info("plot_ifc")),
|
||||
# self.helpc("plot_ifc")),
|
||||
# ),
|
||||
# self.plot_ifc)
|
||||
#))
|
||||
app(("Global options",
|
||||
pn.Column("# Global options",
|
||||
*self.pws("units", "mpi_procs", "verbose"),
|
||||
)))
|
||||
d["Global"] = pn.pws_col(["### Global options", "units", "mpi_procs", "verbose"])
|
||||
|
||||
return tabs
|
||||
if as_dict: return d
|
||||
|
||||
tabs = pn.Tabs(*d.items())
|
||||
return self.get_template_from_tabs(tabs, template=kwargs.get("template", None))
|
||||
|
|
|
@ -5,7 +5,7 @@ import panel as pn
|
|||
#import panel.widgets as pnw
|
||||
import bokeh.models.widgets as bkw
|
||||
|
||||
from .core import PanelWithElectronBands #, PanelWithEbandsRobot
|
||||
from .core import PanelWithElectronBands, ply, mpl, dfc #, PanelWithEbandsRobot
|
||||
|
||||
|
||||
class FatBandsFilePanel(PanelWithElectronBands):
|
||||
|
@ -13,32 +13,37 @@ class FatBandsFilePanel(PanelWithElectronBands):
|
|||
Panel with widgets to interact with a |FatBandsFile|.
|
||||
"""
|
||||
def __init__(self, ncfile, **params):
|
||||
self._ncfile = ncfile
|
||||
super().__init__(**params)
|
||||
self.ncfile = ncfile
|
||||
|
||||
@property
|
||||
def ncfile(self):
|
||||
return self._ncfile
|
||||
|
||||
@property
|
||||
def ebands(self):
|
||||
"""|ElectronBands|."""
|
||||
return self.ncfile.ebands
|
||||
return self._ncfile.ebands
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, as_dict=False, **kwargs):
|
||||
"""Return tabs with widgets to interact with the FATBANDS.nc file."""
|
||||
tabs = pn.Tabs(); app = tabs.append
|
||||
app(("Summary", pn.Row(bkw.PreText(text=self.ncfile.to_string(verbose=self.verbose), sizing_mode="scale_both"))))
|
||||
app(("e-Bands", pn.Row(self.get_plot_ebands_widgets(), self.on_plot_ebands_btn)))
|
||||
d = {}
|
||||
|
||||
d["Summary"] = pn.Row(bkw.PreText(text=self.ncfile.to_string(verbose=self.verbose), sizing_mode="scale_both"))
|
||||
d["e-Bands"] = pn.Row(self.get_plot_ebands_widgets(), self.on_plot_ebands_btn)
|
||||
|
||||
if self.ncfile.ebands.kpoints.is_ibz:
|
||||
# Add DOS tab only if k-sampling.
|
||||
app(("e-DOS", pn.Row(self.get_plot_edos_widgets(), self.on_plot_edos_btn)))
|
||||
# Add DOS tab but only if k-sampling.
|
||||
d["e-DOS"] = pn.Row(self.get_plot_edos_widgets(), self.on_plot_edos_btn)
|
||||
|
||||
# Plot the L-PJDOS grouped by atomic type.
|
||||
#self.ncfile.plot_pjdos_typeview(lmax=lmax, **self.fig_kwargs)
|
||||
#self.ncfile.plot_pjdos_typeview(lmax=lmax, **self.mpl_kwargs)
|
||||
# Plot the L-PJDOS grouped by L.
|
||||
#self.ncfile.plot_pjdos_lview(lmax=lmax, **self.fig_kwargs)
|
||||
#self.ncfile.plot_pjdos_lview(lmax=lmax, **self.mpl_kwargs)
|
||||
|
||||
# Fermi surface requires a gamma-centered k-mesh
|
||||
if self.ncfile.ebands.supports_fermi_surface:
|
||||
app(("Fermi Surface", pn.Row(self.get_plot_fermi_surface_widgets(), self.on_plot_fermi_surface_btn)))
|
||||
d["Fermi Surface"] = pn.Row(self.get_plot_fermi_surface_widgets(), self.on_plot_fermi_surface_btn)
|
||||
|
||||
elif self.ncfile.ebands.kpoints.is_path:
|
||||
# NC files have contributions up to L=4 (g channel)
|
||||
|
@ -47,14 +52,16 @@ class FatBandsFilePanel(PanelWithElectronBands):
|
|||
lmax = 2
|
||||
|
||||
# Plot the electronic fatbands grouped by atomic type.
|
||||
#self.ncfile.plot_fatbands_typeview(lmax=lmax, **self.fig_kwargs)
|
||||
#self.ncfile.plot_fatbands_typeview(lmax=lmax, **self.mpl_kwargs)
|
||||
# Plot the electronic fatbands grouped by L.
|
||||
#self.ncfile.plot_fatbands_lview(lmax=lmax, **self.fig_kwargs)
|
||||
#self.ncfile.plot_fatbands_lview(lmax=lmax, **self.mpl_kwargs)
|
||||
|
||||
else:
|
||||
raise ValueError("Neither a IBZ nor k-path!")
|
||||
|
||||
return tabs
|
||||
if as_dict: return d
|
||||
tabs = pn.Tabs(*d.items())
|
||||
return self.get_template_from_tabs(tabs, template=kwargs.get("template", None))
|
||||
|
||||
|
||||
#class FatbandsRobotPanel(PanelWithEbandsRobot):
|
||||
|
@ -72,7 +79,7 @@ class FatBandsFilePanel(PanelWithElectronBands):
|
|||
# def on_gsr_dataframe_btn(self):
|
||||
# if self.gsr_dataframe_btn.clicks == 0: return
|
||||
# df = self.robot.get_dataframe(with_geo=True)
|
||||
# return pn.Column(self._df(df), sizing_mode='stretch_width')
|
||||
# return pn.Column(dfc(df), sizing_mode='stretch_width')
|
||||
#
|
||||
# def get_panel(self):
|
||||
# """Return tabs with widgets to interact with the |GsrRobot|."""
|
||||
|
|
|
@ -1,77 +1,75 @@
|
|||
""""Panels for AbiPy flows."""
|
||||
""""Panels to interact with AbiPy flows."""
|
||||
import param
|
||||
import panel as pn
|
||||
import panel.widgets as pnw
|
||||
import bokeh.models.widgets as bkw
|
||||
|
||||
from io import StringIO
|
||||
from abipy.panels.core import AbipyParameterized
|
||||
from abipy.panels.core import AbipyParameterized, mpl, ply, dfc, depends_on_btn_click
|
||||
|
||||
|
||||
class FlowPanel(AbipyParameterized):
|
||||
"""
|
||||
Panel to interact with an AbiPy Flow.
|
||||
"""
|
||||
verbose = pn.widgets.IntSlider(start=0, end=10, step=1, value=0)
|
||||
|
||||
engine = pn.widgets.Select(value="fdp",
|
||||
options=['dot', 'neato', 'twopi', 'circo', 'fdp', 'sfdp', 'patchwork', 'osage'])
|
||||
dirtree = pn.widgets.Checkbox(name='Dirtree', value=False)
|
||||
graphviz_btn = pn.widgets.Button(name="Show graph", button_type='primary')
|
||||
|
||||
status_btn = pn.widgets.Button(name="Show status", button_type='primary')
|
||||
history_btn = pn.widgets.Button(name="Show history", button_type='primary')
|
||||
debug_btn = pn.widgets.Button(name="Debug", button_type='primary')
|
||||
events_btn = pn.widgets.Button(name="Events", button_type='primary')
|
||||
corrections_btn = pn.widgets.Button(name="Corrections", button_type='primary')
|
||||
handlers_btn = pn.widgets.Button(name="Handlers", button_type='primary')
|
||||
|
||||
vars_text = pn.widgets.TextInput(name='Abivars', placeholder='Enter list of variables separated by comma')
|
||||
vars_btn = pn.widgets.Button(name="Show Variables", button_type='primary')
|
||||
|
||||
dims_btn = pn.widgets.Button(name="Show Dimensions", button_type='primary')
|
||||
|
||||
structures_btn = pn.widgets.Button(name="Show Structures", button_type='primary')
|
||||
structures_io_checkbox = pn.widgets.CheckBoxGroup(
|
||||
name='Input/Output Structure', value=['output'], options=['input', 'output'], inline=True)
|
||||
|
||||
# Widgets to plot ebands.
|
||||
ebands_btn = pn.widgets.Button(name="Show Ebands", button_type='primary')
|
||||
ebands_plotter_mode = pnw.Select(name="Plot Mode", value="gridplot",
|
||||
options=["gridplot", "combiplot", "boxplot", "combiboxplot"]) # "animate",
|
||||
ebands_plotter_btn = pnw.Button(name="Plot", button_type='primary')
|
||||
ebands_df_checkbox = pnw.Checkbox(name='With Ebands DataFrame', value=False)
|
||||
ebands_ksamp_checkbox = pn.widgets.CheckBoxGroup(
|
||||
name='Input/Output Structure', value=["with_path", "with_ibz"], options=['with_path', 'with_ibz'], inline=True)
|
||||
|
||||
#TODO: Implement widget for selected_nids(flow, options),
|
||||
#radio_group = pn.widgets.RadioButtonGroup(
|
||||
# name='Radio Button Group', options=['Biology', 'Chemistry', 'Physics'], button_type='success')
|
||||
|
||||
def __init__(self, flow, **params):
|
||||
super().__init__(**params)
|
||||
self.flow = flow
|
||||
|
||||
@param.depends('status_btn.clicks')
|
||||
self.engine = pnw.Select(value="fdp", options=['dot', 'neato', 'twopi', 'circo', 'fdp', 'sfdp', 'patchwork', 'osage'])
|
||||
self.dirtree = pnw.Checkbox(name='Dirtree', value=False)
|
||||
self.graphviz_btn = pnw.Button(name="Show graph", button_type='primary')
|
||||
|
||||
self.status_btn = pnw.Button(name="Show status", button_type='primary')
|
||||
self.history_btn = pnw.Button(name="Show history", button_type='primary')
|
||||
self.debug_btn = pnw.Button(name="Debug", button_type='primary')
|
||||
self.events_btn = pnw.Button(name="Events", button_type='primary')
|
||||
self.corrections_btn = pnw.Button(name="Corrections", button_type='primary')
|
||||
self.handlers_btn = pnw.Button(name="Handlers", button_type='primary')
|
||||
|
||||
self.vars_text = pnw.TextInput(name='Abivars', placeholder='Enter list of variables separated by comma')
|
||||
self.vars_btn = pnw.Button(name="Show Variables", button_type='primary')
|
||||
|
||||
self.dims_btn = pnw.Button(name="Show Dimensions", button_type='primary')
|
||||
|
||||
self.structures_btn = pnw.Button(name="Show Structures", button_type='primary')
|
||||
self.structures_io_checkbox = pnw.CheckBoxGroup(
|
||||
name='Input/Output Structure', value=['output'], options=['input', 'output'], inline=True)
|
||||
|
||||
# Widgets to plot ebands.
|
||||
self.ebands_btn = pnw.Button(name="Show Ebands", button_type='primary')
|
||||
self.ebands_plotter_mode = pnw.Select(name="Plot Mode", value="gridplot",
|
||||
options=["gridplot", "combiplot", "boxplot", "combiboxplot"]) # "animate",
|
||||
self.ebands_plotter_btn = pnw.Button(name="Plot", button_type='primary')
|
||||
self.ebands_df_checkbox = pnw.Checkbox(name='With Ebands DataFrame', value=False)
|
||||
self.ebands_ksamp_checkbox = pnw.CheckBoxGroup(
|
||||
name='Input/Output Structure', value=["with_path", "with_ibz"], options=['with_path', 'with_ibz'], inline=True)
|
||||
|
||||
#TODO: Implement widget for selected_nids(flow, options),
|
||||
#radio_group = pn.widgets.RadioButtonGroup(
|
||||
# name='Radio Button Group', options=['Biology', 'Chemistry', 'Physics'], button_type='success')
|
||||
|
||||
super().__init__(**params)
|
||||
|
||||
@depends_on_btn_click("status_btn")
|
||||
def on_status_btn(self):
|
||||
if self.status_btn.clicks == 0: return
|
||||
stream = StringIO()
|
||||
self.flow.show_status(stream=stream, verbose=self.verbose.value)
|
||||
return pn.Row(bkw.PreText(text=stream.getvalue()))
|
||||
|
||||
@param.depends('history_btn.clicks')
|
||||
@depends_on_btn_click("history_btn")
|
||||
def on_history_btn(self):
|
||||
if self.history_btn.clicks == 0: return
|
||||
stream = StringIO()
|
||||
#flow.show_history(status=options.task_status, nids=selected_nids(flow, options),
|
||||
# full_history=options.full_history, metadata=options.metadata)
|
||||
self.flow.show_history(stream=stream)
|
||||
return pn.Row(bkw.PreText(text=stream.getvalue()))
|
||||
|
||||
@param.depends('graphviz_btn.clicks')
|
||||
@depends_on_btn_click("graphviz_btn")
|
||||
def on_graphviz_btn(self):
|
||||
"""
|
||||
Visualize the flow with graphviz.
|
||||
"""
|
||||
if self.graphviz_btn.clicks == 0: return
|
||||
node = self.flow
|
||||
if self.dirtree.value:
|
||||
graph = node.get_graphviz_dirtree(engine=self.engine.value)
|
||||
|
@ -79,16 +77,15 @@ class FlowPanel(AbipyParameterized):
|
|||
graph = node.get_graphviz(engine=self.engine.value)
|
||||
return pn.Column(graph)
|
||||
|
||||
@param.depends('debug_btn.clicks')
|
||||
@depends_on_btn_click("debug_btn")
|
||||
def on_debug_btn(self):
|
||||
if self.debug_btn.clicks == 0: return
|
||||
#TODO https://github.com/ralphbean/ansi2html ?
|
||||
stream = StringIO()
|
||||
#flow.debug(status=options.task_status, nids=selected_nids(flow, options))
|
||||
self.flow.debug(stream=stream)
|
||||
return pn.Row(bkw.PreText(text=stream.getvalue()))
|
||||
|
||||
@param.depends('events_btn.clicks')
|
||||
@depends_on_btn_click("events_btn")
|
||||
def on_events_btn(self):
|
||||
if self.events_btn.clicks == 0: return
|
||||
stream = StringIO()
|
||||
|
@ -96,17 +93,15 @@ class FlowPanel(AbipyParameterized):
|
|||
#flow.show_events(status=options.task_status, nids=selected_nids(flow, options))
|
||||
return pn.Row(bkw.PreText(text=stream.getvalue()))
|
||||
|
||||
@param.depends('corrections_btn.clicks')
|
||||
@depends_on_btn_click("corrections_btn")
|
||||
def on_corrections_btn(self):
|
||||
if self.corrections_btn.clicks == 0: return
|
||||
stream = StringIO()
|
||||
self.flow.show_corrections(stream=stream)
|
||||
#flow.show_corrections(status=options.task_status, nids=selected_nids(flow, options))
|
||||
return pn.Row(bkw.PreText(text=stream.getvalue()))
|
||||
|
||||
@param.depends('handlers_btn.clicks')
|
||||
@depends_on_btn_click("handlers_btn_clicks")
|
||||
def on_handlers_btn(self):
|
||||
#if self.handlers_btn.clicks == 0: return
|
||||
stream = StringIO()
|
||||
#if options.doc:
|
||||
# flowtk.autodoc_event_handlers()
|
||||
|
@ -115,25 +110,22 @@ class FlowPanel(AbipyParameterized):
|
|||
self.flow.show_event_handlers(verbose=self.verbose.value, stream=stream)
|
||||
return pn.Row(bkw.PreText(text=stream.getvalue()))
|
||||
|
||||
@param.depends('vars_btn.clicks')
|
||||
@depends_on_btn_click("vars_btn")
|
||||
def on_vars_btn(self):
|
||||
if self.vars_btn.clicks == 0: return
|
||||
if not self.vars_text.value: return
|
||||
varnames = [s.strip() for s in self.vars_text.value.split(",")]
|
||||
df = self.flow.compare_abivars(varnames=varnames, # nids=selected_nids(flow, options),
|
||||
printout=False, with_colors=False)
|
||||
return pn.Row(self._df(df))
|
||||
return pn.Row(dfc(df))
|
||||
|
||||
@param.depends('dims_btn.clicks')
|
||||
@depends_on_btn_click("dims_btn")
|
||||
def on_dims_btn(self):
|
||||
if self.dims_btn.clicks == 0: return
|
||||
df = self.flow.get_dims_dataframe(# nids=selected_nids(flow, options),
|
||||
printout=False, with_colors=False)
|
||||
return pn.Row(self._df(df), sizing_mode="scale_width")
|
||||
return pn.Row(dfc(df), sizing_mode="scale_width")
|
||||
|
||||
@param.depends('structures_btn.clicks')
|
||||
@depends_on_btn_click("structures_btn")
|
||||
def on_structures_btn(self):
|
||||
if self.structures_btn.clicks == 0: return
|
||||
what = ""
|
||||
if "input" in self.structures_io_checkbox.value: what += "i"
|
||||
if "output" in self.structures_io_checkbox.value: what += "o"
|
||||
|
@ -142,50 +134,54 @@ class FlowPanel(AbipyParameterized):
|
|||
verbose=self.verbose.value, with_spglib=False, printout=False,
|
||||
with_colors=False)
|
||||
|
||||
return pn.Row(self._df(dfs.lattice), sizing_mode="scale_width")
|
||||
return pn.Row(dfc(dfs.lattice), sizing_mode="scale_width")
|
||||
|
||||
@param.depends('ebands_plotter_btn.clicks')
|
||||
def on_ebands_btn(self):
|
||||
if self.ebands_plotter_btn.clicks == 0: return
|
||||
#@param.depends('ebands_plotter_btn.clicks')
|
||||
#def on_ebands_btn(self):
|
||||
# if self.ebands_plotter_btn.clicks == 0: return
|
||||
|
||||
df, ebands_plotter = self.flow.compare_ebands(
|
||||
nids=None, # select_nids(flow, options),
|
||||
with_path="with_path" in self.ebands_ksamp_checkbox.value,
|
||||
with_ibz="with_ibz" in self.ebands_ksamp_checkbox.value,
|
||||
verbose=self.verbose.value,
|
||||
with_spglib=False
|
||||
)
|
||||
# df, ebands_plotter = self.flow.compare_ebands(
|
||||
# nids=None, # select_nids(flow, options),
|
||||
# with_path="with_path" in self.ebands_ksamp_checkbox.value,
|
||||
# with_ibz="with_ibz" in self.ebands_ksamp_checkbox.value,
|
||||
# verbose=self.verbose.value,
|
||||
# with_spglib=False
|
||||
# )
|
||||
|
||||
if ebands_plotter is None:
|
||||
return
|
||||
# if ebands_plotter is None:
|
||||
# return
|
||||
|
||||
plot_mode = self.ebands_plotter_mode.value
|
||||
plotfunc = getattr(ebands_plotter, plot_mode, None)
|
||||
if plotfunc is None:
|
||||
raise ValueError("Don't know how to handle plot_mode: %s" % plot_mode)
|
||||
# plot_mode = self.ebands_plotter_mode.value
|
||||
# plotfunc = getattr(ebands_plotter, plot_mode, None)
|
||||
# if plotfunc is None:
|
||||
# raise ValueError("Don't know how to handle plot_mode: %s" % plot_mode)
|
||||
|
||||
fig = plotfunc(**self.fig_kwargs)
|
||||
col = pn.Column(self._mp(fig))
|
||||
if self.ebands_df_checkbox.value:
|
||||
col.append(self._df(df))
|
||||
# fig = plotfunc(**self.mpl_kwargs)
|
||||
# col = pn.Column(mpl(fig))
|
||||
# if self.ebands_df_checkbox.value:
|
||||
# col.append(dfc(df))
|
||||
|
||||
return pn.Row(col) #, sizing_mode='scale_width')
|
||||
# return pn.Row(col) #, sizing_mode='scale_width')
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, as_dict=False, **kwargs):
|
||||
"""Return tabs with widgets to interact with the flow."""
|
||||
tabs = pn.Tabs(); app = tabs.append
|
||||
|
||||
d = {}
|
||||
|
||||
#row = pn.Row(bkw.PreText(text=self.ddb.to_string(verbose=self.verbose.value), sizing_mode="scale_both"))
|
||||
app(("Status", pn.Row(self.status_btn, self.on_status_btn)))
|
||||
app(("History", pn.Row(self.history_btn, self.on_history_btn)))
|
||||
app(("Events", pn.Row(self.events_btn, self.on_events_btn)))
|
||||
app(("Corrections", pn.Row(self.corrections_btn, self.on_corrections_btn)))
|
||||
app(("Handlers", pn.Row(self.handlers_btn, self.on_handlers_btn)))
|
||||
app(("Structures", pn.Row(pn.Column(self.structures_io_checkbox, self.structures_btn), self.on_structures_btn)))
|
||||
d["Status"] = pn.Row(self.status_btn, self.on_status_btn)
|
||||
d["History"] = pn.Row(self.history_btn, self.on_history_btn)
|
||||
d["Events"] = pn.Row(self.events_btn, self.on_events_btn)
|
||||
d["Corrections"] = pn.Row(self.corrections_btn, self.on_corrections_btn)
|
||||
d["Handlers"] = pn.Row(self.handlers_btn, self.on_handlers_btn)
|
||||
d["Structures"] = pn.Row(pn.Column(self.structures_io_checkbox, self.structures_btn), self.on_structures_btn)
|
||||
ws = pn.Column(self.ebands_plotter_mode, self.ebands_ksamp_checkbox, self.ebands_df_checkbox, self.ebands_plotter_btn)
|
||||
app(("Ebands", pn.Row(ws, self.on_ebands_btn)))
|
||||
app(("Abivars", pn.Row(pn.Column(self.vars_text, self.vars_btn), self.on_vars_btn)))
|
||||
app(("Dims", pn.Row(pn.Column(self.dims_btn), self.on_dims_btn)))
|
||||
app(("Debug", pn.Row(self.debug_btn, self.on_debug_btn)))
|
||||
app(("Graphviz", pn.Row(pn.Column(self.engine, self.dirtree, self.graphviz_btn),
|
||||
self.on_graphviz_btn)))
|
||||
return tabs
|
||||
#d["Ebands"] = pn.Row(ws, self.on_ebands_btn)
|
||||
d["Abivars"] = pn.Row(pn.Column(self.vars_text, self.vars_btn), self.on_vars_btn)
|
||||
d["Dims"] = pn.Row(pn.Column(self.dims_btn), self.on_dims_btn)
|
||||
d["Debug"] = pn.Row(self.debug_btn, self.on_debug_btn)
|
||||
d["Graphviz"] = pn.Row(pn.Column(self.engine, self.dirtree, self.graphviz_btn), self.on_graphviz_btn)
|
||||
|
||||
if as_dict: return d
|
||||
tabs = pn.Tabs(*d.items())
|
||||
return self.get_template_from_tabs(tabs, template=kwargs.get("template", None)
|
||||
|
|
|
@ -1,91 +1,116 @@
|
|||
"""Panels to interact with GSR files."""
|
||||
|
||||
import param
|
||||
import panel as pn
|
||||
import panel.widgets as pnw
|
||||
import bokeh.models.widgets as bkw
|
||||
|
||||
from .core import PanelWithElectronBands, PanelWithEbandsRobot
|
||||
from .core import (PanelWithElectronBands, HasStructureParams, PanelWithNcFile,
|
||||
PanelWithEbandsRobot, ButtonContext, ply, mpl, dfc, depends_on_btn_click)
|
||||
|
||||
|
||||
class GsrFilePanel(PanelWithElectronBands):
|
||||
class GsrFilePanel(PanelWithElectronBands, HasStructureParams, PanelWithNcFile):
|
||||
"""
|
||||
Panel with widgets to interact with a |GsrFile|.
|
||||
"""
|
||||
def __init__(self, gsr, **params):
|
||||
super().__init__(**params)
|
||||
self.gsr = gsr
|
||||
super().__init__(**params)
|
||||
|
||||
@property
|
||||
def structure(self):
|
||||
"""|Structure| object"""
|
||||
return self.gsr.structure
|
||||
|
||||
@property
|
||||
def ebands(self):
|
||||
"""|ElectronBands|."""
|
||||
"""|ElectronBands| object."""
|
||||
return self.gsr.ebands
|
||||
|
||||
def get_panel(self):
|
||||
"""Return tabs with widgets to interact with the DDB file."""
|
||||
@property
|
||||
def ncfile(self):
|
||||
"""This for for the PanelWithNcFile mixin"""
|
||||
return self.gsr
|
||||
|
||||
#def info(method_name):
|
||||
# # Add accordion after the button with warning and help taken from the docstring of the callback
|
||||
# col = pn.Column(); ca = col.append
|
||||
# acc = pn.Accordion(("Help", pn.pane.Markdown(getattr(self, method_name).__doc__)))
|
||||
# acc.append(("Warning", self.warning_md))
|
||||
# ca(pn.layout.Divider())
|
||||
# ca(acc)
|
||||
# return col
|
||||
def get_panel(self, as_dict=False, **kwargs):
|
||||
"""Return tabs with widgets to interact with the GSR file."""
|
||||
d = {}
|
||||
|
||||
|
||||
tabs = pn.Tabs(); app = tabs.append
|
||||
|
||||
app(("Summary",
|
||||
pn.Row(bkw.PreText(text=self.gsr.to_string(verbose=self.verbose), sizing_mode="scale_both"))
|
||||
))
|
||||
app(("e-Bands", pn.Row(
|
||||
self.get_plot_ebands_widgets(),
|
||||
self.on_plot_ebands_btn)
|
||||
))
|
||||
|
||||
# Add DOS tab only if k-sampling.
|
||||
d["Summary"] = pn.Row(
|
||||
bkw.PreText(text=self.gsr.to_string(verbose=self.verbose), sizing_mode="scale_both")
|
||||
)
|
||||
d["e-Bands"] = pn.Row(
|
||||
pn.Column("### e-Bands Options", self.get_plot_ebands_widgets(), self.helpc("on_plot_ebands_btn"),
|
||||
self.on_plot_ebands_btn),
|
||||
)
|
||||
# Add DOS tab but only if k-sampling.
|
||||
kpoints = self.gsr.ebands.kpoints
|
||||
if kpoints.is_ibz:
|
||||
app(("e-DOS", pn.Row(
|
||||
self.get_plot_edos_widgets(), self.on_plot_edos_btn)
|
||||
))
|
||||
d["e-DOS"] = pn.Row(
|
||||
pn.Column("### Options", self.get_plot_edos_widgets(), self.helpc("on_plot_edos_btn")),
|
||||
self.on_plot_edos_btn
|
||||
)
|
||||
|
||||
if self.gsr.ebands.supports_fermi_surface:
|
||||
# Fermi surface requires gamma-centered k-mesh
|
||||
app(("Fermi Surface", pn.Row(
|
||||
self.get_plot_fermi_surface_widgets(), self.on_plot_fermi_surface_btn)))
|
||||
d["SKW"] = self.get_plot_skw_widgets()
|
||||
|
||||
return tabs
|
||||
#if self.gsr.ebands.supports_fermi_surface:
|
||||
# # Fermi surface requires Gamma-centered k-mesh
|
||||
# app(("Fermi Surface", pn.Row(
|
||||
# pn.Column("# Options",
|
||||
# self.get_plot_fermi_surface_widgets(),
|
||||
# self.helpc("on_plot_fermi_surface_btn"),
|
||||
# ),
|
||||
# self.on_plot_fermi_surface_btn)
|
||||
# ))
|
||||
|
||||
d["Structure"] = self.get_struct_view_tab_entry()
|
||||
# TODO
|
||||
#app(("NcFile", self.get_ncfile_panel()))
|
||||
|
||||
#app(("Global", pn.Row(
|
||||
# pn.Column("# Global options",
|
||||
# *self.pws("units", "mpi_procs", "verbose"),
|
||||
# ),
|
||||
# self.get_software_stack())
|
||||
#))
|
||||
|
||||
if as_dict: return d
|
||||
tabs = pn.Tabs(*d.items())
|
||||
return self.get_template_from_tabs(tabs, template=kwargs.get("template", None))
|
||||
|
||||
|
||||
class GsrRobotPanel(PanelWithEbandsRobot):
|
||||
"""
|
||||
A Panel to interoperate with multiple GSR files.
|
||||
"""
|
||||
|
||||
gsr_dataframe_btn = pnw.Button(name="Compute", button_type='primary')
|
||||
|
||||
transpose_gsr_dataframe = pnw.Checkbox(name='Transpose GSR dataframe')
|
||||
|
||||
def __init__(self, robot, **params):
|
||||
super().__init__(**params)
|
||||
self.robot = robot
|
||||
|
||||
@param.depends("gsr_dataframe_btn.clicks")
|
||||
@depends_on_btn_click('gsr_dataframe_btn_btn')
|
||||
def on_gsr_dataframe_btn(self):
|
||||
if self.gsr_dataframe_btn.clicks == 0: return
|
||||
df = self.robot.get_dataframe(with_geo=True)
|
||||
return pn.Column(self._df(df), sizing_mode='stretch_width')
|
||||
transpose = self.transpose_gsr_dataframe.value
|
||||
return pn.Column(dfc(df, transpose=transpose), sizing_mode='stretch_width')
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, **kwargs):
|
||||
"""Return tabs with widgets to interact with the |GsrRobot|."""
|
||||
tabs = pn.Tabs(); app = tabs.append
|
||||
app(("Summary", pn.Row(bkw.PreText(text=self.robot.to_string(verbose=self.verbose),
|
||||
sizing_mode="scale_both"))))
|
||||
app(("e-Bands", pn.Row(self.get_ebands_plotter_widgets(), self.on_ebands_plotter_btn)))
|
||||
d = {}
|
||||
d["Summary"] = pn.Row(bkw.PreText(text=self.robot.to_string(verbose=self.verbose),
|
||||
sizing_mode="scale_both"))
|
||||
d["e-Bands"] = pn.Row(self.get_ebands_plotter_widgets(), self.on_ebands_plotter_btn)
|
||||
|
||||
# Add e-DOS tab only if all ebands have k-sampling.
|
||||
# Add e-DOS tab but only if all ebands have k-sampling.
|
||||
if all(abifile.ebands.kpoints.is_ibz for abifile in self.robot.abifiles):
|
||||
app(("e-DOS", pn.Row(self.get_edos_plotter_widgets(), self.on_edos_plotter_btn)))
|
||||
d["e-DOS"] = pn.Row(self.get_edos_plotter_widgets(), self.on_edos_plotter_btn)
|
||||
|
||||
app(("GSR-DataFrame", pn.Row(self.gsr_dataframe_btn, self.on_gsr_dataframe_btn)))
|
||||
d["GSR-dataframe"] = pn.Row(
|
||||
pn.Column(self.transpose_gsr_dataframe, self.gsr_dataframe_btn),
|
||||
self.on_gsr_dataframe_btn)
|
||||
|
||||
return tabs
|
||||
tabs = pn.Tabs(*d.items())
|
||||
return self.get_template_from_tabs(tabs, template=kwargs.get("template", None))
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
""""Panels for HIST files."""
|
||||
import param
|
||||
import panel as pn
|
||||
import panel.widgets as pnw
|
||||
import bokeh.models.widgets as bkw
|
||||
|
||||
from abipy.panels.core import sizing_mode_select, AbipyParameterized, ButtonContext
|
||||
from abipy.panels.core import AbipyParameterized, ButtonContext, mpl, ply, depends_on_btn_click
|
||||
|
||||
|
||||
_what_list = ["pressure", "forces", "energy", "abc", "angles", "volume"]
|
||||
|
@ -13,60 +14,57 @@ class HistFilePanel(AbipyParameterized):
|
|||
"""
|
||||
Panel with widgets to interact with a |HistFile|.
|
||||
"""
|
||||
what_list = pn.widgets.CheckBoxGroup(name="Select", value=_what_list, options=_what_list, inline=False)
|
||||
plot_relax_btn = pn.widgets.Button(name="Show relaxation", button_type="primary")
|
||||
|
||||
sizing_mode = sizing_mode_select(value="stretch_width")
|
||||
|
||||
appname = pn.widgets.Select(name="Viewer", value="ovito", options=["ovito", "mayavi", "vtk"])
|
||||
to_unit_cell = pn.widgets.Checkbox(name="To unit cell")
|
||||
view_relax_btn = pn.widgets.Button(name="View relaxation", button_type="primary")
|
||||
|
||||
def __init__(self, hist, **params):
|
||||
super().__init__(**params)
|
||||
self.hist = hist
|
||||
self.what_list = pnw.CheckBoxGroup(name="Select", value=_what_list, options=_what_list, inline=False)
|
||||
self.plot_relax_btn = pnw.Button(name="Show relaxation", button_type="primary")
|
||||
|
||||
self.appname = pnw.Select(name="Viewer", value="ovito", options=["ovito", "mayavi", "vtk"])
|
||||
self.to_unit_cell = pnw.Checkbox(name="To unit cell")
|
||||
self.view_relax_btn = pnw.Button(name="View relaxation", button_type="primary")
|
||||
|
||||
super().__init__(**params)
|
||||
|
||||
def get_plot_relax_widgets(self):
|
||||
"""Widgets to visualize the structure relaxation."""
|
||||
return pn.Column(self.what_list, self.sizing_mode, self.plot_relax_btn)
|
||||
return pn.Column(self.what_list, self.plot_relax_btn, sizing_mode="stretch_width")
|
||||
|
||||
@param.depends('plot_relax_btn.clicks')
|
||||
@depends_on_btn_click('plot_relax_btn')
|
||||
def on_plot_relax_btn(self):
|
||||
"""
|
||||
Plot the evolution of structural parameters (lattice lengths, angles and volume)
|
||||
as well as pressure, info on forces and total energy.
|
||||
"""
|
||||
if self.plot_relax_btn.clicks == 0: return
|
||||
num_plots, nrows, ncols = len(self.what_list.value), 1, 1
|
||||
if num_plots > 1:
|
||||
ncols = 2
|
||||
nrows = (num_plots // ncols) + (num_plots % ncols)
|
||||
|
||||
with ButtonContext(self.plot_relax_btn):
|
||||
box = pn.GridBox(nrows=nrows, ncols=ncols, sizing_mode=self.sizing_mode.value) #'scale_width')
|
||||
for i, what in enumerate(self.what_list.value):
|
||||
irow, icol = divmod(i, ncols)
|
||||
box.append(mpl(self.hist.plot(what, title=what, **self.mpl_kwargs)))
|
||||
|
||||
num_plots, nrows, ncols = len(self.what_list.value), 1, 1
|
||||
if num_plots > 1:
|
||||
ncols = 2
|
||||
nrows = (num_plots // ncols) + (num_plots % ncols)
|
||||
return box
|
||||
#return pn.Column(box, box.controls(jslink=True))
|
||||
|
||||
box = pn.GridBox(nrows=nrows, ncols=ncols, sizing_mode=self.sizing_mode.value) #'scale_width')
|
||||
for i, what in enumerate(self.what_list.value):
|
||||
irow, icol = divmod(i, ncols)
|
||||
box.append(self._mp(self.hist.plot(what, title=what, **self.fig_kwargs)))
|
||||
|
||||
return box
|
||||
#return pn.Column(box, box.controls(jslink=True))
|
||||
|
||||
@param.depends('view_relax_btn.clicks')
|
||||
@depends_on_btn_click('view_relax_btn')
|
||||
def on_view_relax_btn(self):
|
||||
if self.view_relax_btn.clicks == 0: return
|
||||
return self.hist.visualize(appname=self.appname.value, to_unit_cell=self.to_unit_cell.value)
|
||||
|
||||
with ButtonContext(self.view_relax_btn):
|
||||
return self.hist.visualize(appname=self.appname.value, to_unit_cell=self.to_unit_cell.value)
|
||||
def get_panel(self, as_dict=False, **kwargs):
|
||||
"""Return tabs with widgets to interact with the HIST.nc file."""
|
||||
d = {}
|
||||
|
||||
def get_panel(self):
|
||||
"""Return tabs with widgets to interact with the DDB file."""
|
||||
tabs = pn.Tabs()
|
||||
tabs.append(("Summary", pn.Row(bkw.PreText(text=self.hist.to_string(verbose=self.verbose),
|
||||
sizing_mode="scale_both"))))
|
||||
tabs.append(("Relaxation", pn.Row(self.get_plot_relax_widgets(), self.on_plot_relax_btn)))
|
||||
tabs.append(("Visualize", pn.Row(pn.Column(self.appname, self.to_unit_cell, self.view_relax_btn),
|
||||
self.on_view_relax_btn)))
|
||||
d["Summary"] = pn.Row(bkw.PreText(text=self.hist.to_string(verbose=self.verbose),
|
||||
sizing_mode="scale_both"))
|
||||
|
||||
return tabs
|
||||
d["Relaxation"] = pn.Row(self.get_plot_relax_widgets(), self.on_plot_relax_btn)
|
||||
|
||||
d["Visualize"] = pn.Row(pn.Column(self.appname, self.to_unit_cell, self.view_relax_btn),
|
||||
self.on_view_relax_btn)
|
||||
|
||||
if as_dict: return d
|
||||
tabs = pn.Tabs(*d.items())
|
||||
return self.get_template_from_tabs(tabs, template=kwargs.get("template", None))
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
import panel as pn
|
||||
#import panel.widgets as pnw
|
||||
import bokeh.models.widgets as bkw
|
||||
from abipy.panels.core import AbipyParameterized #, ButtonContext
|
||||
from abipy.panels.core import AbipyParameterized, mpl, ply, dfc #, ButtonContext
|
||||
|
||||
|
||||
class AbinitOutputFilePanel(AbipyParameterized):
|
||||
"""
|
||||
Panel with widgets to interact with an Abinit output file.
|
||||
Panel with widgets to interact with the Abinit main output file.
|
||||
"""
|
||||
def __init__(self, outfile, **params):
|
||||
super().__init__(**params)
|
||||
|
@ -33,28 +33,31 @@ class AbinitOutputFilePanel(AbipyParameterized):
|
|||
|
||||
box = pn.GridBox(nrows=nrows, ncols=ncols) #, sizing_mode='scale_both')
|
||||
for icycle, cycle in enumerate(cycles):
|
||||
box.append(self._mp(cycle.plot(title="%s cycle #%d" % (what, icycle), **self.fig_kwargs)))
|
||||
box.append(mpl(cycle.plot(title="%s cycle #%d" % (what, icycle), **self.mpl_kwargs)))
|
||||
|
||||
return box
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, as_dict=True, **kwargs):
|
||||
"""Return tabs with widgets to interact with the Abinit output file."""
|
||||
tabs = pn.Tabs(); app = tabs.append
|
||||
d = {}
|
||||
|
||||
app(("Summary", pn.Row(
|
||||
bkw.PreText(text=self.outfile.to_string(verbose=self.verbose), sizing_mode="scale_both"))
|
||||
))
|
||||
d["Summary"] = pn.Row(
|
||||
bkw.PreText(text=self.outfile.to_string(verbose=self.verbose), sizing_mode="scale_both")
|
||||
)
|
||||
df = self.outfile.get_dims_spginfo_dataframe().transpose()
|
||||
df.index.name = "Dataset"
|
||||
app(("Dims", self._df(df)))
|
||||
d["Dims"] = dfc(df)
|
||||
|
||||
# Add tabs with plots for the GS/DFPT SCF cycles.
|
||||
for what in ("GS", "DFPT"):
|
||||
box = self._get_gridbox(what)
|
||||
if box is not None:
|
||||
app(("%s cycles" % what, box))
|
||||
d["%s cycles" % what] = box
|
||||
|
||||
#timer = self.get_timer()
|
||||
#timer.plot_all(**self.fig_kwargs)
|
||||
#timer.plot_all(**self.mpl_kwargs)
|
||||
|
||||
return tabs
|
||||
if as_dict: return d
|
||||
|
||||
tabs = pn.Tabs(*d.items())
|
||||
return self.get_template_from_tabs(tabs, template=kwargs.get("template", None))
|
||||
|
|
|
@ -3,41 +3,41 @@ import param
|
|||
import panel as pn
|
||||
import panel.widgets as pnw
|
||||
|
||||
from abipy.panels.core import AbipyParameterized, ButtonContext
|
||||
from abipy.panels.core import AbipyParameterized, ButtonContext, mpl, ply, dfc, depends_on_btn_click
|
||||
|
||||
|
||||
class PhononBandsPlotterPanel(AbipyParameterized):
|
||||
|
||||
phbands_plotter_mode = pnw.Select(name="Plot Mode", value="gridplot",
|
||||
options=["gridplot", "combiplot", "boxplot", "combiboxplot"]) # "animate",
|
||||
phbands_plotter_units = pnw.Select(name="Units", value="eV",
|
||||
options=["eV", "meV", "Ha", "cm-1", "Thz"])
|
||||
phbands_plotter_btn = pnw.Button(name="Plot", button_type='primary')
|
||||
|
||||
def __init__(self, plotter, **params):
|
||||
super().__init__(**params)
|
||||
|
||||
self.phbands_plotter_mode = pnw.Select(name="Plot Mode", value="gridplot",
|
||||
options=["gridplot", "combiplot", "boxplot", "combiboxplot"]) # "animate",
|
||||
self.phbands_plotter_units = pnw.Select(name="Units", value="eV",
|
||||
options=["eV", "meV", "Ha", "cm-1", "Thz"])
|
||||
self.phbands_plotter_btn = pnw.Button(name="Plot", button_type='primary')
|
||||
|
||||
self.plotter = plotter
|
||||
super().__init__(**params)
|
||||
|
||||
@param.depends("phbands_plotter_btn.clicks")
|
||||
@depends_on_btn_click('phbands_blotter_btn')
|
||||
def on_phbands_plot_btn(self):
|
||||
if self.phbands_plotter_btn.clicks == 0: return
|
||||
plot_mode = self.phbands_plotter_mode.value
|
||||
plotfunc = getattr(self.plotter, plot_mode, None)
|
||||
if plotfunc is None:
|
||||
raise ValueError("Don't know how to handle plot_mode: %s" % plot_mode)
|
||||
|
||||
with ButtonContext(self.phbands_plotter_btn):
|
||||
fig = plotfunc(units=self.phbands_plotter_units.value, **self.mpl_kwargs)
|
||||
df = self.plotter.get_phbands_frame(with_spglib=True)
|
||||
return pn.Row(pn.Column(mpl(fig), dfc(df)), sizing_mode='scale_width')
|
||||
|
||||
plot_mode = self.phbands_plotter_mode.value
|
||||
plotfunc = getattr(self.plotter, plot_mode, None)
|
||||
if plotfunc is None:
|
||||
raise ValueError("Don't know how to handle plot_mode: %s" % plot_mode)
|
||||
|
||||
fig = plotfunc(units=self.phbands_plotter_units.value, **self.fig_kwargs)
|
||||
df = self.plotter.get_phbands_frame(with_spglib=True)
|
||||
return pn.Row(pn.Column(self._mp(fig), self._df(df)), sizing_mode='scale_width')
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, as_dict=False, **kwargs):
|
||||
"""Return tabs with widgets to interact with the |PhononBandsPlotter|."""
|
||||
tabs = pn.Tabs() #; app = tabs.append
|
||||
d = {}
|
||||
|
||||
ws = pn.Column(self.phbands_plotter_mode, self.phbands_plotter_units, self.phbands_plotter_btn)
|
||||
tabs.append(("PhbandsPlotter", pn.Row(ws, self.on_phbands_plot_btn, sizing_mode='scale_width')))
|
||||
d["PhbandsPlotter"] = pn.Row(ws, self.on_phbands_plot_btn, sizing_mode='scale_width')
|
||||
|
||||
return tabs
|
||||
if as_dict: return d
|
||||
|
||||
tabs = pn.Tabs(*d.items())
|
||||
return self.get_template_from_tabs(tabs, template=kwargs.get("template", None))
|
||||
|
|
|
@ -14,7 +14,7 @@ from abipy.abilab import abiopen, extcls_supporting_panel
|
|||
|
||||
class UploadFile(param.Parameterized):
|
||||
|
||||
file_input = pn.widgets.FileInput()
|
||||
file_input = pnw.FileInput()
|
||||
|
||||
abipath = param.Filename()
|
||||
#ready = param.Boolean(default=False, precedence=-1)
|
||||
|
@ -112,7 +112,7 @@ def analyze_file_app(**kwargs):
|
|||
|
||||
#class UploadFiles(param.Parameterized):
|
||||
#
|
||||
# file_inputs = pn.widgets.FileInput(multiple=True)
|
||||
# file_inputs = pnw.FileInput(multiple=True)
|
||||
#
|
||||
# #abipath = param.Filename()
|
||||
#
|
||||
|
|
|
@ -5,295 +5,159 @@ import panel as pn
|
|||
import panel.widgets as pnw
|
||||
import bokeh.models.widgets as bkw
|
||||
|
||||
from abipy.panels.core import AbipyParameterized, gen_id, ButtonContext
|
||||
|
||||
pn.config.js_files.update({
|
||||
#'$': 'https://code.jquery.com/jquery-3.4.1.slim.min.js',
|
||||
"clipboard": "https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js",
|
||||
})
|
||||
|
||||
#pn.config.js_files["ngl"] = "https://cdn.jsdelivr.net/gh/arose/ngl@v2.0.0-dev.33/dist/ngl.js"
|
||||
from abipy.panels.core import HasStructureParams, ButtonContext, dfc, mpl, ply, depends_on_btn_click
|
||||
|
||||
|
||||
_html_with_copy_to_clipboard_ncalls = 0
|
||||
|
||||
|
||||
def html_with_copy_to_clipboard(html, btn_cls="btn-primary btn-sm"):
|
||||
global _html_with_copy_to_clipboard_ncalls
|
||||
_html_with_copy_to_clipboard_ncalls += 1
|
||||
myid = gen_id()
|
||||
html = f"""
|
||||
<button class="btn {btn_cls}" data-clipboard-target="#{myid}"> Copy to clipboard </button>
|
||||
<div id="{myid}"> {html} </div>
|
||||
"""
|
||||
if _html_with_copy_to_clipboard_ncalls == 1:
|
||||
html += "<script>$(document).ready(function () {new ClipboardJS('.btn')})</script>"
|
||||
|
||||
return pn.pane.HTML(html)
|
||||
|
||||
|
||||
class StructurePanel(AbipyParameterized):
|
||||
class StructurePanel(HasStructureParams):
|
||||
"""
|
||||
Panel with widgets to interact with an AbiPy Structure
|
||||
"""
|
||||
verbose = param.Integer(0, bounds=(0, None), doc="Verbosity Level")
|
||||
|
||||
# Convert widgets.
|
||||
output_format = pnw.Select(name="format", value="abinit",
|
||||
options="abinit,cif,xsf,poscar,qe,siesta,wannier90,cssr,json".split(","))
|
||||
|
||||
# Spglib widgets
|
||||
spglib_symprec = pnw.Spinner(name="symprec", value=0.01, start=0.0, end=None, step=0.01)
|
||||
spglib_angtol = pnw.Spinner(name="angtol", value=5, start=0.0, end=None, step=1)
|
||||
|
||||
# K-path widgets
|
||||
kpath_format = pnw.Select(name="format", value="abinit", options=["abinit", "siesta", "wannier90"])
|
||||
line_density = pnw.Spinner(name="line density", value=10, step=5, start=0, end=None)
|
||||
|
||||
# Viewer widgets.
|
||||
viewer_btn = pnw.Button(name="View structure", button_type='primary')
|
||||
viewer = pnw.Select(name="Viewer", value="vesta",
|
||||
options=["jsmol", "vesta", "xcrysden", "vtk", "crystalk", "ngl", "matplotlib", "mayavi"])
|
||||
|
||||
# Mp-match
|
||||
mp_match_btn = pnw.Button(name="Connect to Materials Project", button_type='primary')
|
||||
|
||||
# Mp-search
|
||||
#mp_search_btn = pnw.Button(name="Connect to Materials Project", button_type='primary')
|
||||
#mp_api_key
|
||||
|
||||
# GS input generator widgets.
|
||||
gs_input_btn = pnw.Button(name="Generate input", button_type='primary')
|
||||
gs_type = pnw.Select(name="GS type", value="scf", options=["scf", "relax"])
|
||||
kppra = pnw.Spinner(name="kppra", value=1000, step=1000, start=0, end=None)
|
||||
|
||||
label2mode = {
|
||||
"unpolarized": 'unpolarized',
|
||||
"polarized": 'polarized',
|
||||
"anti-ferromagnetic": "afm",
|
||||
"non-collinear with magnetism": "spinor",
|
||||
"non-collinear, no magnetism": "spinor_nomag",
|
||||
}
|
||||
|
||||
spin_mode = pnw.Select(name="SpinMode", value="unpolarized", options=list(label2mode.keys()))
|
||||
|
||||
def __init__(self, structure, **params):
|
||||
super().__init__(**params)
|
||||
self.structure = structure
|
||||
self._structure = structure
|
||||
|
||||
@param.depends("output_format.value")
|
||||
# Convert widgets.
|
||||
self.output_format = pnw.Select(name="format", value="abinit",
|
||||
options="abinit,cif,xsf,poscar,qe,siesta,wannier90,cssr,json".split(","))
|
||||
|
||||
# Spglib widgets
|
||||
self.spglib_symprec = pnw.Spinner(name="symprec", value=0.01, start=0.0, end=None, step=0.01)
|
||||
self.spglib_angtol = pnw.Spinner(name="angtol", value=5, start=0.0, end=None, step=1)
|
||||
|
||||
# K-path widgets
|
||||
self.kpath_format = pnw.Select(name="format", value="abinit", options=["abinit", "siesta", "wannier90"])
|
||||
self.line_density = pnw.Spinner(name="line density", value=10, step=5, start=0, end=None)
|
||||
self.plot_kpath = pnw.Checkbox(name='Plot k-path', value=False)
|
||||
|
||||
# MP-match
|
||||
self.mp_match_btn = pnw.Button(name="Connect to Materials Project", button_type='primary')
|
||||
|
||||
# MP-search
|
||||
#mp_search_btn = pnw.Button(name="Connect to Materials Project", button_type='primary')
|
||||
#mp_api_key
|
||||
|
||||
# GS input generator widgets.
|
||||
self.gs_input_btn = pnw.Button(name="Generate input", button_type='primary')
|
||||
self.gs_type = pnw.Select(name="GS type", value="scf", options=["scf", "relax"])
|
||||
self.kppra = pnw.Spinner(name="kppra", value=1000, step=1000, start=0, end=None)
|
||||
|
||||
self.label2mode = {
|
||||
"unpolarized": 'unpolarized',
|
||||
"polarized": 'polarized',
|
||||
"anti-ferromagnetic": "afm",
|
||||
"non-collinear with magnetism": "spinor",
|
||||
"non-collinear, no magnetism": "spinor_nomag",
|
||||
}
|
||||
|
||||
self.spin_mode = pnw.Select(name="SpinMode", value="unpolarized", options=list(self.label2mode.keys()))
|
||||
|
||||
super().__init__(**params)
|
||||
|
||||
@property
|
||||
def structure(self):
|
||||
return self._structure
|
||||
|
||||
@pn.depends("output_format.value")
|
||||
def convert(self):
|
||||
"""Convert the input structure to one of the format selected by the user."""
|
||||
return pn.Row(bkw.PreText(text=self.structure.convert(fmt=self.output_format.value)),
|
||||
sizing_mode='stretch_width')
|
||||
s = self.structure.convert(fmt=self.output_format.value)
|
||||
return self.html_with_clipboard_btn(f"<pre> {s} </pre>")
|
||||
|
||||
@param.depends("spglib_symprec.value", "spglib_angtol.value")
|
||||
@pn.depends("spglib_symprec.value", "spglib_angtol.value")
|
||||
def spglib_summary(self):
|
||||
"""Call spglib to find space group symmetries and Wyckoff positions."""
|
||||
s = self.structure.spget_summary(symprec=self.spglib_symprec.value,
|
||||
angle_tolerance=self.spglib_angtol.value)
|
||||
return pn.Row(bkw.PreText(text=s, sizing_mode='stretch_width'))
|
||||
|
||||
@param.depends("kpath_format.value", "line_density.value")
|
||||
@pn.depends("kpath_format.value", "line_density.value")
|
||||
def get_kpath(self):
|
||||
"""Generate high-symmetry k-path from input structure in ABINIT format.."""
|
||||
"""Generate high-symmetry k-path from input structure in the ABINIT format."""
|
||||
col = pn.Column(sizing_mode='stretch_width'); ca = col.append
|
||||
|
||||
s = self.structure.get_kpath_input_string(fmt=self.kpath_format.value,
|
||||
line_density=self.line_density.value)
|
||||
return pn.Row(bkw.PreText(text=s, sizing_mode='stretch_width'))
|
||||
ca(self.html_with_clipboard_btn(f"<pre> {s} </pre>"))
|
||||
|
||||
@param.depends("viewer_btn.clicks")
|
||||
def view(self):
|
||||
"""Visualize input structure."""
|
||||
if self.viewer_btn.clicks == 0: return
|
||||
if self.plot_kpath.value:
|
||||
ca("## Brillouin zone and **k**-path:")
|
||||
kpath_pane = ply(self.structure.plotly_bz(pmg_path=True, show=False), with_divider=False)
|
||||
df_kpts = dfc(self.structure.hsym_kpoints.get_highsym_datataframe(), with_divider=False)
|
||||
ca(pn.Row(kpath_pane, df_kpts))
|
||||
ca(pn.layout.Divider())
|
||||
|
||||
with ButtonContext(self.viewer_btn):
|
||||
v = self.viewer.value
|
||||
return col
|
||||
|
||||
if v == "jsmol":
|
||||
pn.extension(comms='ipywidgets') #, js_files=js_files)
|
||||
view = self.structure.get_jsmol_view()
|
||||
from ipywidgets_bokeh import IPyWidget
|
||||
view = IPyWidget(widget=view) #, width=800, height=300)
|
||||
#import ipywidgets as ipw
|
||||
from IPython.display import display
|
||||
#display(view)
|
||||
return pn.Row(display(view))
|
||||
|
||||
if v == "crystalk":
|
||||
view = self.structure.get_crystaltk_view()
|
||||
return pn.panel(view)
|
||||
|
||||
if v == "ngl":
|
||||
js_files = {'ngl': 'https://cdn.jsdelivr.net/gh/arose/ngl@v2.0.0-dev.33/dist/ngl.js'}
|
||||
pn.extension(comms='ipywidgets', js_files=js_files)
|
||||
view = self.structure.get_ngl_view()
|
||||
return pn.panel(view)
|
||||
|
||||
#pn.config.js_files["ngl"]="https://cdn.jsdelivr.net/gh/arose/ngl@v2.0.0-dev.33/dist/ngl.js"
|
||||
#pn.extension()
|
||||
|
||||
html = """<div id="viewport" style="width:100%; height:100%;"></div>
|
||||
<script>
|
||||
stage = new NGL.Stage("viewport");
|
||||
stage.loadFile("rcsb://1NKT.mmtf", {defaultRepresentation: true});
|
||||
</script>"""
|
||||
|
||||
# html = """
|
||||
# <script>
|
||||
# document.addeventlistener("domcontentloaded", function () {
|
||||
# var stage = new ngl.stage("viewport");
|
||||
# stage.loadfile("rcsb://1crn", {defaultrepresentation: true});
|
||||
# });
|
||||
# </script>"""
|
||||
|
||||
# html = """
|
||||
#<script>
|
||||
#document.addeventlistener("domcontentloaded", function () {
|
||||
# // create a `stage` object
|
||||
# var stage = new NGL.Stage("viewport");
|
||||
# // load a PDB structure and consume the returned `Promise`
|
||||
# stage.loadFile("rcsb://1CRN").then(function (component) {
|
||||
# // add a "cartoon" representation to the structure component
|
||||
# component.addRepresentation("cartoon");
|
||||
# // provide a "good" view of the structure
|
||||
# component.autoView();
|
||||
# });
|
||||
#});
|
||||
#</script>"""
|
||||
|
||||
ngl_pane = pn.pane.HTML(html, height=500, width=500)
|
||||
return pn.Row(ngl_pane)
|
||||
view = self.structure.get_ngl_view()
|
||||
|
||||
#return self.structure.crystaltoolkitview()
|
||||
#import nglview as nv
|
||||
#view = nv.demo(gui=False)
|
||||
|
||||
#from bokeh.models import ColumnDataSource
|
||||
#from bokeh.io import show, curdoc
|
||||
#from bokeh.models.widgets import Button, TextInput
|
||||
#from bokeh.layouts import layout, widgetbox
|
||||
#from jsmol_bokeh_extension import JSMol
|
||||
#script_source = ColumnDataSource()
|
||||
|
||||
#info = dict(
|
||||
# height="100%",
|
||||
# width="100%",
|
||||
# serverURL="https://chemapps.stolaf.edu/jmol/jsmol/php/jsmol.php",
|
||||
# use="HTML5",
|
||||
# j2sPath="https://chemapps.stolaf.edu/jmol/jsmol/j2s",
|
||||
# script=
|
||||
# "background black;load https://chemapps.stolaf.edu/jmol/jsmol-2013-09-18/data/caffeine.mol",
|
||||
#)
|
||||
|
||||
#applet = JSMol(
|
||||
# width=600,
|
||||
# height=600,
|
||||
# script_source=script_source,
|
||||
# info=info,
|
||||
#)
|
||||
|
||||
#button = Button(label='Execute')
|
||||
#inp_script = TextInput(value='background white;')
|
||||
|
||||
#def run_script():
|
||||
# script_source.data['script'] = [inp_script.value]
|
||||
|
||||
#button.on_click(run_script)
|
||||
#ly = layout([applet, widgetbox(button, inp_script)])
|
||||
#show(ly)
|
||||
#curdoc().add_root(ly)
|
||||
#return pn.Row(applet)
|
||||
return self.structure.visualize(appname=self.viewer.value)
|
||||
|
||||
@param.depends("gs_input_btn.clicks")
|
||||
@depends_on_btn_click('gs_input_btn')
|
||||
def on_gs_input_btn(self):
|
||||
"""Generate minimalistic input file from the input file."""
|
||||
if self.gs_input_btn.clicks == 0: return
|
||||
"""Generate minimalistic input file from the input structure."""
|
||||
from abipy.abio.factories import gs_input
|
||||
from abipy.data.hgh_pseudos import HGH_TABLE
|
||||
|
||||
with ButtonContext(self.gs_input_btn):
|
||||
from abipy.abio.factories import gs_input
|
||||
from abipy.data.hgh_pseudos import HGH_TABLE
|
||||
gs_inp = gs_input(
|
||||
self.structure, HGH_TABLE, kppa=self.kppra.value, ecut=8,
|
||||
spin_mode=self.label2mode[self.spin_mode.value],
|
||||
smearing=None)
|
||||
|
||||
gs_inp = gs_input(
|
||||
self.structure, HGH_TABLE, kppa=self.kppra.value, ecut=8,
|
||||
spin_mode=self.label2mode[self.spin_mode.value],
|
||||
smearing=None)
|
||||
gs_inp.pop_vars(("charge", "chksymbreak"))
|
||||
gs_inp.set_vars(ecut="?? # depends on pseudos",
|
||||
nband="?? # depends on pseudos",
|
||||
pseudos='"pseudo1, pseudo2, ..."'
|
||||
)
|
||||
|
||||
gs_inp.pop_vars(("charge", "chksymbreak"))
|
||||
gs_inp.set_vars(ecut="?? # depends on pseudos", nband="?? # depends on pseudos")
|
||||
if self.gs_type.value == "relax":
|
||||
gs_inp.set_vars(optcell=2, ionmov=2, ecutsm=0.5, dilatmx=1.05)
|
||||
|
||||
if self.gs_type.value == "relax":
|
||||
gs_inp.set_vars(optcell=2, ionmov=2, ecutsm=0.5, dilatmx=1.05)
|
||||
gs_inp.set_mnemonics(False)
|
||||
|
||||
gs_inp.set_mnemonics(False)
|
||||
return self.html_with_clipboard_btn(gs_inp._repr_html_())
|
||||
|
||||
return html_with_copy_to_clipboard(gs_inp._repr_html_())
|
||||
|
||||
@param.depends("mp_match_btn.clicks")
|
||||
@depends_on_btn_click('mp_match_btn')
|
||||
def on_mp_match_btn(self):
|
||||
"""Match input structure with the structures available on the materials project."""
|
||||
if self.mp_match_btn.clicks == 0: return
|
||||
from abipy.core.structure import mp_match_structure
|
||||
mp = mp_match_structure(self.structure, api_key=None, endpoint=None, final=True)
|
||||
if not mp.structures:
|
||||
raise RuntimeError("No structure found in the MP database")
|
||||
|
||||
with ButtonContext(self.mp_match_btn):
|
||||
from abipy.core.structure import mp_match_structure
|
||||
mp = mp_match_structure(self.structure, api_key=None, endpoint=None, final=True)
|
||||
if not mp.structures:
|
||||
raise RuntimeError("No structure found in MP database")
|
||||
return pn.Column(dfc(mp.lattice_dataframe), sizing_mode='stretch_width')
|
||||
|
||||
return pn.Column(self._df(mp.lattice_dataframe), sizing_mode='stretch_width')
|
||||
|
||||
#@param.depends("mp_search_btn.clicks")
|
||||
#@depends_on_btn_click('mp_search_btn')
|
||||
#def on_mp_search_btn(self):
|
||||
# if self.mp_search_btn.clicks == 0: return
|
||||
# from abipy.core.structure import mp_search
|
||||
# chemsys_formula_id = self.stucture.formula
|
||||
# mp = mp_search(chemsys_formula_id, api_key=None, endpoint=None, final=True)
|
||||
# if not mp.structures:
|
||||
# raise RuntimeError("No structure found in MP database")
|
||||
|
||||
# return pn.Column(self._df(mp.lattice_dataframe), sizing_mode='stretch_width')
|
||||
# return pn.Column(dfc(mp.lattice_dataframe), sizing_mode='stretch_width')
|
||||
|
||||
def get_panel(self):
|
||||
def get_panel(self, as_dict=False, **kwargs):
|
||||
"""Build panel with widgets to interact with the structure either in a notebook or in a bokeh app"""
|
||||
d = {}
|
||||
|
||||
def info(method_name):
|
||||
# Add accordion after the button with warning and help taken from the docstring of the callback
|
||||
col = pn.Column(); ca = col.append
|
||||
acc = pn.Accordion(("Help", pn.pane.Markdown(getattr(self, method_name).__doc__)))
|
||||
ca(pn.layout.Divider())
|
||||
ca(acc)
|
||||
return col
|
||||
d["Summary"] = pn.Row(bkw.PreText(text=self.structure.to_string(verbose=self.verbose),
|
||||
sizing_mode="scale_both"))
|
||||
d["Spglib"] = pn.Row(
|
||||
self.pws_col(['### Spglib options', "spglib_symprec", "spglib_angtol", self.helpc("spglib_summary")]),
|
||||
self.spglib_summary
|
||||
)
|
||||
d["Kpath"] = pn.Row(
|
||||
self.pws_col(['### K-path options', "kpath_format", "line_density", "plot_kpath", self.helpc("get_kpath")]),
|
||||
self.get_kpath
|
||||
)
|
||||
d["Convert"] = pn.Row(
|
||||
self.pws_col(["### Convert structure", "output_format", self.helpc("convert")]),
|
||||
self.convert
|
||||
)
|
||||
d["Structure"] = self.get_struct_view_tab_entry()
|
||||
d["GS-input"] = pn.Row(
|
||||
self.pws_col(['### Generate GS input', "gs_type", "spin_mode", "kppra", "gs_input_btn",
|
||||
self.helpc("on_gs_input_btn")]),
|
||||
self.on_gs_input_btn
|
||||
)
|
||||
d["MP-match"] = pn.Row(pn.Column(self.mp_match_btn), self.on_mp_match_btn)
|
||||
|
||||
tabs = pn.Tabs(); app = tabs.append
|
||||
if as_dict: return d
|
||||
|
||||
app(("Summary",
|
||||
pn.Row(bkw.PreText(text=self.structure.to_string(verbose=self.verbose), sizing_mode="scale_both"))
|
||||
))
|
||||
app(("Spglib", pn.Row(
|
||||
pn.Column('# Spglib options', *self.pws("spglib_symprec", "spglib_angtol", info("spglib_summary"))),
|
||||
self.spglib_summary)
|
||||
))
|
||||
app(("Kpath", pn.Row(
|
||||
pn.Column('# K-path options', *self.pws("kpath_format", "line_density", info("get_kpath"))),
|
||||
self.get_kpath)
|
||||
))
|
||||
app(("Convert", pn.Row(
|
||||
pn.Column("# Convert structure", *self.pws("output_format", info("convert"))),
|
||||
self.convert)
|
||||
))
|
||||
app(("View", pn.Row(
|
||||
pn.Column("# Visualize structure", *self.pws("viewer", "viewer_btn", info("view"))),
|
||||
self.view)
|
||||
))
|
||||
app(("GS-input", pn.Row(
|
||||
pn.Column('# Generate GS input', *self.pws("gs_type", "spin_mode", "kppra", "gs_input_btn",
|
||||
info("on_gs_input_btn"))),
|
||||
self.on_gs_input_btn)
|
||||
))
|
||||
app(("MP-match", pn.Row(
|
||||
pn.Column(self.mp_match_btn),
|
||||
self.on_mp_match_btn)
|
||||
))
|
||||
|
||||
return tabs
|
||||
tabs = pn.Tabs(*d.items())
|
||||
return self.get_template_from_tabs(tabs, template=kwargs.get("template", None))
|
||||
|
|
|
@ -377,7 +377,8 @@ def abicomp_phbands(options):
|
|||
|
||||
# Select the plot method to call.
|
||||
if options.plot_mode == "panel":
|
||||
plotter.get_panel().show()
|
||||
#template=options.panel_template)
|
||||
plotter.get_panel().show(debug=options.verbose > 0)
|
||||
|
||||
elif options.plot_mode != "None":
|
||||
plotfunc = getattr(plotter, options.plot_mode, None)
|
||||
|
@ -639,14 +640,11 @@ def _invoke_robot(options):
|
|||
no_browser=options.no_browser)
|
||||
|
||||
elif options.panel:
|
||||
try:
|
||||
import panel # noqa: F401
|
||||
except ImportError as exc:
|
||||
cprint("Use `conda install panel` or `pip install panel` to install the python package.", "red")
|
||||
raise exc
|
||||
abilab.abipanel()
|
||||
|
||||
if hasattr(robot, "get_panel"):
|
||||
robot.get_panel().show()
|
||||
app = robot.get_panel(template=options.panel_template)
|
||||
app.show(debug=options.verbose > 0)
|
||||
return 0
|
||||
else:
|
||||
cprint(f"`{type(robot)} does not provide get_panel method", color="red")
|
||||
|
@ -975,7 +973,7 @@ codes), a looser tolerance of 0.1 (the value used in Materials Project) is often
|
|||
help="Used if --expose to iterate over figures. Expose all figures at once if not given on the CLI.")
|
||||
expose_parser.add_argument("-t", "--slide-timeout", type=int, default=None,
|
||||
help="Close figure after slide-timeout seconds (only if slide-mode). Block if not specified.")
|
||||
expose_parser.add_argument("--plotly", default=False, action="store_true",
|
||||
expose_parser.add_argument("-ply", "--plotly", default=False, action="store_true",
|
||||
help='Generate plotly plots in browser instead of matplotlib. WARNING: Not all the features are supported.')
|
||||
expose_parser.add_argument("-cs", "--chart-studio", default=False, action="store_true",
|
||||
help="Push figure to plotly chart studio ." +
|
||||
|
@ -1089,6 +1087,11 @@ the full set of atoms. Note that a value larger than 0.01 is considered to be un
|
|||
robot_parser.add_argument('--no-walk', default=False, action="store_true", help="Don't enter subdirectories.")
|
||||
robot_parser.add_argument("-pn", '--panel', default=False, action="store_true",
|
||||
help="Open GUI in web browser, requires panel package. WARNING: Experimental")
|
||||
robot_parser.add_argument("-pnt", "--panel-template", default="FastList", type=str,
|
||||
help="Specify template for panel dasboard." +
|
||||
"Possible values are: FastList, FastGrid, Golden, Bootstrap, Material, React, Vanilla." +
|
||||
"Default: FastList"
|
||||
)
|
||||
|
||||
robot_parents = [copts_parser, robot_ipy_parser, robot_parser, expose_parser, pandas_parser]
|
||||
p_gsr = subparsers.add_parser('gsr', parents=robot_parents, help=abicomp_gsr.__doc__)
|
||||
|
|
|
@ -75,17 +75,20 @@ from abipy import abilab
|
|||
|
||||
def get_epilog():
|
||||
s = """\
|
||||
======================================================================================================
|
||||
Usage example:
|
||||
|
||||
abiopen.py FILE => Open file in ipython shell.
|
||||
abiopen.py FILE -nb => Generate jupyter notebook.
|
||||
abiopen.py FILE -p => Print info on object to terminal.
|
||||
abiopen.py FILE -e => Generate matplotlib figures automatically.
|
||||
Use -sns to activate seaborn settings.
|
||||
abiopen.py FILE -e --plotly => Generate plotly figures automatically. Show them in the BROWSER.
|
||||
abiopen.py FILE -eweb => Generate matplotlib figures, show them in the $BROWSER.
|
||||
abiopen.py FILE -ply => Generate plotly figures automatically. Show them in the $BROWSER.
|
||||
Note that not all FILEs support plotly.
|
||||
abiopen.py FILE --panel => Generate GUI in web BROWSER to interact with FILE
|
||||
abiopen.py FILE -pn => Generate GUI in web BROWSER to interact with FILE
|
||||
Requires panel package (WARNING: still under development!)
|
||||
abiopen.py FILE -nb => Generate jupyter-lab notebook.
|
||||
abiopen.py FILE -cnb => Generate classic jupyter notebook.
|
||||
|
||||
where `FILE` is any file supported by abipy/pymatgen e.g. Netcdf files, Abinit input, POSCAR, xsf.
|
||||
File extensions supported (including zipped files with extension in ".bz2", ".gz", ".z"):
|
||||
|
@ -94,6 +97,7 @@ Use `-v` to increase verbosity level (can be supplied multiple times e.g -vv).
|
|||
JSON file are supported as well. In this case, abiopen.py tries to reconstruct python objects
|
||||
assuming JSON document in MSONable format and then invokes ipython with the `data` object.
|
||||
Use `-e` or `--notebook` or `--panel` to print the JSON dictionary without reconstructing python objects.
|
||||
======================================================================================================
|
||||
|
||||
Table mapping file extension to AbiPy object:
|
||||
|
||||
|
@ -116,8 +120,8 @@ def get_parser(with_epilog=False):
|
|||
|
||||
# notebook options.
|
||||
parser.add_argument('-nb', '--notebook', action='store_true', default=False, help="Open file in jupyter notebook")
|
||||
parser.add_argument('--classic-notebook', action='store_true', default=False,
|
||||
help="Use classic notebook instead of jupyterlab.")
|
||||
parser.add_argument('--classic-notebook', "-cnb", action='store_true', default=False,
|
||||
help="Use classic jupyter notebook instead of jupyterlab.")
|
||||
parser.add_argument('--no-browser', action='store_true', default=False,
|
||||
help=("Start the jupyter server to serve the notebook "
|
||||
"but don't open the notebook in the browser.\n"
|
||||
|
@ -130,7 +134,13 @@ def get_parser(with_epilog=False):
|
|||
|
||||
# panel option
|
||||
parser.add_argument("-pn", '--panel', action='store_true', default=False,
|
||||
help="Open GUI in web browser, requires panel package.")
|
||||
help="Open Dashboard in web browser, requires panel package.")
|
||||
|
||||
parser.add_argument("-pnt", "--panel-template", default="FastList", type=str,
|
||||
help="Specify template for panel dasboard." +
|
||||
"Possible values are: FastList, FastGrid, Golden, Bootstrap, Material, React, Vanilla." +
|
||||
"Default: FastList"
|
||||
)
|
||||
|
||||
# Expose option.
|
||||
parser.add_argument('-e', '--expose', action='store_true', default=False,
|
||||
|
@ -145,11 +155,10 @@ def get_parser(with_epilog=False):
|
|||
help=("Set matplotlib interactive backend. "
|
||||
"Possible values: GTKAgg, GTK3Agg, GTK, GTKCairo, GTK3Cairo, WXAgg, WX, TkAgg, Qt4Agg, Qt5Agg, macosx."
|
||||
"See also: https://matplotlib.org/faq/usage_faq.html#what-is-a-backend."))
|
||||
parser.add_argument("--plotly", default=False, action="store_true",
|
||||
help='Generate plotly plots in browser instead of matplotlib. WARNING: Not all the features are supported.')
|
||||
parser.add_argument("-cs", "--chart-studio", default=False, action="store_true",
|
||||
help="Push figure to plotly chart studio. " +
|
||||
"Requires --plotly and user account at https://chart-studio.plotly.com.")
|
||||
parser.add_argument("-ew", "--expose-web", default=False, action="store_true",
|
||||
help='Generate matplotlib plots in $BROWSER instead of X-server. WARNING: Not all the features are supported.')
|
||||
parser.add_argument("-ply", "--plotly", default=False, action="store_true",
|
||||
help='Generate plotly plots in $BROWSER instead of matplotlib. WARNING: Not all the features are supported.')
|
||||
|
||||
return parser
|
||||
|
||||
|
@ -179,8 +188,12 @@ def main():
|
|||
raise ValueError('Invalid log level: %s' % options.loglevel)
|
||||
logging.basicConfig(level=numeric_level)
|
||||
|
||||
# Plotly automatically activate expose mode.
|
||||
##############################################################################################
|
||||
# Handle meta options i.e. options that set other options.
|
||||
# OK, it's not very clean but I haven't find any parse API to express this kind of dependency.
|
||||
##############################################################################################
|
||||
if options.plotly: options.expose = True
|
||||
if options.expose_web: options.expose = True
|
||||
if options.classic_notebook: options.notebook = True
|
||||
|
||||
if options.verbose > 2: print(options)
|
||||
|
@ -214,23 +227,24 @@ def main():
|
|||
return 0
|
||||
|
||||
elif options.expose:
|
||||
# Generate matplotlib plots automatically.
|
||||
# Print info to terminal
|
||||
if hasattr(abifile, "to_string"):
|
||||
print(abifile.to_string(verbose=options.verbose))
|
||||
else:
|
||||
print(abifile)
|
||||
|
||||
# Generate plots automatically.
|
||||
if options.plotly:
|
||||
# plotly version
|
||||
if hasattr(abifile, "plotly_expose"):
|
||||
abifile.plotly_expose(chart_studio=options.chart_studio, verbose=options.verbose)
|
||||
abifile.plotly_expose(verbose=options.verbose)
|
||||
else:
|
||||
cprint("`%s` does not implement plotly_expose method" % type(abifile), "red")
|
||||
|
||||
elif hasattr(abifile, "expose"):
|
||||
# matplotlib version
|
||||
abifile.expose(slide_mode=options.slide_mode, slide_timeout=options.slide_timeout,
|
||||
verbose=options.verbose)
|
||||
use_web=options.expose_web, verbose=options.verbose)
|
||||
else:
|
||||
if not hasattr(abifile, "yield_figs"):
|
||||
raise TypeError("Object of type `%s` does not implement (expose or yield_figs methods" % type(abifile))
|
||||
|
@ -242,25 +256,15 @@ def main():
|
|||
return 0
|
||||
|
||||
elif options.panel:
|
||||
try:
|
||||
import panel as pn
|
||||
except ImportError as exc:
|
||||
cprint("Use `conda install panel` or `pip install panel` to install the python package.", "red")
|
||||
raise exc
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
abilab.abipanel()
|
||||
|
||||
if not hasattr(abifile, "get_panel"):
|
||||
raise TypeError("Object of type `%s` does not implement get_panel method" % type(abifile))
|
||||
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
|
||||
#pn.extension("katex")
|
||||
try:
|
||||
pn.extension("plotly")
|
||||
except Exception:
|
||||
cprint("Use `conda install plotly` or `pip install plotly` to install the plotly package.", "red")
|
||||
|
||||
abifile.get_panel().show() # threaded=True)
|
||||
app = abifile.get_panel(template=options.panel_template)
|
||||
app.show(debug=options.verbose > 0)
|
||||
return 0
|
||||
|
||||
# Start ipython shell with namespace
|
||||
|
|
|
@ -1270,8 +1270,19 @@ def main():
|
|||
else:
|
||||
graph = node.get_graphviz(engine=options.engine)
|
||||
|
||||
if options.verbose:
|
||||
# Print DOT string. Can be used with e.g. http://viz-js.com/
|
||||
print(graph)
|
||||
|
||||
graph.view(directory=directory, cleanup=False)
|
||||
|
||||
if options.verbose > 1:
|
||||
# Write graph to file in png format.
|
||||
graph.format = "png"
|
||||
graph.attr(dpi=str(300))
|
||||
path = graph.render("graph", view=False, cleanup=False)
|
||||
print("Saving png file to:", path)
|
||||
|
||||
elif options.command == "listext":
|
||||
if not options.listexts:
|
||||
print("\nPlease specify the file extension(s), e.g. GSR SIGRES.\nList of available extensions:\n")
|
||||
|
|
|
@ -346,6 +346,11 @@ closest points in this particular structure. This is usually what you want in a
|
|||
|
||||
p_panel = subparsers.add_parser('panel', parents=[copts_parser, path_selector],
|
||||
help="Open GUI in web browser, requires panel package.")
|
||||
p_panel.add_argument("-pnt", "--panel-template", default="FastList", type=str,
|
||||
help="Specify template for panel dasboard." +
|
||||
"Possible values are: FastList, FastGrid, Golden, Bootstrap, Material, React, Vanilla." +
|
||||
"Default: FastList"
|
||||
)
|
||||
|
||||
# Subparser for kpath.
|
||||
p_kpath = subparsers.add_parser('kpath', parents=[copts_parser, path_selector],
|
||||
|
@ -763,13 +768,9 @@ def main():
|
|||
|
||||
elif options.command == "panel":
|
||||
structure = abilab.Structure.from_file(options.filepath)
|
||||
try:
|
||||
import panel # noqa: F401
|
||||
except ImportError as exc:
|
||||
cprint("Use `conda install panel` or `pip install panel` to install the python package.", "red")
|
||||
raise exc
|
||||
|
||||
structure.get_panel().show() #threaded=True)
|
||||
abilab.abipanel()
|
||||
app = structure.get_panel(template=options.panel_template)
|
||||
app.show(debug=options.verbose > 0)
|
||||
return 0
|
||||
|
||||
elif options.command == "visualize":
|
||||
|
|
|
@ -11,7 +11,7 @@ from monty.functools import prof_main
|
|||
from monty.termcolor import cprint
|
||||
from abipy import abilab
|
||||
from abipy.iotools.visualizer import Visualizer
|
||||
from abipy.tools.plotting import MplExpose, GenericDataFilePlotter, plotlyfigs_to_browser, push_to_chart_studio
|
||||
from abipy.tools.plotting import MplExpose, PanelExpose, GenericDataFilePlotter, plotlyfigs_to_browser, push_to_chart_studio
|
||||
|
||||
|
||||
def handle_overwrite(path, options):
|
||||
|
@ -124,10 +124,12 @@ def abiview_ebands(options):
|
|||
elif options.bxsf:
|
||||
outpath = options.filepath + ".bxsf"
|
||||
abifile.ebands.to_bxsf(handle_overwrite(outpath, options))
|
||||
#elif options.plotly:
|
||||
# print(abifile.to_string(verbose=options.verbose))
|
||||
else:
|
||||
print(abifile.to_string(verbose=options.verbose))
|
||||
abifile.expose_ebands(slide_mode=options.slide_mode, slide_timeout=options.slide_timeout,
|
||||
verbose=options.verbose)
|
||||
expose_web=options.expose_web, verbose=options.verbose)
|
||||
|
||||
return 0
|
||||
|
||||
|
@ -195,6 +197,7 @@ asr: {asr}, chneut: {chneut}, dipdip: {dipdip}, lo_to_splitting: {lo_to_splittin
|
|||
outpath = options.filepath + ".agr"
|
||||
phbands.to_xmgrace(handle_overwrite(outpath, options))
|
||||
return 0
|
||||
|
||||
#elif options.bxsf:
|
||||
# outpath = options.filepath + ".bxsf"
|
||||
# phbands.to_bxsf(handle_overwrite(outpath, options))
|
||||
|
@ -204,34 +207,34 @@ asr: {asr}, chneut: {chneut}, dipdip: {dipdip}, lo_to_splitting: {lo_to_splittin
|
|||
return phbands.view_phononwebsite(browser=options.browser, verbose=options.verbose)
|
||||
|
||||
elif options.plotly:
|
||||
# plotly output
|
||||
# Plotly + Panel version.
|
||||
phdos = phdos_file.phdos
|
||||
figs = []
|
||||
e = figs.append
|
||||
e(phbands.plotly_with_phdos(phdos, units=units, show=False))
|
||||
e(phdos.plotly(units=units, show=False))
|
||||
push_to_chart_studio(figs) if options.chart_studio else plotlyfigs_to_browser(figs)
|
||||
with PanelExpose(title=f"Vibrational properties of {phdos_file.structure.formula}") as e:
|
||||
e(phbands.qpoints.plotly(show=False))
|
||||
e(phbands.plotly_with_phdos(phdos, units=units, show=False))
|
||||
e(phbands.plot_colored_matched(units=units, show=False))
|
||||
e(phbands.plot_fatbands(units=units, phdos_file=phdos_file, show=False))
|
||||
e(phdos.plotly(units=units, show=False))
|
||||
e(phdos_file.plotly_pjdos_type(units=units, show=False))
|
||||
#push_to_chart_studio(figs) if options.chart_studio else plotlyfigs_to_browser(figs)
|
||||
|
||||
else:
|
||||
# matplotlib output
|
||||
phdos = phdos_file.phdos
|
||||
|
||||
with MplExpose(slide_mode=options.slide_mode, slide_timeout=options.slide_timeout) as e:
|
||||
#e(phbands.expose())
|
||||
#e(phdos.expose())
|
||||
if not options.expose_web:
|
||||
# matplotlib figure and X-server.
|
||||
e = MplExpose(slide_mode=options.slide_mode, slide_timeout=options.slide_timeout)
|
||||
else:
|
||||
# panel version with matplotlib.
|
||||
e = PanelExpose(title=f"Vibrational properties of {phdos_file.structure.formula}")
|
||||
|
||||
with e:
|
||||
e(phbands.qpoints.plot(show=False))
|
||||
e(phbands.plot_with_phdos(phdos, units=units, show=False))
|
||||
e(phbands.plot_colored_matched(units=units, show=False))
|
||||
e(phbands.plot_fatbands(units=units, phdos_file=phdos_file, show=False))
|
||||
e(phdos.plot(units=units, show=False))
|
||||
e(phdos_file.plot_pjdos_type(units=units, show=False))
|
||||
#try
|
||||
# msq_dos = phdos_file.msq_dos
|
||||
#except RuntimeError:
|
||||
# msq_dos = None
|
||||
#if msq_dos is not None:
|
||||
# e(msq_dos.plot_uiso(show=False))
|
||||
# e(msq_dos.plot_uiso(show=False))
|
||||
|
||||
phbst_file.close()
|
||||
phdos_file.close()
|
||||
|
@ -257,7 +260,7 @@ num_points: {num_points}, asr: {asr}, chneut: {chneut}, dipdip: {dipdip}
|
|||
df = sv.get_dataframe()
|
||||
abilab.print_dataframe(df, title="Speed of sound for different directions:")
|
||||
df_to_clipboard(options, df)
|
||||
sv.plot()
|
||||
sv.plotly if options.plotly else sv.plot()
|
||||
|
||||
return 0
|
||||
|
||||
|
@ -278,7 +281,10 @@ asr: {asr}, chneut: {chneut}, dipdip: {dipdip}
|
|||
|
||||
gamma_ev = 1e-4
|
||||
print("Plotting dielectric tensor with constant phonon damping: %s (eV)" % gamma_ev)
|
||||
tgen.plot_all(gamma_ev=gamma_ev)
|
||||
if options.plotly:
|
||||
tgen.plotly_all(gamma_ev=gamma_ev)
|
||||
else:
|
||||
tgen.plot_all(gamma_ev=gamma_ev)
|
||||
|
||||
return 0
|
||||
|
||||
|
@ -332,7 +338,7 @@ def abiview_ddb_quad(options):
|
|||
|
||||
title = ddb.structure.formula
|
||||
renderer = "browser" if not options.chart_studio else "chart_studio"
|
||||
plotter.combiplotly(renderer=renderee, title=title) if options.plotly else plotter.plot(title=title)
|
||||
plotter.combiplotly(renderer=renderer, title=title) if options.plotly else plotter.plot(title=title)
|
||||
|
||||
return 0
|
||||
|
||||
|
@ -376,7 +382,15 @@ asr: {asr}, chneut: {chneut}, dipdip: {dipdip}
|
|||
# Execute anaddb to compute the interatomic force constants.
|
||||
ifc = ddb.anaget_ifc(asr=asr, chneut=chneut, dipdip=dipdip)
|
||||
#print(ifc)
|
||||
with MplExpose(slide_mode=options.slide_mode, slide_timeout=options.slide_timeout) as e:
|
||||
|
||||
if not options.expose_web:
|
||||
# matplotlib figure and X-server.
|
||||
e = MplExpose(slide_mode=options.slide_mode, slide_timeout=options.slide_timeout)
|
||||
else:
|
||||
# panel version
|
||||
e = PanelExpose(title=f"Interatomic force constants of {phdos_file.structure.formula}")
|
||||
|
||||
with e:
|
||||
e(ifc.plot_longitudinal_ifc(title="Longitudinal IFCs", show=False))
|
||||
e(ifc.plot_longitudinal_ifc_short_range(title="Longitudinal IFCs short range", show=False))
|
||||
e(ifc.plot_longitudinal_ifc_ewald(title="Longitudinal IFCs Ewald", show=False))
|
||||
|
@ -537,6 +551,8 @@ def get_parser(with_epilog=False):
|
|||
help="Iterate over figures. Expose all figures at once if not given on the CLI.")
|
||||
slide_parser.add_argument("-t", "--slide-timeout", type=int, default=None,
|
||||
help="Close figure after slide-timeout seconds (only if slide-mode). Block if not specified.")
|
||||
slide_parser.add_argument("-ew", "--expose-web", default=False, action="store_true",
|
||||
help='Generate matplotlib plots in $BROWSER instead of X-server. WARNING: Not all the features are supported.')
|
||||
|
||||
# Parent parser for commands that operating on pandas dataframes
|
||||
pandas_parser = argparse.ArgumentParser(add_help=False)
|
||||
|
@ -555,7 +571,7 @@ def get_parser(with_epilog=False):
|
|||
|
||||
# Parent parser for commands supporting plotly plots
|
||||
plotly_parser = argparse.ArgumentParser(add_help=False)
|
||||
plotly_parser.add_argument('--plotly', default=False, action="store_true",
|
||||
plotly_parser.add_argument("-ply", '--plotly', default=False, action="store_true",
|
||||
help='Generate plotly plots in browser instead of matplotlib.')
|
||||
plotly_parser.add_argument("-cs", "--chart-studio", default=False, action="store_true",
|
||||
help="Push figure to plotly chart studio. " +
|
||||
|
|
|
@ -28,7 +28,9 @@ class AbilabTest(AbipyTest):
|
|||
abilab.print_dataframe(df, title="foo")
|
||||
|
||||
d = abilab.software_stack()
|
||||
assert d
|
||||
assert d and "pymatgen" in d
|
||||
df = abilab.software_stack(as_dataframe=True)
|
||||
assert df is not None
|
||||
|
||||
filepath = self.get_tmpname(text=True, suffix=".json")
|
||||
data = {"foo": "bar"}
|
||||
|
|
|
@ -55,6 +55,12 @@ linestyles = OrderedDict(
|
|||
# Matplotlib tools
|
||||
###################
|
||||
|
||||
def is_mpl_figure(obj):
|
||||
"""Return True if obj is a matplotlib Figure."""
|
||||
from matplotlib import pyplot as plt
|
||||
return isinstance(obj, plt.Figure)
|
||||
|
||||
|
||||
def ax_append_title(ax, title, loc="center", fontsize=None):
|
||||
"""Add title to previous ax.title. Return new title."""
|
||||
prev_title = ax.get_title(loc=loc)
|
||||
|
@ -456,6 +462,10 @@ class Marker(namedtuple("Marker", "x y s")):
|
|||
|
||||
class MplExpose(object): # pragma: no cover
|
||||
"""
|
||||
Context manager used to produce several matplotlib figures and then show
|
||||
all them at the end so that the user does not need to close the window to
|
||||
visualize to the next one.
|
||||
|
||||
Example:
|
||||
|
||||
with MplExpose() as e:
|
||||
|
@ -465,8 +475,8 @@ class MplExpose(object): # pragma: no cover
|
|||
def __init__(self, slide_mode=False, slide_timeout=None, verbose=1):
|
||||
"""
|
||||
Args:
|
||||
slide_mode: If true, iterate over figures. Default: Expose all figures at once.
|
||||
slide_timeout: Close figure after slide-timeout seconds Block if None.
|
||||
slide_mode: If Rrue, iterate over figures. Default: Expose all figures at once.
|
||||
slide_timeout: Close figure after slide-timeout seconds. Block if None.
|
||||
verbose: verbosity level
|
||||
"""
|
||||
self.figures = []
|
||||
|
@ -487,8 +497,8 @@ class MplExpose(object): # pragma: no cover
|
|||
|
||||
def __call__(self, obj):
|
||||
"""
|
||||
Add an object to MplExpose. Support mpl figure, list of figures or
|
||||
generator yielding figures.
|
||||
Add an object to MplExpose.
|
||||
Support mpl figure, list of figures or generator yielding figures.
|
||||
"""
|
||||
import types
|
||||
if isinstance(obj, (types.GeneratorType, list, tuple)):
|
||||
|
@ -521,6 +531,7 @@ class MplExpose(object): # pragma: no cover
|
|||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""Activated at the end of the with statement. """
|
||||
if exc_type is not None: return
|
||||
self.expose()
|
||||
|
||||
def expose(self):
|
||||
|
@ -533,6 +544,91 @@ class MplExpose(object): # pragma: no cover
|
|||
fig.clear()
|
||||
|
||||
|
||||
class PanelExpose(object): # pragma: no cover
|
||||
"""
|
||||
Context manager used to produce several matplotlib/plotly figures and then show
|
||||
all them inside the Browser using a panel template.
|
||||
|
||||
Example:
|
||||
|
||||
with PanelExpose() as e:
|
||||
e(obj.plot1(show=False))
|
||||
e(obj.plot2(show=False))
|
||||
"""
|
||||
def __init__(self, title=None, verbose=1):
|
||||
"""
|
||||
Args:
|
||||
title: String to be show in the header.
|
||||
verbose: verbosity level
|
||||
"""
|
||||
self.title = title
|
||||
self.figures = []
|
||||
self.verbose = verbose
|
||||
|
||||
if self.verbose:
|
||||
print("\nLoading all figures before showing them. It may take some time...")
|
||||
|
||||
self.start_time = time.time()
|
||||
|
||||
def __call__(self, obj):
|
||||
"""
|
||||
Add an object to MplPanelExpose.
|
||||
Support mpl figure, list of figures or generator yielding figures.
|
||||
"""
|
||||
import types
|
||||
if isinstance(obj, (types.GeneratorType, list, tuple)):
|
||||
for fig in obj:
|
||||
self.add_fig(fig)
|
||||
else:
|
||||
self.add_fig(obj)
|
||||
|
||||
def add_fig(self, fig):
|
||||
"""Add a matplotlib figure."""
|
||||
if fig is None: return
|
||||
|
||||
self.figures.append(fig)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""Activated at the end of the with statement. """
|
||||
if exc_type is not None: return
|
||||
self.expose()
|
||||
|
||||
def expose(self):
|
||||
"""Show all figures. Clear figures if needed."""
|
||||
import panel as pn
|
||||
pn.config.sizing_mode = 'stretch_width'
|
||||
from abipy.panels.core import get_template_cls_from_name
|
||||
cls = get_template_cls_from_name("FastGridTemplate")
|
||||
|
||||
template = cls(
|
||||
title=self.title if self.title is not None else self.__class__.__name__,
|
||||
header_background="#ff8c00 ", # Dark orange
|
||||
)
|
||||
#pn.config.sizing_mode = 'stretch_width'
|
||||
from abipy.panels.core import mpl, ply
|
||||
for i, fig in enumerate(self.figures):
|
||||
row, col = divmod(i, 2)
|
||||
if is_plotly_figure(fig):
|
||||
p = ply(fig, with_divider=False)
|
||||
elif is_mpl_figure(fig):
|
||||
p = mpl(fig, with_divider=False)
|
||||
else:
|
||||
raise TypeError(f"Don't know how to handle type: `{type(fig)}`")
|
||||
|
||||
if hasattr(template.main, "append"):
|
||||
template.main.append(p)
|
||||
else:
|
||||
# Assume .main area acts like a GridSpec
|
||||
row_slice = slice(3 * row, 3 * (row + 1))
|
||||
if col == 0: template.main[row_slice, :6] = p
|
||||
if col == 1: template.main[row_slice, 6:] = p
|
||||
|
||||
return template.show()
|
||||
|
||||
|
||||
def plot_unit_cell(lattice, ax=None, **kwargs):
|
||||
"""
|
||||
Adds the unit cell of the lattice to a matplotlib Axes3D
|
||||
|
@ -607,10 +703,10 @@ def ax_add_cartesian_frame(ax, start=(0, 0, 0)):
|
|||
def plot_structure(structure, ax=None, to_unit_cell=False, alpha=0.7,
|
||||
style="points+labels", color_scheme="VESTA", **kwargs):
|
||||
"""
|
||||
Plot structure with matplotlib (minimalistic version)
|
||||
Plot structure with matplotlib (minimalistic version).
|
||||
|
||||
Args:
|
||||
structure: Structure object
|
||||
structure: |Structure| object
|
||||
ax: matplotlib :class:`Axes3D` or None if a new figure should be created.
|
||||
alpha: The alpha blending value, between 0 (transparent) and 1 (opaque)
|
||||
to_unit_cell: True if sites should be wrapped into the first unit cell.
|
||||
|
@ -857,6 +953,12 @@ class GenericDataFilesPlotter(object):
|
|||
# Plotly helper functions
|
||||
##########################
|
||||
|
||||
def is_plotly_figure(obj):
|
||||
"""Return True if obj is a plotly Figure."""
|
||||
import plotly.graph_objs as go
|
||||
return isinstance(obj, go.Figure)
|
||||
#return isinstance(obj, (go.Figure, go.FigureWidget))
|
||||
|
||||
|
||||
class PlotlyRowColDesc(object):
|
||||
"""
|
||||
|
@ -939,6 +1041,7 @@ def get_fig_plotly(fig=None, **fig_kw):
|
|||
|
||||
if fig is None:
|
||||
fig = go.Figure(**fig_kw)
|
||||
#fig = go.FigureWidget(**fig_kw)
|
||||
|
||||
return fig, go
|
||||
|
||||
|
@ -948,7 +1051,7 @@ def plotly_set_lims(fig, lims, axname):
|
|||
Set the data limits for the axis ax.
|
||||
|
||||
Args:
|
||||
lims: tuple(2) for (left, right), tuple(1) or scalar for left only.
|
||||
lims: tuple(2) for (left, right), if tuple(1) or scalar for left only, none is set.
|
||||
axname: "x" for x-axis, "y" for y-axis.
|
||||
|
||||
Return: (left, right)
|
||||
|
@ -983,12 +1086,23 @@ def plotly_set_lims(fig, lims, axname):
|
|||
#if right is not None: ax_range[1] = right
|
||||
|
||||
# Example: fig.update_layout(yaxis_range=[-4,4])
|
||||
k = dict(x="xaxis_range", y="yaxis_range")[axname]
|
||||
fig.update_layout(k=[left, right])
|
||||
k = dict(x="xaxis", y="yaxis")[axname]
|
||||
fig.layout[k].range = [left, right]
|
||||
|
||||
return left, right
|
||||
|
||||
|
||||
_PLOTLY_DEFAULT_SHOW = [True]
|
||||
|
||||
|
||||
def set_plotly_default_show(true_or_false):
|
||||
"""
|
||||
Set the default value of show in the add_plotly_fig_kwargs decorator.
|
||||
Usefule for instance when generating the sphinx gallery of plotly plots.
|
||||
"""
|
||||
_PLOTLY_DEFAULT_SHOW[0] = true_or_false
|
||||
|
||||
|
||||
def add_plotly_fig_kwargs(func):
|
||||
"""
|
||||
Decorator that adds keyword arguments for functions returning plotly figures.
|
||||
|
@ -1002,12 +1116,13 @@ def add_plotly_fig_kwargs(func):
|
|||
def wrapper(*args, **kwargs):
|
||||
# pop the kwds used by the decorator.
|
||||
title = kwargs.pop("title", None)
|
||||
show = kwargs.pop("show", True)
|
||||
show = kwargs.pop("show", _PLOTLY_DEFAULT_SHOW[0])
|
||||
hovermode = kwargs.pop("hovermode", False)
|
||||
savefig = kwargs.pop("savefig", None)
|
||||
write_json = kwargs.pop("write_json", None)
|
||||
config = kwargs.pop("config", None)
|
||||
renderer = kwargs.pop("renderer", None)
|
||||
chart_studio = kwargs.pop("chart_studio", False)
|
||||
|
||||
# Allow users to specify the renderer via shell env.
|
||||
if renderer is not None and os.getenv("PLOTLY_RENDERER", default=None) is not None:
|
||||
|
@ -1031,11 +1146,11 @@ def add_plotly_fig_kwargs(func):
|
|||
|
||||
fig.layout.hovermode = hovermode
|
||||
|
||||
if show:
|
||||
if renderer == "chart_studio":
|
||||
push_to_chart_studio(fig)
|
||||
else:
|
||||
fig.show(renderer=renderer, config=config)
|
||||
if show: # and _PLOTLY_DEFAULT_SHOW:
|
||||
fig.show(renderer=renderer, config=config)
|
||||
|
||||
if chart_studio:
|
||||
push_to_chart_studio(fig)
|
||||
|
||||
return fig
|
||||
|
||||
|
@ -1062,9 +1177,9 @@ def add_plotly_fig_kwargs(func):
|
|||
(separated by ‘+’ characters) or None. If None, then the default
|
||||
renderers specified in plotly.io.renderers.default are used.
|
||||
See https://plotly.com/python-api-reference/generated/plotly.graph_objects.Figure.html
|
||||
Note that if renderee is equal to `chart_studio`, the file is uploaded to the chart studio
|
||||
cloud. This is an AbiPy extension on top of the plotly API.
|
||||
config (dict) A dict of parameters to configure the figure. The defaults are set in plotly.js.
|
||||
chart_studio True to push figure to chart_studio server. Requires authenticatios.
|
||||
Default: False.
|
||||
================ ====================================================================
|
||||
"""
|
||||
)
|
||||
|
@ -1118,20 +1233,21 @@ def plotlyfigs_to_browser(figs, filename=None, browser=None):
|
|||
return filename
|
||||
|
||||
|
||||
def plotly_klabels(labels):
|
||||
def plotly_klabels(labels, allow_dupes=False):
|
||||
"""
|
||||
This helper function polish a list of k-points labels before calling plotly by:
|
||||
|
||||
- Checking if we have two equivalent consequtive labels (only the first one is shown and the second one is set to "")
|
||||
- Replacing particulat Latex tokens with unicode as plotly support for Latex is far from optimal.
|
||||
- Checking if we have two equivalent consecutive labels (only the first one is shown and the second one is set to "")
|
||||
- Replacing particular Latex tokens with unicode as plotly support for Latex is far from optimal.
|
||||
|
||||
Return: New list labels, same length as input labels.
|
||||
"""
|
||||
new_labels = labels.copy()
|
||||
|
||||
# Don't show label if previous k-point is the same.
|
||||
for il in range(1, len(new_labels)):
|
||||
if new_labels[il] == new_labels[il - 1]: new_labels[il] = ""
|
||||
if not allow_dupes:
|
||||
# Don't show label if previous k-point is the same.
|
||||
for il in range(1, len(new_labels)):
|
||||
if new_labels[il] == new_labels[il - 1]: new_labels[il] = ""
|
||||
|
||||
replace = {
|
||||
r"$\Gamma$": "Γ",
|
||||
|
@ -1144,6 +1260,15 @@ def plotly_klabels(labels):
|
|||
return new_labels
|
||||
|
||||
|
||||
def plotly_set_xylabels(fig, xlabel, ylabel, exchange_xy):
|
||||
"""
|
||||
Set the x- and the y-label of axis ax, exchanging x and y if exchange_xy
|
||||
"""
|
||||
if exchange_xy: xlabel, ylabel = ylabel, xlabel
|
||||
fig.layout.xaxis.title.text = xlabel
|
||||
fig.layout.yaxis.title.text = ylabel
|
||||
|
||||
|
||||
_PLOTLY_AUTHEHTICATED = False
|
||||
|
||||
|
||||
|
@ -1151,6 +1276,10 @@ def plotly_chartstudio_authenticate():
|
|||
"""
|
||||
Authenticate the user on the chart studio portal by reading `PLOTLY_USERNAME` and `PLOTLY_API_KEY`
|
||||
from the pymatgen configuration file located in $HOME/.pmgrc.yaml.
|
||||
|
||||
PLOTLY_USERNAME: johndoe
|
||||
PLOTLY_API_KEY: XXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
"""
|
||||
global _PLOTLY_AUTHEHTICATED
|
||||
if _PLOTLY_AUTHEHTICATED: return
|
||||
|
@ -1165,7 +1294,7 @@ def plotly_chartstudio_authenticate():
|
|||
Add it to $HOME/.pmgrc.yaml using the follow syntax:
|
||||
|
||||
PLOTLY_USERNAME: john_doe
|
||||
PMG_MAPI_KEY: secret # to the your api_key go to profile > settings > regenerate key
|
||||
PLOTLY_API_KEY: secret # to get your api_key go to profile > settings > regenerate key
|
||||
|
||||
"""
|
||||
|
||||
|
@ -1192,3 +1321,595 @@ def push_to_chart_studio(figs):
|
|||
if not isinstance(figs, (list, tuple)): figs = [figs]
|
||||
for fig in figs:
|
||||
py.plot(fig, auto_open=True)
|
||||
|
||||
|
||||
####################################################
|
||||
# This code is shamelessy taken from Adam's package
|
||||
####################################################
|
||||
import plotly.graph_objects as go
|
||||
|
||||
def go_points(points, size=4, color="black", labels=None, **kwargs):
|
||||
|
||||
#textposition = 'top right',
|
||||
#textfont = dict(color='#E58606'),
|
||||
mode = "markers" if labels is None else "markers+text"
|
||||
#text = labels
|
||||
|
||||
if labels is not None:
|
||||
labels = plotly_klabels(labels, allow_dupes=True)
|
||||
|
||||
return go.Scatter3d(
|
||||
x=[v[0] for v in points],
|
||||
y=[v[1] for v in points],
|
||||
z=[v[2] for v in points],
|
||||
marker=dict(size=size, color=color),
|
||||
mode=mode,
|
||||
text=labels,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
def _add_if_not_in(d, key, value):
|
||||
if key not in d:
|
||||
d[key] = value
|
||||
|
||||
|
||||
def go_line(v1, v2, color="black", width=2, mode="lines", **kwargs):
|
||||
|
||||
_add_if_not_in(kwargs, "line_color", "black")
|
||||
_add_if_not_in(kwargs, "line_width", 2)
|
||||
|
||||
return go.Scatter3d(
|
||||
mode=mode,
|
||||
x=[v1[0], v2[0]],
|
||||
y=[v1[1], v2[1]],
|
||||
z=[v1[2], v2[2]],
|
||||
#line=dict(color=color, width=width),
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
def go_lines(V, name=None, color="black", width=2, **kwargs):
|
||||
gen = ((v1, v2) for (v1, v2) in V)
|
||||
v1, v2 = next(gen)
|
||||
out = [
|
||||
go_line(v1, v2, width=width, color=color, name=name, legendgroup=name, **kwargs)
|
||||
]
|
||||
out.extend(
|
||||
go_line(
|
||||
v1,
|
||||
v2,
|
||||
width=width,
|
||||
color=color,
|
||||
showlegend=False,
|
||||
legendgroup=name,
|
||||
**kwargs
|
||||
)
|
||||
for (v1, v2) in gen
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def vectors(lattice, name=None, color="black", width=4, **kwargs):
|
||||
gen = zip(lattice, ["a", "b", "c"])
|
||||
v, label = next(gen)
|
||||
|
||||
out = [
|
||||
go_line(
|
||||
[0, 0, 0],
|
||||
v,
|
||||
text=["", label],
|
||||
width=width,
|
||||
color=color,
|
||||
name=name,
|
||||
legendgroup=name,
|
||||
mode="lines+text",
|
||||
**kwargs
|
||||
)
|
||||
]
|
||||
out.extend(
|
||||
go_line(
|
||||
[0, 0, 0],
|
||||
v,
|
||||
text=["", label],
|
||||
width=width,
|
||||
color=color,
|
||||
showlegend=False,
|
||||
legendgroup=name,
|
||||
mode="lines+text",
|
||||
**kwargs
|
||||
)
|
||||
for (v, label) in gen
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def get_vectors(lattice_mat, name=None, color="black", width=2, **kwargs):
|
||||
return go_lines([[[0, 0, 0], v] for v in lattice_mat], **kwargs)
|
||||
|
||||
|
||||
def get_box(lattice_mat, **kwargs):
|
||||
a, b, c = lattice_mat
|
||||
segments = [
|
||||
[[0, 0, 0], a],
|
||||
[[0, 0, 0], b],
|
||||
[[0, 0, 0], c],
|
||||
[a, a + b],
|
||||
[a, a + c],
|
||||
[b, b + a],
|
||||
[b, b + c],
|
||||
[c, c + a],
|
||||
[c, c + b],
|
||||
[a + b, a + b + c],
|
||||
[a + c, a + b + c],
|
||||
[b + c, a + b + c],
|
||||
]
|
||||
return go_lines(segments, **kwargs)
|
||||
|
||||
|
||||
def plot_fcc_conv():
|
||||
|
||||
fcc_conv = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
|
||||
fcc_vectors = vectors(
|
||||
fcc_conv, name="conv lattice vectors", color="darkblue", width=6
|
||||
)
|
||||
fcc_box = get_box(fcc_conv, name="conv lattice")
|
||||
|
||||
atoms = go_points(
|
||||
[[0, 0, 0], [0.5, 0.5, 0], [0.5, 0, 0.5], [0, 0.5, 0.5]],
|
||||
size=10,
|
||||
color="orange",
|
||||
name="atoms",
|
||||
legendgroup="atoms",
|
||||
)
|
||||
|
||||
fig = go.Figure(data=[*fcc_box, *fcc_vectors, atoms])
|
||||
return fig
|
||||
|
||||
|
||||
def plot_fcc_prim():
|
||||
fcc_prim = np.array([[0.5, 0.5, 0], [0, 0.5, 0.5], [0.5, 0, 0.5]])
|
||||
|
||||
fcc_prim_vectors = vectors(
|
||||
fcc_prim, name="prim lattice vectors", color="green", width=6
|
||||
)
|
||||
fcc_prim_box = get_box(fcc_prim, name="prim lattice", color="green")
|
||||
|
||||
atoms = go_points(
|
||||
[[0, 0, 0], [0.5, 0.5, 0], [0.5, 0, 0.5], [0, 0.5, 0.5]],
|
||||
size=10,
|
||||
color="orange",
|
||||
name="atoms",
|
||||
legendgroup="atoms",
|
||||
)
|
||||
|
||||
fcc_conv = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
|
||||
fcc_conv_box = get_box(fcc_conv, name="conv lattice")
|
||||
|
||||
|
||||
fig = go.Figure(data=[*fcc_prim_box, *fcc_prim_vectors, *fcc_conv_box, atoms])
|
||||
|
||||
return fig
|
||||
|
||||
|
||||
def plot_fcc_100():
|
||||
|
||||
# fcc_100_cell = np.array([[0, 0.5, -0.5], [0, 0.5, 0.5], [1.0, 0.0, 0]])
|
||||
fcc_100_cell = np.array([[0.5, -0.5, 0], [0.5, 0.5, 0], [0.0, 0, 1.0]])
|
||||
|
||||
fcc_100_vectors = vectors(
|
||||
fcc_100_cell, name="100 lattice vectors", color="red", width=6
|
||||
)
|
||||
fcc_100_box = get_box(fcc_100_cell, name="100 lattice", color="red")
|
||||
|
||||
fig = plot_fcc_conv()
|
||||
fig.add_traces([*fcc_100_box, *fcc_100_vectors])
|
||||
|
||||
return fig
|
||||
|
||||
|
||||
def plot_fcc_110():
|
||||
fcc_110_cell = np.array([[0, 0.0, 1.0], [0.5, -0.5, 0], [0.5, 0.5, 0.0]])
|
||||
|
||||
fcc_110_vectors = vectors(
|
||||
fcc_110_cell, name="reduced lattice vectors", color="red", width=6
|
||||
)
|
||||
fcc_110_box = get_box(fcc_110_cell, name="reduced lattice", color="red")
|
||||
|
||||
fig = plot_fcc_conv()
|
||||
fig.add_traces([*fcc_110_box, *fcc_110_vectors])
|
||||
return fig
|
||||
|
||||
|
||||
def plot_fcc_111():
|
||||
fcc_111_cell = np.array([[0.5, 0, -0.5], [0, 0.5, -0.5], [1, 1, 1]])
|
||||
|
||||
fcc_111_vectors = vectors(
|
||||
fcc_111_cell, name="reduced lattice vectors", color="red", width=6
|
||||
)
|
||||
fcc_111_box = get_box(fcc_111_cell, name="reduced lattice", color="red")
|
||||
|
||||
fig = plot_fcc_conv()
|
||||
fig.add_traces([*fcc_111_box, *fcc_111_vectors])
|
||||
return fig
|
||||
|
||||
|
||||
def plotly_structure(structure, ax=None, to_unit_cell=False, alpha=0.7,
|
||||
style="points+labels", color_scheme="VESTA", **kwargs):
|
||||
"""
|
||||
Plot structure with plotly (minimalistic version).
|
||||
|
||||
Args:
|
||||
structure: |Structure| object
|
||||
ax: matplotlib :class:`Axes3D` or None if a new figure should be created.
|
||||
alpha: The alpha blending value, between 0 (transparent) and 1 (opaque)
|
||||
to_unit_cell: True if sites should be wrapped into the first unit cell.
|
||||
style: "points+labels" to show atoms sites with labels.
|
||||
color_scheme: color scheme for atom types. Allowed values in ("Jmol", "VESTA")
|
||||
|
||||
Returns: |matplotlib-Figure|
|
||||
"""
|
||||
#fig, ax = plot_unit_cell(structure.lattice, ax=ax, linewidth=1)
|
||||
|
||||
box = get_box(structure.lattice.matrix) #, **kwargs):
|
||||
|
||||
from pymatgen.analysis.molecule_structure_comparator import CovalentRadius
|
||||
from pymatgen.vis.structure_vtk import EL_COLORS
|
||||
|
||||
#symb2data = {}
|
||||
#for symbol in structure.symbol_set:
|
||||
# symb2data[symbol] = d = {}
|
||||
# d["color"] = color = tuple(i / 255 for i in EL_COLORS[color_scheme][symbol])
|
||||
# d["radius"] = CovalentRadius.radius[symbol]
|
||||
# inds = structure.indices_from_symbol(symbol)
|
||||
# sites = [structure[i] for i in inds]
|
||||
# d["xyz"] = []
|
||||
# for site in sites:
|
||||
# if to_unit_cell and hasattr(site, "to_unit_cell"): site = site.to_unit_cell()
|
||||
# Use cartesian coordinates.
|
||||
# x, y, z = site.coords
|
||||
# d["xyz"].append((x, y ,z)
|
||||
|
||||
xyz, sizes, colors = np.empty((len(structure), 3)), [], []
|
||||
for i, site in enumerate(structure):
|
||||
symbol = site.specie.symbol
|
||||
color = tuple(i / 255 for i in EL_COLORS[color_scheme][symbol])
|
||||
radius = CovalentRadius.radius[symbol]
|
||||
if to_unit_cell and hasattr(site, "to_unit_cell"): site = site.to_unit_cell()
|
||||
# Use cartesian coordinates.
|
||||
x, y, z = site.coords
|
||||
xyz[i] = (x, y, z) # , radius)
|
||||
sizes.append(radius)
|
||||
colors.append(color)
|
||||
#if "labels" in style:
|
||||
# ax.text(x, y, z, symbol)
|
||||
|
||||
atoms = go_points(
|
||||
#[[0, 0, 0], [0.5, 0.5, 0], [0.5, 0, 0.5], [0, 0.5, 0.5]],
|
||||
xyz,
|
||||
size=10,
|
||||
color="orange",
|
||||
name="atoms",
|
||||
legendgroup="atoms",
|
||||
)
|
||||
|
||||
#marker = [dict(size=size, color=color) for (size, color) in zip(sizes, colors)]
|
||||
|
||||
#atoms = go.Scatter3d(
|
||||
# x=[v[0] for v in xyz],
|
||||
# y=[v[1] for v in xyz],
|
||||
# z=[v[2] for v in xyz],
|
||||
# #marker=dict(size=size, color=color),
|
||||
# marker=marker,
|
||||
# mode="markers",
|
||||
# #**kwargs
|
||||
#)
|
||||
|
||||
# The definition of sizes is not optimal because matplotlib uses points
|
||||
# wherease we would like something that depends on the radius (5000 seems to give reasonable plots)
|
||||
# For possibile approaches, see
|
||||
# https://stackoverflow.com/questions/9081553/python-scatter-plot-size-and-style-of-the-marker/24567352#24567352
|
||||
# https://gist.github.com/syrte/592a062c562cd2a98a83
|
||||
#if "points" in style:
|
||||
# x, y, z, s = xyzs.T.copy()
|
||||
# s = 5000 * s ** 2
|
||||
# ax.scatter(x, y, zs=z, s=s, c=colors, alpha=alpha) #facecolors="white", #edgecolors="blue"
|
||||
|
||||
#ax.set_title(structure.composition.formula)
|
||||
#ax.set_axis_off()
|
||||
|
||||
#fig = go.Figure(data=[*box, *vectors, atoms])
|
||||
fig = go.Figure(data=[*box, atoms])
|
||||
return fig
|
||||
|
||||
|
||||
# This is the matplotlib API to plot the BZ.
|
||||
|
||||
def plotly_wigner_seitz(lattice, fig=None, **kwargs):
|
||||
"""
|
||||
Adds the skeleton of the Wigner-Seitz cell of the lattice to a plotly figure.
|
||||
|
||||
Args:
|
||||
lattice: Lattice object
|
||||
fig: plotly figure or None if a new figure should be created.
|
||||
kwargs: kwargs passed to the matplotlib function 'plot'. Color defaults to black
|
||||
and linewidth to 1.
|
||||
|
||||
Returns: Plotly figure
|
||||
"""
|
||||
#ax, fig, plt = get_ax3d_fig_plt(ax)
|
||||
fig, go = get_fig_plotly(fig=fig) #, **fig_kw)
|
||||
|
||||
if "line_color" not in kwargs:
|
||||
kwargs["line_color"] = "black"
|
||||
if "line_width" not in kwargs:
|
||||
kwargs["line_width"] = 1
|
||||
|
||||
bz = lattice.get_wigner_seitz_cell()
|
||||
#ax, fig, plt = get_ax3d_fig_plt(ax)
|
||||
|
||||
for iface in range(len(bz)): # pylint: disable=C0200
|
||||
for line in itertools.combinations(bz[iface], 2):
|
||||
for jface in range(len(bz)):
|
||||
if (
|
||||
iface < jface
|
||||
and any(np.all(line[0] == x) for x in bz[jface])
|
||||
and any(np.all(line[1] == x) for x in bz[jface])
|
||||
):
|
||||
#ax.plot(*zip(line[0], line[1]), **kwargs)
|
||||
fig.add_trace(go_line(line[0], line[1], showlegend=False, **kwargs))
|
||||
|
||||
return fig
|
||||
|
||||
|
||||
def plotly_lattice_vectors(lattice, fig=None, **kwargs):
|
||||
"""
|
||||
Adds the basis vectors of the lattice provided to a matplotlib Axes
|
||||
|
||||
Args:
|
||||
lattice: Lattice object
|
||||
fig: plotly figure or None if a new figure should be created.
|
||||
kwargs: kwargs passed to the matplotlib function 'plot'. Color defaults to green
|
||||
and linewidth to 3.
|
||||
|
||||
Returns:
|
||||
matplotlib figure and matplotlib ax
|
||||
"""
|
||||
#ax, fig, plt = get_ax3d_fig_plt(ax)
|
||||
fig, go = get_fig_plotly(fig=fig) #, **fig_kw)
|
||||
|
||||
if "line_color" not in kwargs:
|
||||
kwargs["line_color"] = "green"
|
||||
if "line_width" not in kwargs:
|
||||
kwargs["line_width"] = 3
|
||||
if "showlegend" not in kwargs:
|
||||
kwargs["showlegend"] = False
|
||||
|
||||
vertex1 = lattice.get_cartesian_coords([0.0, 0.0, 0.0])
|
||||
vertex2 = lattice.get_cartesian_coords([1.0, 0.0, 0.0])
|
||||
#ax.plot(*zip(vertex1, vertex2), **kwargs)
|
||||
fig.add_trace(go_line(vertex1, vertex2, name="a", **kwargs))
|
||||
vertex2 = lattice.get_cartesian_coords([0.0, 1.0, 0.0])
|
||||
#ax.plot(*zip(vertex1, vertex2), **kwargs)
|
||||
fig.add_trace(go_line(vertex1, vertex2, name="b", **kwargs))
|
||||
vertex2 = lattice.get_cartesian_coords([0.0, 0.0, 1.0])
|
||||
#ax.plot(*zip(vertex1, vertex2), **kwargs)
|
||||
fig.add_trace(go_line(vertex1, vertex2, name="c", **kwargs))
|
||||
|
||||
return fig
|
||||
|
||||
|
||||
def plotly_path(line, lattice=None, coords_are_cartesian=False, fig=None, **kwargs):
|
||||
"""
|
||||
Adds a line passing through the coordinates listed in 'line' to a matplotlib Axes
|
||||
|
||||
Args:
|
||||
line: list of coordinates.
|
||||
lattice: Lattice object used to convert from reciprocal to cartesian coordinates
|
||||
coords_are_cartesian: Set to True if you are providing
|
||||
coordinates in cartesian coordinates. Defaults to False.
|
||||
Requires lattice if False.
|
||||
fig: plotly figure or None if a new figure should be created.
|
||||
kwargs: kwargs passed to the matplotlib function 'plot'. Color defaults to red
|
||||
and linewidth to 3.
|
||||
|
||||
Returns:
|
||||
matplotlib figure and matplotlib ax
|
||||
"""
|
||||
|
||||
#ax, fig, plt = get_ax3d_fig_plt(ax)
|
||||
fig, go = get_fig_plotly(fig=fig) #, **fig_kw)
|
||||
|
||||
if "line_color" not in kwargs:
|
||||
kwargs["line_color"] = "red"
|
||||
if "line_width" not in kwargs:
|
||||
kwargs["line_width"] = 3
|
||||
|
||||
for k in range(1, len(line)):
|
||||
vertex1 = line[k - 1]
|
||||
vertex2 = line[k]
|
||||
if not coords_are_cartesian:
|
||||
if lattice is None:
|
||||
raise ValueError("coords_are_cartesian False requires the lattice")
|
||||
vertex1 = lattice.get_cartesian_coords(vertex1)
|
||||
vertex2 = lattice.get_cartesian_coords(vertex2)
|
||||
#ax.plot(*zip(vertex1, vertex2), **kwargs)
|
||||
fig.add_trace(go_line(vertex1, vertex2, showlegend=False, **kwargs))
|
||||
|
||||
return fig
|
||||
|
||||
|
||||
def plotly_labels(labels, lattice=None, coords_are_cartesian=False, ax=None, **kwargs):
|
||||
"""
|
||||
Adds labels to a matplotlib Axes
|
||||
|
||||
Args:
|
||||
labels: dict containing the label as a key and the coordinates as value.
|
||||
lattice: Lattice object used to convert from reciprocal to cartesian coordinates
|
||||
coords_are_cartesian: Set to True if you are providing.
|
||||
coordinates in cartesian coordinates. Defaults to False.
|
||||
Requires lattice if False.
|
||||
ax: matplotlib :class:`Axes` or None if a new figure should be created.
|
||||
kwargs: kwargs passed to the matplotlib function 'text'. Color defaults to blue
|
||||
and size to 25.
|
||||
|
||||
Returns:
|
||||
matplotlib figure and matplotlib ax
|
||||
"""
|
||||
ax, fig, plt = get_ax3d_fig_plt(ax)
|
||||
|
||||
if "color" not in kwargs:
|
||||
kwargs["color"] = "b"
|
||||
if "size" not in kwargs:
|
||||
kwargs["size"] = 25
|
||||
|
||||
for k, coords in labels.items():
|
||||
label = k
|
||||
if k.startswith("\\") or k.find("_") != -1:
|
||||
label = "$" + k + "$"
|
||||
off = 0.01
|
||||
if coords_are_cartesian:
|
||||
coords = np.array(coords)
|
||||
else:
|
||||
if lattice is None:
|
||||
raise ValueError("coords_are_cartesian False requires the lattice")
|
||||
coords = lattice.get_cartesian_coords(coords)
|
||||
ax.text(*(coords + off), s=label, **kwargs)
|
||||
|
||||
return fig, ax
|
||||
|
||||
|
||||
def plotly_points(points, lattice=None, coords_are_cartesian=False, fold=False, labels=None, fig=None, **kwargs):
|
||||
"""
|
||||
Adds points to a matplotlib Axes
|
||||
|
||||
Args:
|
||||
points: list of coordinates
|
||||
lattice: Lattice object used to convert from reciprocal to cartesian coordinates
|
||||
coords_are_cartesian: Set to True if you are providing
|
||||
coordinates in cartesian coordinates. Defaults to False.
|
||||
Requires lattice if False.
|
||||
fold: whether the points should be folded inside the first Brillouin Zone.
|
||||
Defaults to False. Requires lattice if True.
|
||||
fig: plotly figure or None if a new figure should be created.
|
||||
kwargs: kwargs passed to the matplotlib function 'scatter'. Color defaults to blue
|
||||
|
||||
Returns:
|
||||
matplotlib figure and matplotlib ax
|
||||
"""
|
||||
#ax, fig, plt = get_ax3d_fig_plt(ax)
|
||||
fig, go = get_fig_plotly(fig=fig) #, **fig_kw)
|
||||
|
||||
if "marker_color" not in kwargs:
|
||||
kwargs["marker_color"] = "blue"
|
||||
|
||||
if (not coords_are_cartesian or fold) and lattice is None:
|
||||
raise ValueError("coords_are_cartesian False or fold True require the lattice")
|
||||
|
||||
from pymatgen.electronic_structure.plotter import fold_point
|
||||
vecs = []
|
||||
for p in points:
|
||||
|
||||
if fold:
|
||||
p = fold_point(p, lattice, coords_are_cartesian=coords_are_cartesian)
|
||||
|
||||
elif not coords_are_cartesian:
|
||||
p = lattice.get_cartesian_coords(p)
|
||||
|
||||
vecs.append(p)
|
||||
#ax.scatter(*p, **kwargs)
|
||||
|
||||
kws = dict(textposition="top right", showlegend=False) #, textfont=dict(color='#E58606'))
|
||||
kws.update(kwargs)
|
||||
fig.add_trace(go_points(vecs, labels=labels, **kws))
|
||||
|
||||
return fig
|
||||
|
||||
|
||||
@add_plotly_fig_kwargs
|
||||
def plotly_brillouin_zone_from_kpath(kpath, fig=None, **kwargs):
|
||||
"""
|
||||
Gives the plot (as a matplotlib object) of the symmetry line path in
|
||||
the Brillouin Zone.
|
||||
|
||||
Args:
|
||||
kpath (HighSymmKpath): a HighSymmKPath object
|
||||
ax: matplotlib :class:`Axes` or None if a new figure should be created.
|
||||
**kwargs: provided by add_fig_kwargs decorator
|
||||
|
||||
Returns: plotly figure.
|
||||
"""
|
||||
lines = [[kpath.kpath["kpoints"][k] for k in p] for p in kpath.kpath["path"]]
|
||||
return plotly_brillouin_zone(
|
||||
bz_lattice=kpath.prim_rec,
|
||||
lines=lines,
|
||||
fig=fig,
|
||||
labels=kpath.kpath["kpoints"],
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
|
||||
@add_plotly_fig_kwargs
|
||||
def plotly_brillouin_zone(
|
||||
bz_lattice,
|
||||
lines=None,
|
||||
labels=None,
|
||||
kpoints=None,
|
||||
fold=False,
|
||||
coords_are_cartesian=False,
|
||||
fig=None,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
Plots a 3D representation of the Brillouin zone of the structure.
|
||||
Can add to the plot paths, labels and kpoints
|
||||
|
||||
Args:
|
||||
bz_lattice: Lattice object of the Brillouin zone
|
||||
lines: list of lists of coordinates. Each list represent a different path
|
||||
labels: dict containing the label as a key and the coordinates as value.
|
||||
kpoints: list of coordinates
|
||||
fold: whether the points should be folded inside the first Brillouin Zone.
|
||||
Defaults to False. Requires lattice if True.
|
||||
coords_are_cartesian: Set to True if you are providing
|
||||
coordinates in cartesian coordinates. Defaults to False.
|
||||
ax: matplotlib :class:`Axes` or None if a new figure should be created.
|
||||
kwargs: provided by add_fig_kwargs decorator
|
||||
|
||||
Returns: plotly figure
|
||||
"""
|
||||
|
||||
fig = plotly_lattice_vectors(bz_lattice, fig=fig)
|
||||
plotly_wigner_seitz(bz_lattice, fig=fig)
|
||||
if lines is not None:
|
||||
for line in lines:
|
||||
plotly_path(line, bz_lattice, coords_are_cartesian=coords_are_cartesian, fig=fig)
|
||||
|
||||
if labels is not None:
|
||||
# TODO
|
||||
#plotly_labels(labels, bz_lattice, coords_are_cartesian=coords_are_cartesian, ax=ax)
|
||||
plotly_points(
|
||||
labels.values(),
|
||||
lattice=bz_lattice,
|
||||
coords_are_cartesian=coords_are_cartesian,
|
||||
fold=False,
|
||||
labels=list(labels.keys()),
|
||||
fig=fig,
|
||||
)
|
||||
|
||||
if kpoints is not None:
|
||||
plotly_points(
|
||||
kpoints,
|
||||
lattice=bz_lattice,
|
||||
coords_are_cartesian=coords_are_cartesian,
|
||||
fold=fold,
|
||||
fig=fig,
|
||||
)
|
||||
|
||||
#ax.set_xlim3d(-1, 1)
|
||||
#ax.set_ylim3d(-1, 1)
|
||||
#ax.set_zlim3d(-1, 1)
|
||||
# ax.set_aspect('equal')
|
||||
#ax.axis("off")
|
||||
|
||||
return fig
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
"""Utilities for pandas dataframe"""
|
||||
"""Utilities for pandas dataframes"""
|
||||
|
||||
import sys
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import numpy as np
|
|||
from abipy import abilab
|
||||
import abipy.data as abidata
|
||||
from abipy.tools.plotting import *
|
||||
from abipy.tools.plotting import is_mpl_figure, is_plotly_figure
|
||||
from abipy.core.testing import AbipyTest
|
||||
|
||||
|
||||
|
@ -18,6 +19,8 @@ class TestPlotting(AbipyTest):
|
|||
raise self.SkipTest("This test requires matplotlib")
|
||||
|
||||
ax, fig, plt = get_ax_fig_plt(ax=None)
|
||||
assert is_mpl_figure(fig)
|
||||
assert not is_plotly_figure(fig)
|
||||
|
||||
left, right = set_axlims(ax, None, "x")
|
||||
assert left is None and right is None
|
||||
|
|
|
@ -1,111 +1,253 @@
|
|||
#name: binder3.6
|
||||
##name: env3.8
|
||||
channels:
|
||||
- gmatteo
|
||||
- abinit
|
||||
- matsci
|
||||
- conda-forge
|
||||
- defaults
|
||||
- conda-forge
|
||||
- defaults
|
||||
dependencies:
|
||||
- apscheduler=2.1.0=py36_0
|
||||
- html2text=2016.9.19=py36_0
|
||||
- asn1crypto=0.22.0=py36_0
|
||||
- backports=1.0=py36_1
|
||||
- backports.functools_lru_cache=1.4=py36_1
|
||||
- blas=1.1=openblas
|
||||
- ca-certificates=2017.11.5=0
|
||||
- certifi=2017.11.5=py36_0
|
||||
- cffi=1.11.2=py36_0
|
||||
- chardet=3.0.4=py36_0
|
||||
- cryptography=2.1.4=py36_0
|
||||
- curl=7.55.1=0
|
||||
- cycler=0.10.0=py36_0
|
||||
- dbus=1.10.22=0
|
||||
- decorator=4.1.2=py36_0
|
||||
- expat=2.2.5=0
|
||||
- fastcache=1.0.2=py36_0
|
||||
- fontconfig=2.12.6=0
|
||||
- freetype=2.8.1=0
|
||||
- gettext=0.19.7=1
|
||||
- glib=2.55.0=0
|
||||
- gmp=6.1.2=0
|
||||
- gmpy2=2.0.8=py36_1
|
||||
- gst-plugins-base=1.8.0=0
|
||||
- gstreamer=1.8.0=1
|
||||
- hdf4=4.2.13=0
|
||||
- hdf5=1.10.1=1
|
||||
- icu=58.2=0
|
||||
- idna=2.6=py36_1
|
||||
- jpeg=9b=2
|
||||
- krb5=1.14.2=0
|
||||
- libffi=3.2.1=3
|
||||
- libiconv=1.15=0
|
||||
- libnetcdf=4.4.1.1=10
|
||||
- libpng=1.6.34=0
|
||||
- libssh2=1.8.0=2
|
||||
- libxcb=1.12=1
|
||||
- libxml2=2.9.5=2
|
||||
- matplotlib=2.1.1=py36_2
|
||||
- mpc=1.0.3=4
|
||||
- mpfr=3.1.5=0
|
||||
- mpich=3.2=5
|
||||
- mpmath=1.0.0=py_0
|
||||
- ncurses=5.9=10
|
||||
- netcdf-fortran=4.4.4=6
|
||||
- netcdf4=1.3.1=py36_1
|
||||
- networkx=2.0=py36_1
|
||||
- numpy=1.13.3=py36_blas_openblas_201
|
||||
- openblas=0.2.20=6
|
||||
- openssl=1.0.2n=0
|
||||
- pandas=0.22.0=py36_0
|
||||
- patsy=0.4.1=py36_0
|
||||
- pcre=8.39=0
|
||||
- pip=9.0.1=py36_1
|
||||
- prettytable=0.7.2=py36_1
|
||||
- pycparser=2.18=py36_0
|
||||
- pyopenssl=17.4.0=py36_0
|
||||
- pyparsing=2.2.0=py36_0
|
||||
- pyqt=5.6.0=py36_4
|
||||
- pysocks=1.6.7=py36_0
|
||||
- python=3.6.4=0
|
||||
- python-dateutil=2.6.1=py36_0
|
||||
- pytz=2017.3=py_2
|
||||
- pyyaml=3.12=py36_1
|
||||
- qt=5.6.2=7
|
||||
- readline=7.0=0
|
||||
- requests=2.18.4=py36_1
|
||||
- scipy=1.0.0=py36_blas_openblas_201
|
||||
- seaborn=0.8.1=py36_0
|
||||
- setuptools=38.2.4=py36_0
|
||||
- sip=4.18=py36_1
|
||||
- six=1.11.0=py36_1
|
||||
- sqlite=3.20.1=2
|
||||
- statsmodels=0.8.0=py36_0
|
||||
- sympy=1.1.1=py36_0
|
||||
- tk=8.6.7=0
|
||||
- tornado=4.5.2=py36_0
|
||||
- urllib3=1.22=py36_0
|
||||
- wheel=0.30.0=py_1
|
||||
- xorg-libxau=1.0.8=3
|
||||
- xorg-libxdmcp=1.1.2=3
|
||||
- xz=5.2.3=0
|
||||
- yaml=0.1.6=0
|
||||
- zlib=1.2.11=0
|
||||
- libgcc=7.2.0=h69d50b8_2
|
||||
- libgcc-ng=7.2.0=h7cc24e2_2
|
||||
- libgfortran=3.0.0=1
|
||||
- libstdcxx-ng=7.2.0=h7a57d05_2
|
||||
- abinit=8.6.1=1
|
||||
- fftw=3.3.6=0
|
||||
- libxc=2.2.2=0
|
||||
- monty=1.0.2=py36h8689505_2
|
||||
- palettable=2.1.1=py36h1b737fa_2
|
||||
- pydispatcher=2.0.5=py36h30c4b39_1
|
||||
- pymatgen=2017.12.16=py36_0
|
||||
- ruamel.yaml=0.15.25=py36_0
|
||||
- spglib=1.9.9.44=py36_0
|
||||
- tabulate=0.7.7=py36h0a86d05_2
|
||||
- tqdm=4.10.0=py36_1
|
||||
- pip:
|
||||
- backports.functools-lru-cache==1.4
|
||||
#prefix: /home/ucl/naps/gmatteo/miniconda3/envs/binder3.6
|
||||
|
||||
- _libgcc_mutex=0.1=conda_forge
|
||||
- _openmp_mutex=4.5=1_gnu
|
||||
- abinit=9.4.0=h321dead_0
|
||||
- apipkg=1.5=py_0
|
||||
- appdirs=1.4.4=pyh9f0ad1d_0
|
||||
- apscheduler=3.7.0=py38h578d9bd_0
|
||||
- argon2-cffi=20.1.0=py38h497a2fe_2
|
||||
- ase=3.21.1=pyhd8ed1ab_0
|
||||
- async_generator=1.10=py_0
|
||||
- attrs=21.1.0=pyhd8ed1ab_0
|
||||
- backcall=0.2.0=pyh9f0ad1d_0
|
||||
- backports=1.0=py_2
|
||||
- backports.functools_lru_cache=1.6.4=pyhd8ed1ab_0
|
||||
- bleach=3.3.0=pyh44b312d_0
|
||||
- bokeh=2.3.1=py38h578d9bd_0
|
||||
- brotlipy=0.7.0=py38h497a2fe_1001
|
||||
- bzip2=1.0.8=h7f98852_4
|
||||
- c-ares=1.17.1=h7f98852_1
|
||||
- ca-certificates=2020.12.5=ha878542_0
|
||||
- cached-property=1.5.2=hd8ed1ab_1
|
||||
- cached_property=1.5.2=pyha770c72_1
|
||||
- certifi=2020.12.5=py38h578d9bd_1
|
||||
- cffi=1.14.5=py38ha65f79e_0
|
||||
- cftime=1.4.1=py38h5c078b8_0
|
||||
- chardet=4.0.0=py38h578d9bd_1
|
||||
- chart-studio=1.1.0=pyh9f0ad1d_0
|
||||
- click=7.1.2=pyh9f0ad1d_0
|
||||
- cloudpickle=1.6.0=py_0
|
||||
- coverage=5.5=py38h497a2fe_0
|
||||
- cryptography=3.4.7=py38ha5dfef3_0
|
||||
- curl=7.76.1=h979ede3_1
|
||||
- cycler=0.10.0=py_2
|
||||
- cytoolz=0.11.0=py38h497a2fe_3
|
||||
- dask-core=2021.4.1=pyhd8ed1ab_0
|
||||
- dbus=1.13.18=hb2f20db_0
|
||||
- decorator=4.4.2=py_0
|
||||
- defusedxml=0.7.1=pyhd8ed1ab_0
|
||||
- entrypoints=0.3=pyhd8ed1ab_1003
|
||||
- enum34=1.1.10=py38h32f6830_2
|
||||
- execnet=1.8.0=pyh44b312d_0
|
||||
- expat=2.3.0=h9c3ff4c_0
|
||||
- fftw=3.3.9=mpi_mpich_h245ceca_1
|
||||
- flask=1.1.2=pyh9f0ad1d_0
|
||||
- fontconfig=2.13.1=hba837de_1005
|
||||
- freetype=2.10.4=h0708190_1
|
||||
- fsspec=2021.4.0=pyhd8ed1ab_0
|
||||
- future=0.18.2=py38h578d9bd_3
|
||||
- gettext=0.19.8.1=h0b5b191_1005
|
||||
- glib=2.68.1=h9c3ff4c_0
|
||||
- glib-tools=2.68.1=h9c3ff4c_0
|
||||
- gmp=6.2.1=h58526e2_0
|
||||
- gmpy2=2.1.0b1=py38hd744826_1
|
||||
- gst-plugins-base=1.14.0=hbbd80ab_1
|
||||
- gstreamer=1.14.0=h28cd5cc_2
|
||||
- h5py=3.2.1=nompi_py38h9915d05_100
|
||||
- hdf4=4.2.13=h10796ff_1005
|
||||
- hdf5=1.10.6=mpi_mpich_h996c276_1014
|
||||
- icu=58.2=hf484d3e_1000
|
||||
- idna=2.10=pyh9f0ad1d_0
|
||||
- imagecodecs-lite=2019.12.3=py38h5c078b8_3
|
||||
- imageio=2.9.0=py_0
|
||||
- importlib-metadata=4.0.1=py38h578d9bd_0
|
||||
- iniconfig=1.1.1=pyh9f0ad1d_0
|
||||
- ipykernel=5.5.4=py38hd0cf306_0
|
||||
- ipython=7.23.1=py38hd0cf306_0
|
||||
- ipython_genutils=0.2.0=py_1
|
||||
- ipywidgets=7.6.3=pyhd3deb0d_0
|
||||
- itsdangerous=1.1.0=py_0
|
||||
- jedi=0.18.0=py38h578d9bd_2
|
||||
- jinja2=2.11.3=pyh44b312d_0
|
||||
- jpeg=9d=h36c2ea0_0
|
||||
- jsoncpp=1.8.4=hc9558a2_1002
|
||||
- jsonschema=3.2.0=pyhd8ed1ab_3
|
||||
- jupyter=1.0.0=py38h578d9bd_6
|
||||
- jupyter_client=6.1.12=pyhd8ed1ab_0
|
||||
- jupyter_console=6.4.0=pyhd8ed1ab_0
|
||||
- jupyter_core=4.7.1=py38h578d9bd_0
|
||||
- jupyterlab_pygments=0.1.2=pyh9f0ad1d_0
|
||||
- jupyterlab_widgets=1.0.0=pyhd8ed1ab_1
|
||||
- kiwisolver=1.3.1=py38h1fd1430_1
|
||||
- krb5=1.17.2=h926e7f8_0
|
||||
- latexcodec=2.0.1=pyh9f0ad1d_0
|
||||
- lcms2=2.12=hddcbb42_0
|
||||
- ld_impl_linux-64=2.33.1=h53a641e_7
|
||||
- libblas=3.9.0=9_openblas
|
||||
- libcblas=3.9.0=9_openblas
|
||||
- libcurl=7.76.1=hc4aaa36_1
|
||||
- libedit=3.1.20191231=he28a2e2_2
|
||||
- libev=4.33=h516909a_1
|
||||
- libffi=3.3=he6710b0_2
|
||||
- libgcc-ng=9.3.0=h2828fa1_19
|
||||
- libgfortran-ng=9.3.0=hff62375_19
|
||||
- libgfortran5=9.3.0=hff62375_19
|
||||
- libglib=2.68.1=h3e27bee_0
|
||||
- libgomp=9.3.0=h2828fa1_19
|
||||
- libiconv=1.16=h516909a_0
|
||||
- liblapack=3.9.0=9_openblas
|
||||
- libnetcdf=4.7.4=mpi_mpich_hdef422e_7
|
||||
- libnghttp2=1.43.0=h812cca2_0
|
||||
- libopenblas=0.3.15=pthreads_h8fe5266_0
|
||||
- libpng=1.6.37=h21135ba_2
|
||||
- libsodium=1.0.18=h36c2ea0_1
|
||||
- libssh2=1.9.0=ha56f1ee_6
|
||||
- libstdcxx-ng=9.3.0=h6de172a_19
|
||||
- libtiff=4.2.0=hdc55705_0
|
||||
- libuuid=2.32.1=h7f98852_1000
|
||||
- libwebp-base=1.2.0=h7f98852_2
|
||||
- libxc=4.3.4=h86c2bf4_2
|
||||
- libxcb=1.13=h7f98852_1003
|
||||
- libxml2=2.9.10=hb55368b_3
|
||||
- locket=0.2.0=py_2
|
||||
- lz4-c=1.9.2=he1b5a44_3
|
||||
- markdown=3.3.4=pyhd8ed1ab_0
|
||||
- markupsafe=1.1.1=py38h497a2fe_3
|
||||
- matplotlib=3.4.1=py38h578d9bd_0
|
||||
- matplotlib-base=3.4.1=py38hcc49a3a_0
|
||||
- matplotlib-inline=0.1.2=pyhd8ed1ab_2
|
||||
- mistune=0.8.4=py38h497a2fe_1003
|
||||
- monty=2021.3.3=pyhd8ed1ab_0
|
||||
- more-itertools=8.7.0=pyhd8ed1ab_1
|
||||
- mpc=1.1.0=h04dde30_1009
|
||||
- mpfr=4.0.2=he80fd80_1
|
||||
- mpi=1.0=mpich
|
||||
- mpich=3.4.1=h846660c_104
|
||||
- mpmath=1.2.1=pyhd8ed1ab_0
|
||||
- nbclient=0.5.3=pyhd8ed1ab_0
|
||||
- nbconvert=6.0.7=py38h578d9bd_3
|
||||
- nbformat=5.1.3=pyhd8ed1ab_0
|
||||
- ncurses=6.2=he6710b0_1
|
||||
- nest-asyncio=1.5.1=pyhd8ed1ab_0
|
||||
- netcdf-fortran=4.5.3=mpi_mpich_hafa3f36_3
|
||||
- netcdf4=1.5.6=nompi_py38hf887595_102
|
||||
- networkx=2.5.1=pyhd8ed1ab_0
|
||||
- notebook=6.3.0=pyha770c72_1
|
||||
- numpy=1.20.2=py38h9894fe3_0
|
||||
- olefile=0.46=pyh9f0ad1d_1
|
||||
- openjpeg=2.4.0=hf7af979_0
|
||||
- openssl=1.1.1k=h7f98852_0
|
||||
- packaging=20.9=pyh44b312d_0
|
||||
- palettable=3.3.0=py_0
|
||||
- pandas=1.2.4=py38h1abd341_0
|
||||
- pandoc=2.12=h7f98852_0
|
||||
- pandocfilters=1.4.2=py_1
|
||||
- panel=0.11.3=pyhd8ed1ab_0
|
||||
- param=1.10.1=pyhd3deb0d_0
|
||||
- parso=0.8.2=pyhd8ed1ab_0
|
||||
- partd=1.2.0=pyhd8ed1ab_0
|
||||
- pathlib=1.0.1=py38h578d9bd_4
|
||||
- patsy=0.5.1=py_0
|
||||
- pcre=8.44=he1b5a44_0
|
||||
- pexpect=4.8.0=pyh9f0ad1d_2
|
||||
- phonopy=2.9.3=py38h5c078b8_0
|
||||
- pickleshare=0.7.5=py_1003
|
||||
- pillow=8.1.2=py38ha0e1e83_1
|
||||
- pip=21.0.1=py38h06a4308_0
|
||||
- plotly=4.14.3=pyh44b312d_0
|
||||
- pluggy=0.13.1=py38h578d9bd_4
|
||||
- pooch=1.3.0=pyhd8ed1ab_0
|
||||
- prometheus_client=0.10.1=pyhd8ed1ab_0
|
||||
- prompt-toolkit=3.0.18=pyha770c72_0
|
||||
- prompt_toolkit=3.0.18=hd8ed1ab_0
|
||||
- pthread-stubs=0.4=h36c2ea0_1001
|
||||
- ptyprocess=0.7.0=pyhd3deb0d_0
|
||||
- py=1.10.0=pyhd3deb0d_0
|
||||
- pybtex=0.24.0=py38h578d9bd_0
|
||||
- pycparser=2.20=pyh9f0ad1d_2
|
||||
- pyct=0.4.6=py_0
|
||||
- pyct-core=0.4.6=py_0
|
||||
- pydispatcher=2.0.5=py_1
|
||||
- pygments=2.9.0=pyhd8ed1ab_0
|
||||
- pymatgen=2022.0.7=py38h1fd1430_0
|
||||
- pyopenssl=20.0.1=pyhd8ed1ab_0
|
||||
- pyparsing=2.4.7=pyh9f0ad1d_0
|
||||
- pyqt=5.9.2=py38h05f1152_4
|
||||
- pyrsistent=0.17.3=py38h497a2fe_2
|
||||
- pysocks=1.7.1=py38h578d9bd_3
|
||||
- pytest=6.2.4=py38h578d9bd_0
|
||||
- pytest-cov=2.11.1=pyh44b312d_0
|
||||
- pytest-forked=1.3.0=pyhd3deb0d_0
|
||||
- pytest-sugar=0.9.4=pyh9f0ad1d_1
|
||||
- pytest-xdist=2.2.1=pyhd8ed1ab_0
|
||||
- python=3.8.8=hdb3f193_5
|
||||
- python-coveralls=2.9.3=py_0
|
||||
- python-dateutil=2.8.1=py_0
|
||||
- python_abi=3.8=1_cp38
|
||||
- pytz=2021.1=pyhd8ed1ab_0
|
||||
- pyviz_comms=2.0.1=pyhd3deb0d_0
|
||||
- pywavelets=1.1.1=py38h5c078b8_3
|
||||
- pyyaml=5.4.1=py38h497a2fe_0
|
||||
- pyzmq=22.0.3=py38h2035c66_1
|
||||
- qt=5.9.7=h5867ecd_1
|
||||
- qtconsole=5.1.0=pyhd8ed1ab_0
|
||||
- qtpy=1.9.0=py_0
|
||||
- readline=8.1=h27cfd23_0
|
||||
- requests=2.25.1=pyhd3deb0d_0
|
||||
- retrying=1.3.3=py_2
|
||||
- ruamel.yaml=0.16.12=py38h497a2fe_2
|
||||
- ruamel.yaml.clib=0.2.2=py38h497a2fe_2
|
||||
- scikit-image=0.18.1=py38h51da96c_0
|
||||
- scipy=1.6.3=py38h7b17777_0
|
||||
- scripttest=1.3.0=py_1
|
||||
- seaborn=0.11.1=hd8ed1ab_1
|
||||
- seaborn-base=0.11.1=pyhd8ed1ab_1
|
||||
- send2trash=1.5.0=py_0
|
||||
- setuptools=52.0.0=py38h06a4308_0
|
||||
- sip=4.19.13=py38he6710b0_0
|
||||
- six=1.16.0=pyh6c4a22f_0
|
||||
- spglib=1.16.1=py38h5c078b8_0
|
||||
- sqlite=3.35.4=hdfb4753_0
|
||||
- statsmodels=0.12.2=py38h5c078b8_0
|
||||
- sympy=1.8=py38h578d9bd_0
|
||||
- tabulate=0.8.9=pyhd8ed1ab_0
|
||||
- tbb=2020.2=h4bd325d_4
|
||||
- termcolor=1.1.0=py_2
|
||||
- terminado=0.9.4=py38h578d9bd_0
|
||||
- testpath=0.4.4=py_0
|
||||
- tifffile=2019.7.26.2=py38_0
|
||||
- tk=8.6.10=hbc83047_0
|
||||
- toml=0.10.2=pyhd8ed1ab_0
|
||||
- toolz=0.11.1=py_0
|
||||
- tornado=6.1=py38h497a2fe_1
|
||||
- tqdm=4.60.0=pyhd8ed1ab_0
|
||||
- traitlets=5.0.5=py_0
|
||||
- typing_extensions=3.7.4.3=py_0
|
||||
- tzlocal=2.0.0=py_0
|
||||
- uncertainties=3.1.5=pyhd8ed1ab_0
|
||||
- urllib3=1.26.4=pyhd8ed1ab_0
|
||||
- vtk=8.2.0=py38hf2e56f5_218
|
||||
- wcwidth=0.2.5=pyh9f0ad1d_2
|
||||
- webencodings=0.5.1=py_1
|
||||
- werkzeug=1.0.1=pyh9f0ad1d_0
|
||||
- wheel=0.36.2=pyhd3eb1b0_0
|
||||
- widgetsnbextension=3.5.1=py38h578d9bd_4
|
||||
- xorg-kbproto=1.0.7=h7f98852_1002
|
||||
- xorg-libice=1.0.10=h7f98852_0
|
||||
- xorg-libsm=1.2.3=hd9c2040_1000
|
||||
- xorg-libx11=1.7.0=h7f98852_0
|
||||
- xorg-libxau=1.0.9=h7f98852_0
|
||||
- xorg-libxdmcp=1.1.3=h7f98852_0
|
||||
- xorg-libxt=1.2.1=h7f98852_2
|
||||
- xorg-xproto=7.0.31=h7f98852_1007
|
||||
- xz=5.2.5=h7b6447c_0
|
||||
- yaml=0.2.5=h516909a_0
|
||||
- zeromq=4.3.4=h9c3ff4c_0
|
||||
- zipp=3.4.1=pyhd8ed1ab_0
|
||||
- zlib=1.2.11=h7b6447c_3
|
||||
- zstd=1.4.5=h9ceee32_0
|
||||
#prefix: /home/gmatteo/miniconda3/envs/my_binder
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,8 @@
|
|||
#!/bin/band
|
||||
# WARNING: Must be executed on a linux box.
|
||||
conda env remove -n abipy_binder
|
||||
conda create -n abipy_binder python=3.8
|
||||
conda install --file ../requirements.txt -y -c conda-forge
|
||||
conda install --file ../requirements-optional.txt -y -c conda-forge
|
||||
conda install abinit -c conda-forge
|
||||
conda env export > environment.yml
|
|
@ -7,9 +7,9 @@
|
|||
# Notebooks w/ extensions that auto-run code must be "trusted" to work the first time
|
||||
#jupyter trust index.ipynb
|
||||
|
||||
# Install abipy scripts and configuration files.
|
||||
# Install AbiPy scripts and configuration files.
|
||||
python setup.py install
|
||||
mkdir -p ${HOME}/.abinit/abipy
|
||||
cp abipy/data/managers/travis_scheduler.yml ${HOME}/.abinit/abipy/scheduler.yml
|
||||
cp abipy/data/managers/travis_manager.yml ${HOME}/.abinit/abipy/manager.yml
|
||||
#./dev_scripts/pyclean.py .
|
||||
#./dev_scripts/pyclean.py .
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS = -j1
|
||||
SPHINXOPTS = -j2
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1,7 @@
|
|||
{%- extends "!layout.html" %}
|
||||
|
||||
{%- block scripts %}
|
||||
<script type="text/javascript" src="https://cdn.plot.ly/plotly-latest.min.js"></script>
|
||||
{{ super() }}
|
||||
{%- endblock %}
|
||||
|
|
@ -78,7 +78,7 @@ panels Package
|
|||
:show-inheritance:
|
||||
|
||||
:mod:`pipelines` Module
|
||||
---------------------
|
||||
----------------------
|
||||
|
||||
.. automodule:: abipy.panels.pipelines
|
||||
:members:
|
||||
|
@ -88,7 +88,7 @@ panels Package
|
|||
:mod:`sigeph` Module
|
||||
---------------------
|
||||
|
||||
.. automodule:: abipy.panels.pipelines
|
||||
.. automodule:: abipy.panels.sigeph
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
|
147
docs/conf.py
147
docs/conf.py
|
@ -9,20 +9,24 @@ import sys
|
|||
import os
|
||||
import shutil
|
||||
|
||||
#import warnings
|
||||
|
||||
# Remove matplotlib agg warnings from generated doc when using plt.show
|
||||
import warnings
|
||||
|
||||
#warnings.filterwarnings("ignore", category=UserWarning,
|
||||
# message='Matplotlib is currently using agg, which is a'
|
||||
# ' non-GUI backend, so cannot show the figure.')
|
||||
|
||||
if not sys.warnoptions:
|
||||
warnings.simplefilter("ignore")
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
|
||||
ABIPY_ROOT = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
|
||||
|
||||
sys.path.insert(0, ABIPY_ROOT)
|
||||
|
||||
|
||||
import imp
|
||||
mod_name = os.path.join(ABIPY_ROOT, "abipy", "core", "release.py")
|
||||
relmod = imp.load_source(mod_name, mod_name)
|
||||
|
@ -53,7 +57,6 @@ extensions = [
|
|||
"sphinxarg.ext", # CLI doc
|
||||
'sphinxcontrib.bibtex',
|
||||
"jupyter_sphinx",
|
||||
#"jupyter_sphinx.execute",
|
||||
#'nbsphinx',
|
||||
#"releases",
|
||||
#'sphinx.ext.coverage',
|
||||
|
@ -113,7 +116,16 @@ mpl.rcParams['figure.dpi'] = 300
|
|||
# return figure_rst(image_names, gallery_conf['src_dir'])
|
||||
|
||||
|
||||
from sphinx_gallery.sorting import FileNameSortKey, NumberOfCodeLinesSortKey
|
||||
# Set plotly renderer to capture _repr_html_ for sphinx-gallery
|
||||
# https://sphinx-gallery.github.io/stable/auto_examples/plot_9_plotly.html
|
||||
import plotly.io as pio
|
||||
pio.renderers.default = 'sphinx_gallery'
|
||||
|
||||
# Here we change the default value of show used in the plotly decorator.
|
||||
from abipy.tools.plotting import set_plotly_default_show
|
||||
set_plotly_default_show(False)
|
||||
|
||||
from sphinx_gallery.sorting import ExampleTitleSortKey
|
||||
|
||||
sphinx_gallery_conf = {
|
||||
# path to your examples scripts
|
||||
|
@ -121,15 +133,14 @@ sphinx_gallery_conf = {
|
|||
"../abipy/examples/plot",
|
||||
"../abipy/examples/flows",
|
||||
],
|
||||
#'examples_dirs': [],
|
||||
# path where to save gallery generated examples
|
||||
'gallery_dirs': [
|
||||
"gallery",
|
||||
"flow_gallery",
|
||||
],
|
||||
'filename_pattern': "(/plot_*|/run_*)",
|
||||
'filename_pattern': "(/plot*|/run_*)",
|
||||
'default_thumb_file': '_static/abipy_logo.png',
|
||||
'within_subsection_order': NumberOfCodeLinesSortKey,
|
||||
'within_subsection_order': ExampleTitleSortKey,
|
||||
'backreferences_dir': None,
|
||||
#'reset_modules': (reset_mpl,),
|
||||
#'find_mayavi_figures': True,
|
||||
|
@ -143,17 +154,33 @@ sphinx_gallery_conf = {
|
|||
#'image_scrapers': ('matplotlib',),
|
||||
#'image_scrapers': ('matplotlib', 'mayavi'),
|
||||
#'image_scrapers': ('matplotlib', PNGScraper()),
|
||||
# TODO
|
||||
#https://sphinx-gallery.github.io/advanced_configuration.html#generate-binder-links-for-gallery-notebooks-experimental
|
||||
#'binder': {
|
||||
# 'org': 'abinit',
|
||||
# #'repo': 'abipy',
|
||||
# #'repo': 'https://github.com/abinit/abipy',
|
||||
# "repo": "http://abinit.github.io/abipy/",
|
||||
# 'url': 'https://mybinder.org', # URL serving binders (e.g. mybinder.org)
|
||||
# 'branch': 'develop', # Can also be a tag or commit hash
|
||||
# 'dependencies': '../binder/environment.yml' # list_of_paths_to_dependency_files>'
|
||||
# },
|
||||
#'image_scrapers': ('matplotlib', plotly),
|
||||
|
||||
# capture raw HTML or, if not present, __repr__ of last expression in
|
||||
# each code block
|
||||
'capture_repr': ('_repr_html_', '__repr__'),
|
||||
#
|
||||
# https://sphinx-gallery.github.io/stable/configuration.html#binder-links
|
||||
|
||||
'binder': {
|
||||
# Required keys
|
||||
'org': 'abinit',
|
||||
'repo': 'abipy',
|
||||
# Can be any branch, tag, or commit hash. Use a branch that hosts your docs.
|
||||
'branch': 'gh-pages',
|
||||
# Any URL of a binderhub deployment. Must be full URL (e.g. https://mybinder.org).
|
||||
'binderhub_url': 'https://mybinder.org',
|
||||
# A list of paths (relative to conf.py) to dependency files that Binder uses to infer
|
||||
# the environment needed to run your examples
|
||||
'dependencies': ["../binder/environment.yml", "../binder/postBuild"],
|
||||
# Optional keys
|
||||
# A prefix to prepend to any filepaths in Binder links.
|
||||
#'filepath_prefix': '<prefix>'
|
||||
# Jupyter notebooks for Binder will be copied to this directory (relative to built documentation root).
|
||||
#'notebooks_dir': '<notebooks-directory-name>'
|
||||
# Whether Binder links should start Jupyter Lab instead of the Jupyter Notebook interface.
|
||||
#'use_jupyter_lab': False,
|
||||
},
|
||||
}
|
||||
|
||||
# Generate the API documentation when building
|
||||
|
@ -174,7 +201,7 @@ master_doc = 'index'
|
|||
|
||||
# General information about the project.
|
||||
project = 'abipy'
|
||||
copyright = '2018, ' + relmod.author
|
||||
copyright = '2021, ' + relmod.author
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
|
@ -182,6 +209,7 @@ copyright = '2018, ' + relmod.author
|
|||
#
|
||||
# The short X.Y version.
|
||||
version = relmod.__version__
|
||||
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = relmod.__version__
|
||||
|
||||
|
@ -223,89 +251,21 @@ pygments_style = 'sphinx'
|
|||
# -- Options for HTML output ---------------------------------------------------
|
||||
|
||||
# Activate the theme.
|
||||
import sphinx_bootstrap_theme
|
||||
html_theme = 'bootstrap'
|
||||
html_theme_path = sphinx_bootstrap_theme.get_html_theme_path()
|
||||
|
||||
import sphinx_rtd_theme
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||
|
||||
# (Optional) Logo. Should be small enough to fit the navbar (ideally 24x24).
|
||||
# Path should be relative to the ``_static`` files directory.
|
||||
#html_logo = "my_logo.png"
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a
|
||||
# theme further.
|
||||
html_theme_options = {
|
||||
# Navigation bar title. (Default: ``project`` value)
|
||||
#'navbar_title': "Demo",
|
||||
|
||||
# Tab name for entire site. (Default: "Site")
|
||||
'navbar_site_name': "Site",
|
||||
|
||||
# A list of tuples containing pages or urls to link to.
|
||||
# Valid tuples should be in the following forms:
|
||||
# (name, page) # a link to a page
|
||||
# (name, "/aa/bb", 1) # a link to an arbitrary relative url
|
||||
# (name, "http://example.com", True) # arbitrary absolute url
|
||||
# Note the "1" or "True" value above as the third argument to indicate
|
||||
# an arbitrary url.
|
||||
#'navbar_links': [
|
||||
# ("Examples", "examples"),
|
||||
# ("Link", "http://example.com", True),
|
||||
#],
|
||||
|
||||
# Render the next and previous page links in navbar. (Default: true)
|
||||
'navbar_sidebarrel': True,
|
||||
|
||||
# Render the current pages TOC in the navbar. (Default: true)
|
||||
'navbar_pagenav': True,
|
||||
|
||||
# Tab name for the current pages TOC. (Default: "Page")
|
||||
'navbar_pagenav_name': "Page",
|
||||
|
||||
# Global TOC depth for "site" navbar tab. (Default: 1)
|
||||
# Switching to -1 shows all levels.
|
||||
'globaltoc_depth': 1,
|
||||
|
||||
# Include hidden TOCs in Site navbar?
|
||||
#
|
||||
# Note: If this is "false", you cannot have mixed ``:hidden:`` and
|
||||
# non-hidden ``toctree`` directives in the same page, or else the build
|
||||
# will break.
|
||||
#
|
||||
# Values: "true" (default) or "false"
|
||||
'globaltoc_includehidden': "true",
|
||||
|
||||
# HTML navbar class (Default: "navbar") to attach to <div> element.
|
||||
# For black navbar, do "navbar navbar-inverse"
|
||||
#'navbar_class': "navbar navbar-inverse",
|
||||
|
||||
# Fix navigation bar to top of page?
|
||||
# Values: "true" (default) or "false"
|
||||
'navbar_fixed_top': "true",
|
||||
|
||||
# Location of link to source.
|
||||
# Options are "nav" (default), "footer" or anything else to exclude.
|
||||
'source_link_position': "nav",
|
||||
|
||||
# Bootswatch (http://bootswatch.com/) theme.
|
||||
# Options are nothing (default) or the name of a valid theme
|
||||
# such as "cosmo" or "sandstone".
|
||||
#'bootswatch_theme': "united",
|
||||
#'bootswatch_theme': "flatly",
|
||||
#'bootswatch_theme': "litera",
|
||||
#'bootswatch_theme': "simplex",
|
||||
#'bootswatch_theme': "sandstone",
|
||||
|
||||
# Choose Bootstrap version.
|
||||
# Values: "3" (default) or "2" (in quotes)
|
||||
'bootstrap_version': "3",
|
||||
}
|
||||
|
||||
|
||||
def setup(app):
|
||||
"""
|
||||
Sphinx automatically calls your setup function defined in "conf.py" during the build process for you.
|
||||
There is no need to, nor should you, call this function directly in your code.
|
||||
http://www.sphinx-doc.org/en/stable/extdev/appapi.html
|
||||
See http://www.sphinx-doc.org/en/stable/extdev/appapi.html
|
||||
"""
|
||||
# Add custom css in _static
|
||||
#app.add_stylesheet("my_style.css")
|
||||
|
@ -505,6 +465,5 @@ from pybtex.plugin import register_plugin
|
|||
register_plugin('pybtex.style.labels', 'abipy', AbiPyLabelStyle)
|
||||
register_plugin('pybtex.style.formatting', 'abipystyle', AbiPyStyle)
|
||||
|
||||
|
||||
# This is for releases http://releases.readthedocs.io/en/latest/usage.html
|
||||
releases_github_path = "abinit/abipy"
|
||||
|
|
|
@ -7,15 +7,25 @@ Graphical interface
|
|||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
AbiPy provides interactive dashboards that can be used either as a standalone web apps
|
||||
with the `bokeh server <http://docs.bokeh.org/>`_ or inside jupyter notebooks.
|
||||
AbiPy provides interactive dashboards that can be used either as a standalone web applications
|
||||
(**dashboards**) with the `bokeh server <http://docs.bokeh.org/>`_ or inside jupyter notebooks.
|
||||
This document explains how to install the required dependencies and how to
|
||||
generate dashboards either with the command line interface or inside jupyter notebooks.
|
||||
generate dashboards/GUIs either with the command line interface (CLI) or inside jupyter notebooks.
|
||||
|
||||
.. important::
|
||||
|
||||
Note that you will need a running python kernel to execute the callbacks triggerered
|
||||
by the GUI hence the examples given in this page are only meant to show how to build the the GUI.
|
||||
Please note that one needs a **running python backend**
|
||||
to execute the callbacks triggerered by the GUI widgets.
|
||||
This part, indeed, is implemented in HTML/CSS/JS code executed
|
||||
by the frontend (i.e. **your browser**) that sends the signal
|
||||
to the python server (the **backend**).
|
||||
The python server is supposed to process the data
|
||||
and send the results back to the frontend for visualization purposes
|
||||
|
||||
Don't be surprised if you start to click buttons and **nothing happens**!
|
||||
The examples provided in this page are only meant to show how to build GUI
|
||||
or dashboards with AbiPy.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
@ -24,16 +34,16 @@ Install the `panel <https://panel.pyviz.org/>`_ package either from pip with:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install panel
|
||||
pip install panel
|
||||
|
||||
or with conda:
|
||||
or with conda (**recommended**) using:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
conda install panel -c conda-forge
|
||||
conda install panel -c conda-forge
|
||||
|
||||
If you want to work with JupyterLab, you will also need to install
|
||||
the optional PyViz JupyterLab extension:
|
||||
If you plan to use panel within JupyterLab, you will also need to install
|
||||
the PyViz JupyterLab extension and activate it with:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
@ -44,24 +54,37 @@ the optional PyViz JupyterLab extension:
|
|||
Basic Usage
|
||||
-----------
|
||||
|
||||
The AbiPy structure and many AbiPY files provide a ``get_panel`` method that returns
|
||||
a dashboard that can be used inside the jupyter notebook.
|
||||
To enable the integration with ``panel`` inside a jupyter notebook, execute the below code:
|
||||
Several AbiPy objects provide a ``get_panel`` method returning
|
||||
an object that can be displayed inside the jupyter notebook or inside a Bokeh server.
|
||||
When running inside a jupyter notebook, remember enable the integration
|
||||
with the ``panel`` infrastructure by executing:
|
||||
|
||||
.. jupyter-execute::
|
||||
|
||||
# Import panel and activate extensions
|
||||
import panel as pn
|
||||
pn.extension()
|
||||
from abipy import abilab
|
||||
abilab.abipanel();
|
||||
|
||||
Now one can start to construct AbiPy objects and use the ``get_panel`` method to generate graphical interfaces.
|
||||
In our first example, we use the ``abiopen`` function to open a ``GSR`` file
|
||||
and then we call ``get_panel`` to build a set of widgets that allows us to interact with the object:
|
||||
**before calling** any AbiPy ``get_panel`` method.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``abipanel`` function is needed to load extensions and javascript packages
|
||||
required by AbiPy.
|
||||
This function is just a small wrapper around the official panel API:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
import panel as pn
|
||||
pn.extension()
|
||||
|
||||
|
||||
At this point, we can start to construct AbiPy objects.
|
||||
For our first example, we use the ``abiopen`` function to open a ``GSR`` file,
|
||||
then we call ``get_panel`` to build a set of widgets that allows us to interact
|
||||
with the `GsrFile`:
|
||||
|
||||
.. jupyter-execute::
|
||||
|
||||
# Import AbiPy modules.
|
||||
from abipy import abilab
|
||||
import abipy.data as abidata
|
||||
|
||||
|
@ -70,75 +93,92 @@ and then we call ``get_panel`` to build a set of widgets that allows us to inter
|
|||
|
||||
gsr.get_panel()
|
||||
|
||||
The **summary** tab provides a string representation of the file
|
||||
but there is not widget to interact with it.
|
||||
If you select the **e-Bands** tab, you will see several widgets and a button
|
||||
that activates the visualization of the KS band energies.
|
||||
Again, in this HTML page there is no python server running in background so
|
||||
if you click the **Plot e-bands** button nothing happens (this is not a bug!).
|
||||
|
||||
The same approach can be used with a ``DDB`` file.
|
||||
In this case, we get more tabs and options because one can use the GUI
|
||||
to set the input parameters, invoke ``anaddb`` and visualize the results:
|
||||
The advantage of this notebook-based approach is that it is possible to mix
|
||||
the panel GUIs with python code that can be used to perform
|
||||
more advanced tasks not supported by the GUI.
|
||||
|
||||
|
||||
.. jupyter-execute::
|
||||
|
||||
# Open DDB file with abiopen and invoke get_panel method.
|
||||
#ddb_path = abidata.ref_file("mp-1009129-9x9x10q_ebecs_DDB")
|
||||
|
||||
#abilab.abiopen(ddb_path).get_panel()
|
||||
|
||||
|
||||
Calling ``get_structure`` with an AbiPy structure, creates a set of widgets
|
||||
to facilitate common operations such as exporting to a different format or
|
||||
generating a Abinit input file for GS calculations:
|
||||
Obviously it is possible to have multiple panels running in the same notebook.
|
||||
Calling ``get_structure`` with an AbiPy structure, for instance, creates a set of widgets
|
||||
to facilitate common operations such as exporting the structure to a different format or
|
||||
generating a basic Abinit input file for e.g. GS calculations:
|
||||
|
||||
.. jupyter-execute::
|
||||
|
||||
gsr.structure.get_panel()
|
||||
|
||||
.. note::
|
||||
|
||||
There are, however, cases in which you don't need the interactive environment provided
|
||||
by jupyter notebooks as you are mainly interested in the visualization of the results.
|
||||
In this case, it is possible to use the command line interface to automatically generate
|
||||
a dashboard with widgets without having to start a jupyter-lab application.
|
||||
At present, not all the AbiPy objects support the ``get_panel`` protocol
|
||||
but we plan to gradually support more objects, especially the most important
|
||||
netcdf files produced by Abinit
|
||||
|
||||
To build a dashboard for a ``Structure`` object extract from ``FILE``, use:
|
||||
To generate a notebook from the command line, use the abiopen.py_ script:
|
||||
|
||||
.. code-block:: shell
|
||||
.. code-block:: bash
|
||||
|
||||
abistruct.py panel FILE
|
||||
abiopen.py si_nscf_GSR.nc -nb # short for --notebook
|
||||
|
||||
that will automatically open the notebook inside jupyterlab.
|
||||
If you prefer classic jupyter notebooks, use the ``-nb --classic-notebook`` options
|
||||
|
||||
where ``FILE`` is any file providing a ``Structure`` object e.g. netcdf file, cif files, abi, abo etc.
|
||||
If you do not need to execute python code, you may want to generate a panel dashboard with:
|
||||
|
||||
To build a dashboard associated to one of the AbiPy file, use the syntax:
|
||||
.. code-block:: bash
|
||||
|
||||
.. code-block:: shell
|
||||
abiopen.py si_nscf_GSR.nc -pn # short for --panel
|
||||
|
||||
abiopen.py FILE --panel
|
||||
|
||||
|
||||
where ``FILE`` is one of the Abinit files supported by ``abiopen.py``.
|
||||
For instance, one can create a dashboard to interact with a ``DDB`` file with:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
abiopen.py out_DDB --panel
|
||||
|
||||
.. important::
|
||||
|
||||
To build a dashboard for an AbiPy Flow use:
|
||||
|
||||
abirun.py FLOWDIR panel
|
||||
|
||||
or, alternatively:
|
||||
|
||||
abiopen.py FLOWDIR/__AbinitFlow__.pickle --panel
|
||||
The same approach can be used with a ``DDB`` file.
|
||||
In this case, we get more tabs and options because one can use the GUI
|
||||
to set the input parameters, invoke ``anaddb`` and visualize the results:
|
||||
|
||||
.. jupyter-execute::
|
||||
|
||||
import numpy as np
|
||||
from matplotlib import pyplot
|
||||
%matplotlib inline
|
||||
# Open DDB file with abiopen and invoke get_panel method.
|
||||
ddb_path = abidata.ref_file("mp-1009129-9x9x10q_ebecs_DDB")
|
||||
abilab.abiopen(ddb_path).get_panel()
|
||||
|
||||
x = np.linspace(1E-3, 2 * np.pi)
|
||||
The same result can be obtained from the CLI with
|
||||
|
||||
pyplot.plot(x, np.sin(x) / x)
|
||||
pyplot.plot(x, np.cos(x))
|
||||
pyplot.grid()
|
||||
.. code-block:: bash
|
||||
|
||||
abiopen.py mp-1009129-9x9x10q_ebecs_DDB -nb
|
||||
|
||||
There are, however, cases in which you don't need the interactive environment provided
|
||||
by jupyter notebooks as you are mainly interested in the visualization of the results.
|
||||
In this case, it is possible to use the command line interface to automatically generate
|
||||
a dashboard with widgets without having to start a jupyter-lab application.
|
||||
|
||||
To build a dashboard for a ``Structure`` object extracted from ``FILE``, use::
|
||||
|
||||
abistruct.py panel FILE
|
||||
|
||||
where ``FILE`` is **any** file providing a ``Structure`` object
|
||||
e.g. netcdf files, cif files, abi, abo files etc.
|
||||
|
||||
To build a dashboard associated to one of the AbiPy file, use the syntax::
|
||||
|
||||
|
||||
abiopen.py FILE --panel
|
||||
|
||||
where ``FILE`` is one of the Abinit files supported by ``abiopen.py``.
|
||||
For instance, one can create a dashboard to interact with a ``DDB`` file with::
|
||||
|
||||
abiopen.py out_DDB --panel
|
||||
|
||||
|
||||
.. important::
|
||||
|
||||
To build a dashboard for an AbiPy Flow use::
|
||||
|
||||
abirun.py FLOWDIR panel
|
||||
|
||||
or alternatively::
|
||||
|
||||
abiopen.py FLOWDIR/__AbinitFlow__.pickle --panel
|
||||
|
|
|
@ -59,9 +59,9 @@ API
|
|||
Indices and tables
|
||||
==================
|
||||
|
||||
:ref:`genindex`
|
||||
:ref:`modindex`
|
||||
:ref:`search`
|
||||
:ref:`genindex`
|
||||
:ref:`modindex`
|
||||
:ref:`search`
|
||||
|
||||
License
|
||||
=======
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue