1""""Panels for DDB files.""" 2 3import param 4import panel as pn 5import panel.widgets as pnw 6import bokeh.models.widgets as bkw 7 8from abipy.panels.core import AbipyParameterized 9 10 11class DdbFilePanel(AbipyParameterized): 12 """ 13 A panel to analyze a |DdbFile|. 14 Provides widgets to invoke anaddb and visualize the results. 15 """ 16 verbose = param.Integer(0, bounds=(0, None), doc="Verbosity Level") 17 mpi_procs = param.Integer(1, bounds=(1, None), doc="Number of MPI processes used in anaddb") 18 19 nqsmall = param.Integer(10, bounds=(1, None), doc="Number of divisions for smallest vector to generate Q-mesh") 20 ndivsm = param.Integer(5, bounds=(1, None), doc="Number of divisions for smallest segment in q-path") 21 lo_to_splitting = param.ObjectSelector(default="automatic", objects=["automatic", True, False]) 22 chneut = param.ObjectSelector(default=1, objects=[0, 1, 2], doc="Abinit variable") 23 dipdip = param.ObjectSelector(default=1, objects=[0, 1], doc="Abinit variable") 24 asr = param.ObjectSelector(default=2, objects=[0, 1, 2], doc="Abinit variable") 25 units = param.ObjectSelector(default="eV", objects=["eV", "meV", "Ha", "cm-1", "Thz"], doc="Energy units") 26 27 dos_method = param.ObjectSelector(default="tetra", objects=["tetra", "gaussian"], doc="Integration method for DOS") 28 temp_range = pnw.RangeSlider(name="T-range", start=0.0, end=1000, value=(0.0, 300.0), step=20) 29 30 gamma_ev = param.Number(1e-4, bounds=(1e-20, None), doc="Phonon linewidth in eV") 31 w_range = pnw.RangeSlider(name="Frequency range (eV)", start=0.0, end=1.0, 32 value=(0.0, 0.1), step=0.001) 33 34 get_epsinf_btn = pnw.Button(name="Compute", button_type='primary') 35 plot_phbands_btn = pnw.Button(name="Plot Bands and DOS", button_type='primary') 36 plot_eps0w_btn = pnw.Button(name="Plot eps0(omega)", button_type='primary') 37 38 plot_vsound_btn = pnw.Button(name="Calculate speed of sound", button_type='primary') 39 plot_check_asr_dipdip_btn = pnw.Button(name="Compute phonons with/wo ASR and DIPDIP", button_type='primary') 40 plot_ifc_btn = pnw.Button(name="Compute IFC(R)", button_type='primary') 41 42 def __init__(self, ddb, **params): 43 super().__init__(**params) 44 self.ddb = ddb 45 46 @param.depends('get_epsinf_btn.clicks') 47 def get_epsinf(self): 48 """Compute eps_infinity and Born effective charges from DDB.""" 49 if self.get_epsinf_btn.clicks == 0: return 50 51 epsinf, becs = self.ddb.anaget_epsinf_and_becs(chneut=self.chneut, 52 mpi_procs=self.mpi_procs, verbose=self.verbose) 53 54 gen, inp = self.ddb.anaget_dielectric_tensor_generator(asr=self.asr, chneut=self.chneut, dipdip=self.dipdip, 55 mpi_procs=self.mpi_procs, verbose=self.verbose, 56 return_input=True) 57 58 eps0 = gen.tensor_at_frequency(w=0, gamma_ev=self.gamma_ev) 59 #eps0 = pnw.DataFrame(eps0.get_dataframe()) 60 return pn.Column(epsinf, eps0, becs, pn.pane.HTML(inp._repr_html_())) 61 62 @param.depends('plot_eps0w_btn.clicks') 63 def plot_eps0w(self): 64 """Compute eps0(omega) from DDB and plot the results.""" 65 if self.plot_eps0w_btn.clicks == 0: return 66 gen, inp = self.ddb.anaget_dielectric_tensor_generator(asr=self.asr, chneut=self.chneut, dipdip=self.dipdip, 67 mpi_procs=self.mpi_procs, verbose=self.verbose, 68 return_input=True) 69 ws = self.w_range.value 70 w_max = ws[1] 71 if w_max == 1.0: w_max = None # Will compute w_max in plot routine from ph freqs. 72 73 def p(component, reim): 74 return gen.plot(w_min=ws[0], w_max=w_max, gamma_ev=self.gamma_ev, num=500, component=component, 75 reim=reim, units=self.units, **self.fig_kwargs) 76 77 # Build grid 78 gspec = pn.GridSpec(sizing_mode='scale_width') 79 gspec[0, 0] = p("diag", "re") 80 gspec[0, 1] = p("diag", "im") 81 gspec[1, 0] = p("offdiag", "re") 82 gspec[1, 1] = p("offdiag", "im") 83 gspec[2, :] = gen.get_oscillator_dataframe(reim="all", tol=1e-6) 84 # Add HTML pane with input. 85 gspec[3, 0] = pn.pane.HTML(inp._repr_html_()) 86 87 return gspec 88 89 @param.depends('plot_phbands_btn.clicks') 90 def plot_phbands_and_phdos(self, event=None): 91 """Compute phonon bands and ph-DOSes from DDB and plot the results.""" 92 if self.plot_phbands_btn.clicks == 0: return 93 #self.plot_phbands_btn.button_type = "warning" 94 95 #print("Computing phbands") 96 with self.ddb.anaget_phbst_and_phdos_files( 97 nqsmall=self.nqsmall, qppa=None, ndivsm=self.ndivsm, 98 line_density=None, asr=self.asr, chneut=self.chneut, dipdip=self.dipdip, 99 dos_method=self.dos_method, lo_to_splitting=self.lo_to_splitting, 100 verbose=self.verbose, mpi_procs=self.mpi_procs, return_input=True) as g: 101 102 phbst_file, phdos_file = g 103 phbands, phdos = phbst_file.phbands, phdos_file.phdos 104 #print("Computing phbands completed") 105 106 # Build grid 107 gspec = pn.GridSpec(sizing_mode='scale_width') 108 gspec[0, 0] = phbands.plot_with_phdos(phdos, units=self.units, **self.fig_kwargs) 109 gspec[0, 1] = phdos_file.plot_pjdos_type(units=self.units, exchange_xy=True, **self.fig_kwargs) 110 gspec[1, 0] = phdos_file.msqd_dos.plot(units=self.units, **self.fig_kwargs) 111 temps = self.temp_range.value 112 gspec[1, 1] = phdos.plot_harmonic_thermo(tstart=temps[0], tstop=temps[1], num=50, **self.fig_kwargs) 113 #msqd_dos.plot_tensor(**self.fig_kwargs) 114 #self.plot_phbands_btn.button_type = "primary" 115 116 # Add HTML pane with input 117 gspec[2,:] = pn.pane.HTML(g.input._repr_html_()) 118 119 return gspec 120 121 @param.depends('plot_vsound_btn.clicks') 122 def plot_vsound(self): 123 """ 124 Compute the speed of sound by fitting phonon frequencies 125 along selected directions by linear least-squares fit. 126 """ 127 if self.plot_vsound_btn.clicks == 0: return 128 from abipy.dfpt.vsound import SoundVelocity 129 sv = SoundVelocity.from_ddb(self.ddb.filepath, num_points=20, qpt_norm=0.1, 130 ignore_neg_freqs=True, asr=self.asr, chneut=self.chneut, dipdip=self.dipdip, 131 verbose=self.verbose, mpi_procs=self.mpi_procs) 132 133 # Insert results in grid. 134 gspec = pn.GridSpec(sizing_mode='scale_width') 135 gspec[0, :1] = sv.get_dataframe() 136 gspec[1, :1] = sv.plot(**self.fig_kwargs) 137 138 return gspec 139 140 @param.depends('plot_check_asr_dipdip_btn.clicks') 141 def plot_without_asr_dipdip(self): 142 if self.plot_check_asr_dipdip_btn.clicks == 0: return 143 144 # Insert results in grid. 145 gspec = pn.GridSpec(sizing_mode='scale_width') 146 147 asr_plotter = self.ddb.anacompare_asr(asr_list=(0, 2), chneut_list=(1, ), dipdip=1, 148 lo_to_splitting=self.lo_to_splitting, 149 nqsmall=self.nqsmall, ndivsm=self.ndivsm, 150 dos_method=self.dos_method, ngqpt=None, 151 verbose=self.verbose, mpi_procs=self.mpi_procs) 152 gspec[0, :1] = asr_plotter.plot(**self.fig_kwargs) 153 154 dipdip_plotter = self.ddb.anacompare_dipdip(chneut_list=(1,), asr=2, lo_to_splitting=self.lo_to_splitting, 155 nqsmall=self.nqsmall, ndivsm=self.ndivsm, 156 dos_method=self.dos_method, ngqpt=None, 157 verbose=self.verbose, mpi_procs=self.mpi_procs) 158 gspec[1, :1] = dipdip_plotter.plot(**self.fig_kwargs) 159 return gspec 160 161 @param.depends('plot_ifc_btn.clicks') 162 def plot_ifc(self): 163 if self.plot_ifc_btn.clicks == 0: return 164 165 ifc = self.ddb.anaget_ifc(asr=self.asr, chneut=self.chneut, dipdip=self.dipdip) 166 167 # Insert results in grid. 168 gspec = pn.GridSpec(sizing_mode='scale_width') 169 gspec[0, :1] = ifc.plot_longitudinal_ifc(title="Longitudinal IFCs", show=False) 170 gspec[1, :1] = ifc.plot_longitudinal_ifc_short_range(title="Longitudinal IFCs short range", show=False) 171 gspec[2, :1] = ifc.plot_longitudinal_ifc_ewald(title="Longitudinal IFCs Ewald", show=False) 172 173 return gspec 174 175 def get_panel(self): 176 """Return tabs with widgets to interact with the DDB file.""" 177 tabs = pn.Tabs(); app = tabs.append 178 row = pn.Row(bkw.PreText(text=self.ddb.to_string(verbose=self.verbose), sizing_mode="scale_both")) 179 app(("Summary", row)) 180 app(("Ph-bands", pn.Row( 181 pn.Column("# PH-bands options", 182 *[self.param[k] for k in ("nqsmall", "ndivsm", "asr", "chneut", "dipdip", 183 "lo_to_splitting", "dos_method")], 184 self.temp_range, self.plot_phbands_btn), 185 self.plot_phbands_and_phdos) 186 )) 187 app(("BECs", pn.Row( 188 pn.Column("# Born effective charges options", 189 *[self.param[k] for k in ("asr", "chneut", "dipdip", "gamma_ev")], self.get_epsinf_btn), 190 self.get_epsinf) 191 )) 192 app(("eps0", pn.Row( 193 pn.Column("# epsilon_0", 194 *[self.param[k] for k in ("asr", "chneut", "dipdip", "gamma_ev")], 195 self.w_range, self.plot_eps0w_btn), 196 self.plot_eps0w) 197 )) 198 app(("Speed of sound", pn.Row( 199 pn.Column("# Speed of sound options", 200 *[self.param[k] for k in ("asr", "chneut", "dipdip")], 201 self.plot_vsound_btn), 202 self.plot_vsound) 203 )) 204 app(("Check ASR and DIPDIP", pn.Row( 205 pn.Column("# Options", 206 *[self.param[k] for k in ("nqsmall", "ndivsm", "dos_method")], 207 self.plot_check_asr_dipdip_btn), 208 self.plot_without_asr_dipdip) 209 )) 210 211 app(("IFCs", pn.Row( 212 pn.Column("# Options", 213 *[self.param[k] for k in ("asr", "dipdip", "chneut")], 214 self.plot_ifc_btn), 215 self.plot_ifc) 216 )) 217 218 app(("Global Opts", pn.Column("# Global Options", *[self.param[k] for k in ("units", "mpi_procs", "verbose")]))) 219 220 return tabs 221