1 /* Copyright (c) 2015  Gerald Knizia
2  *
3  * This file is part of the IboView program (see: http://www.iboview.org)
4  *
5  * IboView is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, version 3.
8  *
9  * IboView is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with bfint (LICENSE). If not, see http://www.gnu.org/licenses/
16  *
17  * Please see IboView documentation in README.txt for:
18  * -- A list of included external software and their licenses. The included
19  *    external software's copyright is not touched by this agreement.
20  * -- Notes on re-distribution and contributions to/further development of
21  *    the IboView software
22  */
23 
24 #include "Iv.h"
25 #include "IvComputeWfForm.h"
26 #include "IvSettings.h"
27 #include "QPropertyModel.h"
28 #include "ui_ComputeWfForm.h"
29 #include "IvDocument.h"
30 #include "CtBasisSet.h"
31 #include "CtAtomSet.h"
32 
33 extern "C" {
34    size_t getMemorySize(); // memory_size.c
35 }
36 
FComputeWfForm(FDocument * document,QWidget * parent)37 FComputeWfForm::FComputeWfForm(FDocument *document, QWidget *parent)
38    : QDialog(parent),
39      ui(new Ui::ComputeWfForm),
40      m_pDocument(document),
41      m_bMemoryOkay(true),
42      m_bOtherError(false)
43 {
44    ui->setupUi(this);
45 //    ui->label_WorkSpace->setVisible(false);
46 //    ui->spinBox_WorkSpacePerThread->setVisible(false);
47    ui->spinBox_WorkSpacePerThread->setEnabled(false);
48 
49 //    ui->tabWidget->layout()->setContentsMargins(0, 0, 0, 0); // left, top, right, bottom
50 
51 //    m_pDocument->GetWfOptions()->setObjectName("WfOptions");
52    LinkPropertyWidgets(m_pDocument->GetWfOptions(), this, "wf_option");
53    connect(ui->checkBox_RunScf, SIGNAL(toggled(bool)), this, SLOT(ToggleScfPage(bool)));
54    connect(ui->checkBox_RunIbba, SIGNAL(toggled(bool)), this, SLOT(ToggleIbbaPage(bool)));
55 
56    connect(ui->comboBox_ScfMethod, SIGNAL(currentIndexChanged(int)), this, SLOT(RecomputeMemory()));
57    connect(ui->comboBox_ScfOrbitalBasis, SIGNAL(currentIndexChanged(int)), this, SLOT(RecomputeMemory()));
58    connect(ui->comboBox_ScfFitBasis, SIGNAL(currentIndexChanged(int)), this, SLOT(RecomputeMemory()));
59    connect(ui->spinBox_NumThreads, SIGNAL(valueChanged(int)), this, SLOT(RecomputeMemory()));
60    connect(ui->spinBox_WorkSpacePerThread, SIGNAL(valueChanged(int)), this, SLOT(RecomputeMemory()));
61    connect(ui->spinBox_WfCharge, SIGNAL(valueChanged(int)), this, SLOT(RecomputeMemory()));
62    connect(ui->spinBox_WfSpin, SIGNAL(valueChanged(int)), this, SLOT(RecomputeMemory()));
63    RecomputeMemory();
64 
65    CheckEcps();
66 
67    // if there already is electronic structure stuff, don't make new IBOs by default, unless
68    // the user actually asked for it explicitly.
69    if (m_pDocument->GetCurrentFrame() && m_pDocument->GetCurrentFrame()->HaveOrbitals()) {
70       ui->checkBox_RunScf->setChecked(false);
71    }
72 
73    ui->buttonBox->setFocus();
74 
75    if (!IvRestoreWindowSize("ComputeWindow/Size", this))
76       IvGuessSubDialogSize(this);
77 }
78 
79 // void FComputeWfForm::closeEvent(QCloseEvent *event)
80 // {
81 //    IvSaveWindowSize("ComputeWindow/Size", this);
82 //    return QDialog::closeEvent(event);
83 // }
84 
85 
~FComputeWfForm()86 FComputeWfForm::~FComputeWfForm()
87 {
88    IvSaveWindowSize("ComputeWindow/Size", this);
89    delete ui;
90 }
91 
ToggleScfPage(bool Checked)92 void FComputeWfForm::ToggleScfPage(bool Checked)
93 {
94    ui->page_WfSetup->setEnabled(Checked);
95    if (Checked)
96       ui->tabWidget->setCurrentIndex(0);
97    else
98       ui->tabWidget->setCurrentIndex(1);
99 }
100 
ToggleIbbaPage(bool Checked)101 void FComputeWfForm::ToggleIbbaPage(bool Checked)
102 {
103    ui->page_IbbaSetup->setEnabled(Checked);
104    if (Checked)
105       ui->tabWidget->setCurrentIndex(1);
106 }
107 
SetMemoryText(QString s,FStatusClass Class)108 void FComputeWfForm::SetMemoryText(QString s, FStatusClass Class)
109 {
110    ui->label_MemoryGuess->setStyleSheet(QString("QLabel{padding: .2ex; font-size: 12pt; font-weight: bold; %1} QLabel::disabled{background: #444; color:#aaa}").arg(GetStatusStyle(Class)));
111    ui->label_MemoryGuess->setText(s);
112 }
113 
114 
RecomputeMemory()115 void FComputeWfForm::RecomputeMemory()
116 {
117    m_bMemoryOkay = true;
118    m_bOtherError = true; // will be cleared at end of 'try{..}'
119    try {
120       FFrame
121          *pFrame = m_pDocument->GetCurrentFrame();
122       ct::FAtomSet
123          *pOrigAtoms = 0;
124       if (pFrame)
125          pOrigAtoms = pFrame->pGetAtoms();
126       if (pOrigAtoms == 0)
127          return SetMemoryText("[no geometry]", STATUS_Confused);
128       // make a copy of the atom set and set the current bases.
129       ct::FAtomSet
130          Atoms(*pOrigAtoms);
131       FWfOptions
132          *pWfOptions = m_pDocument->GetWfOptions();
133       pWfOptions->AssignBasisSets(&Atoms);
134 
135       // currently open-shell is not supported for KS... check number of electrons
136       // and extra spin. Should be fixed soon.
137       int
138          nElecTotal = (Atoms.NuclearCharge() - pWfOptions->GetCharge());
139 //       IvEmit("!!nElecTotal = %1", nElecTotal);
140       if (nElecTotal < 0)
141          return SetMemoryText("[nElec < 0]", STATUS_Confused);
142       if (pWfOptions->GetExtraSpin() != 0 || (unsigned(nElecTotal) % 2) != 0)
143          return SetMemoryText("[open-shell not working]", STATUS_Confused);
144 
145       // instanciate the fitting sets to see how large they are.
146       ct::FBasisSet
147          OrbBasis(Atoms, ct::BASIS_Orbital),
148          FitBasis(Atoms, ct::BASIS_JkFit);
149       size_t
150          nAo = OrbBasis.nFn(),
151          nFit = FitBasis.nFn();
152 //       IvEmit("Basis sizes: nAo = %1  nFit = %2", nAo, nFit);
153 
154       // that is the estimate for the fully caching small-molecule 3ix DF-RKS.
155       size_t
156          nThreads = (size_t)pWfOptions->GetNumThreads(),
157          nWorkSpaceShared = sizeof(double) * (8*nAo*nAo + nFit*nFit),
158          nMemEst = nWorkSpaceShared + sizeof(double) * (nFit*((nAo*(nAo+1))/2)),
159 //          nMemEst = sizeof(double) * (8*nAo*nAo + nFit*nFit + nFit*((nAo*(nAo+1))/2)),
160          nSysMem = getMemorySize(); // amount of physical memory on the system.
161 
162       size_t
163          nMinWorkSpacePerThread = size_t(20)<<20; // 20 MB
164       nMinWorkSpacePerThread += sizeof(double)*(std::max(size_t(2), size_t(FitBasis.nFnOfLargestShell())) * nAo*nAo);
165       // ^- 2 fock matrices per thread in AccXc and nFnOfLargestShell() for FormIntMNF
166       //    as intermediate while building the cached integrals. The latter could certainly
167       //    be reduced if I find some time. But for the moment this will have to work...
168       nMemEst += nThreads * nMinWorkSpacePerThread;
169       pWfOptions->SetWorkSpaceMb((nMinWorkSpacePerThread + nWorkSpaceShared/nThreads)>>20);
170 
171 //       nMemEst += size_t(pWfOptions->GetNumThreads()) * (size_t(pWfOptions->GetWorkSpaceMb()) << 20);
172 
173 //       nSysMem = size_t(8) << 30;
174 
175       if (nSysMem == 0)
176          nSysMem = size_t(8) << 30; // assume 8 GB.
177 
178 //       IvEmit("This system has %1 GB of memory. Does it?", double(nSysMem)/double(1<<30));
179       double
180          f = (double(nMemEst) + double(size_t(2)<<30)) / double(nSysMem);
181       // convert to MB
182       nMemEst >>= 20;
183       FStatusClass
184          Class = STATUS_Confused;
185       if (f < 0.3)
186          Class = STATUS_Idle;
187       else if (f < 0.8)
188          Class = STATUS_Warning;
189       else {
190          Class = STATUS_Error;
191          m_bMemoryOkay = false;
192       }
193       SetMemoryText(QString("%1 MB").arg((int)nMemEst), Class);
194       m_bOtherError = false;
195 
196    } catch (std::runtime_error &e) {
197       SetMemoryText("[failed to load basis set]", STATUS_Confused);
198       m_bOtherError = true;
199    }
200 }
201 
CheckEcps()202 void FComputeWfForm::CheckEcps()
203 {
204    try {
205       FFrame
206          *pFrame = m_pDocument->GetCurrentFrame();
207       ct::FAtomSet
208          *pOrigAtoms = 0;
209       if (pFrame)
210          pOrigAtoms = pFrame->pGetAtoms();
211       if (pOrigAtoms == 0)
212          return SetMemoryText("[no geometry]", STATUS_Confused);
213       bool NeedsEcps = false;
214       for (size_t iAt = 0; iAt < pOrigAtoms->size(); ++ iAt) {
215          if ((*pOrigAtoms)[iAt].AtomicNumber > 36)
216             NeedsEcps = true;
217       }
218 
219       if (NeedsEcps) {
220          ui->textBrowser_WfNotes->setText("<div style=\"font-size: 11pt; color:#ccc\"><p><div style=\"font-size: 13pt; color:white\">"
221             "Sorry, MicroScf currently cannot do this calculation :(.</div> "
222             "It can only compute Kohn-Sham wave functions up to element 36 (Kr), due to "
223             "a lack of ECP integrals.</p>"
224             "<p>Note: Chemical analysis of an imported wave function should still work.</p></div>");
225          ui->checkBox_RunScf->setChecked(false);
226          ui->checkBox_RunScf->setEnabled(false);
227       }
228    } catch (std::runtime_error &e) {
229       ui->textBrowser_WfNotes->setText("[failed to instanciate FAtomSet]");
230    }
231 }
232 
233 
234 
235 
236 
GetRunScf() const237 bool FComputeWfForm::GetRunScf() const
238 {
239    return ui->checkBox_RunScf->isChecked();
240 }
241 
GetRunIbba() const242 bool FComputeWfForm::GetRunIbba() const
243 {
244    return ui->checkBox_RunIbba->isChecked();
245 }
246 
IsMemoryOkay() const247 bool FComputeWfForm::IsMemoryOkay() const
248 {
249    return m_bMemoryOkay;
250 }
251