Skip to content

Commit baedfd2

Browse files
andyclaude
andcommitted
Merge wip/small-a9: GROMACS names in the Tools menu, MO coefficient labels, Launch anyway test, Geometry Trace on Total Energy
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BTQ7mniRtDdhU7VF9tEVBD
2 parents af9e0a9 + 96d2f70 commit baedfd2

10 files changed

Lines changed: 86 additions & 18 deletions

File tree

‎docs/claude/wx-viewer/md-editor-tools-are-registered-as-nwchems.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ button, so a GROMACS Optimize showed "NWChem M..." clipped.
1414
(NWChem MD tasks are `NWChemMD`, their study `MDStudy`); `shortLabel`
1515
drops a trailing " Editor"; the button's width is its label's and the
1616
panel gives all its buttons the widest one, so the property columns still
17-
line up. The menu items ("NWChem MD Optimize &Editor...") still say NWChem.
17+
line up. The Tools menu items get the same substitution (`CalcMgr::getToolsMenu`); the hook `toolsmenu <url>` lists them.
1818

1919
Check: the Organizer hook `summary <url>` (ECCE_TEST_ORGANIZER) lists
2020
`tool=<label>` per button, with `:clipped` when the label is wider than

‎src/apps/builder/BuilderTraceStress.C‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,18 @@ bool Builder::traceStressCommand(SceneScript& s, const vector<string>& w)
217217
return true;
218218
}
219219

220+
// "gttitle <text>": the plot's title contains <text> (the series shown).
221+
if (c == "gttitle" && w.size() >= 2) {
222+
ewxPlotCtrl *plot = plotOf(gt);
223+
string want = w[1];
224+
for (size_t i = 2; i < w.size(); i++) want += " " + w[i];
225+
if (!plot) return s.fail("gttitle: no plot");
226+
string title = string(plot->GetPlotTitle().ToUTF8());
227+
if (title.find(want) == string::npos)
228+
return s.fail("gttitle: plot shows '" + title + "', want '" + want + "'");
229+
return true;
230+
}
231+
220232
// "gtpick <step|mid|last>": click the plot where that step's point is
221233
// drawn (zero-based; mid and last of the plotted points), as a user does; the molecule on screen must then be the
222234
// one the trace holds for that step.

‎src/apps/builder/GeomTracePropertyPanel.C‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ GeomTracePropertyPanel::GeomTracePropertyPanel()
7272
p_recompute(false),
7373
p_fold(true),
7474
p_currentProp(""),
75+
p_propChosen(false),
7576
p_importantProps(),
7677
p_keyToId(),
7778
p_idToKey()
@@ -89,6 +90,7 @@ GeomTracePropertyPanel::GeomTracePropertyPanel(IPropCalculation *calculation,
8990
p_recompute(false),
9091
p_fold(false),
9192
p_currentProp(""),
93+
p_propChosen(false),
9294
p_importantProps(),
9395
p_keyToId(),
9496
p_idToKey()
@@ -247,7 +249,11 @@ void GeomTracePropertyPanel::restoreSettings()
247249
config->Read("GeomTrace/Delay",&p_delay,500);
248250
p_currentProp = config->Read("GeomTrace/Prop","");
249251
if (p_currentProp.empty() || !getCalculation()->getProperty(p_currentProp)) {
250-
// find first important prop that actually exists to fill plot
252+
// Open on the total energy when there is one; else the first series.
253+
if (getCalculation()->getProperty("TEVEC") && p_keyToId.count("TEVEC")) {
254+
p_currentProp = "TEVEC";
255+
return;
256+
}
251257
map<string,wxWindowID>::iterator string_to_id_it;
252258
for (string_to_id_it = p_keyToId.begin();
253259
string_to_id_it != p_keyToId.end();
@@ -267,7 +273,8 @@ void GeomTracePropertyPanel::saveSettings()
267273
config->Write("GeomTrace/Recompute", p_recompute);
268274
config->Write("GeomTrace/Fold", p_fold);
269275
config->Write("GeomTrace/Delay", p_delay);
270-
config->Write("GeomTrace/Prop", wxString(p_currentProp));
276+
if (p_propChosen)
277+
config->Write("GeomTrace/Prop", wxString(p_currentProp));
271278
}
272279

273280

@@ -341,6 +348,7 @@ void GeomTracePropertyPanel::OnToolClick(wxCommandEvent& event)
341348
p_fold = event.IsChecked();
342349
} else {
343350
p_currentProp = p_idToKey[event.GetId()];
351+
p_propChosen = true;
344352
fillPlot();
345353
}
346354
saveSettings();

‎src/apps/builder/GeomTracePropertyPanel.H‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class GeomTracePropertyPanel : public VizPropertyPanel,
7777
bool p_fold;
7878

7979
string p_currentProp;
80+
bool p_propChosen; // the user picked the series (so it is remembered)
8081

8182
vector<string> p_importantProps;
8283
map<string,wxWindowID> p_keyToId;

‎src/apps/builder/MoCoeffs.C‎

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -271,9 +271,6 @@ void MoCoeffs::showCoeffs(ICalculation *expt, int moNum,
271271
#endif
272272

273273
size_t numFuncTypes; // length of funcTypes array ==> # of funs in a GBS
274-
size_t idxAtom_plus1 = idxAtom + 1;
275-
sprintf(buf,"%zu",idxAtom_plus1);
276-
p_grid->SetCellValue(idxAtom,0,buf);
277274

278275
sprintf(buf,"%s%zu",atomID.c_str(),idxAtom+1);
279276
p_grid->SetCellValue(idxCoef,1,buf);
@@ -367,7 +364,7 @@ void MoCoeffs::showCoeffs(ICalculation *expt, int moNum,
367364
for (int kdx=0; kdx<length_g_shell; kdx++) {
368365

369366
// Atomic Orbital
370-
sprintf(buf,"g%zu ",fCount);
367+
sprintf(buf,"g%zu ",gCount);
371368
p_grid->SetCellValue(idxCoef, 2, buf);
372369

373370
// Coeff
@@ -383,7 +380,7 @@ void MoCoeffs::showCoeffs(ICalculation *expt, int moNum,
383380
for (int kdx=0; kdx<length_h_shell; kdx++) {
384381

385382
// Atomic Orbital
386-
sprintf(buf,"h%zu ",fCount);
383+
sprintf(buf,"h%zu ",hCount);
387384
p_grid->SetCellValue(idxCoef, 2, buf);
388385

389386
// Coeff
@@ -399,7 +396,7 @@ void MoCoeffs::showCoeffs(ICalculation *expt, int moNum,
399396
for (int kdx=0; kdx<length_i_shell; kdx++) {
400397

401398
// Atomic Orbital
402-
sprintf(buf,"i%zu ",fCount);
399+
sprintf(buf,"i%zu ",iCount);
403400
p_grid->SetCellValue(idxCoef, 2, buf);
404401

405402
// Coeff

‎src/apps/organizer/CalcMgr.C‎

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,21 @@ void CalcMgr::runTestCommand(const string& line)
625625
}
626626
}
627627
}
628+
} else if (command == "toolsmenu") {
629+
// "toolsmenu <url>": the labels of the Tools menu for <url>.
630+
WxResourceTreeItemData *node = findNode(EcceURL(calcName), false, false);
631+
if (!node) {
632+
outcome = "not in the tree";
633+
} else {
634+
wxMenu menu;
635+
getToolsMenu(menu, node);
636+
outcome = "ok";
637+
for (size_t i = 0; i < menu.GetMenuItemCount(); i++) {
638+
wxMenuItem *it = menu.FindItemByPosition(i);
639+
if (!it->IsSeparator())
640+
outcome += " item=" + string(it->GetItemLabel().ToUTF8());
641+
}
642+
}
628643
} else if (command == "contextmenu") {
629644
// "contextmenu <url>": the tree's item-menu event for <url>, as a
630645
// right click sends it, then the labels of the menu's New submenu.
@@ -3359,8 +3374,17 @@ void CalcMgr::getToolsMenu(wxMenu & menu, WxResourceTreeItemData * itemData)
33593374

33603375
vector<ResourceTool *>::iterator toolItor = toolVec.begin();
33613376
for (;toolItor != toolVec.end(); toolItor++) {
3377+
// The MD editors are registered once, as NWChem's, and also edit the
3378+
// GROMACS tasks: name the code of the task (as the summary buttons do).
3379+
wxString label = wxString::FromUTF8((*toolItor)->getMenuItem().c_str());
3380+
if (label.StartsWith("NWChem MD ") && itemData && itemData->getResource()) {
3381+
string app = itemData->getResource()->getProp(
3382+
VDoc::getEcceNamespace() + ":application");
3383+
if (!app.empty() && app.compare(0, 6, "NWChem") != 0)
3384+
label = wxString::FromUTF8(app.c_str()) + label.Mid(6);
3385+
}
33623386
wxMenuItem *item = new wxMenuItem(&menu, (*toolItor)->getId(),
3363-
(*toolItor)->getMenuItem(), _T(""), wxITEM_NORMAL);
3387+
label, _T(""), wxITEM_NORMAL);
33643388
item->SetBitmap(wxBitmap(ewxBitmap((*toolItor)->getIcon())
33653389
.ConvertToImage().Scale(16,16)));
33663390
menu.Append(item);

‎src/wxgui/wxdialogs/ewxMessageDialog.C‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <cstring>
12
#include "wx/wxprec.h"
23

34
#ifndef WX_PRECOMP
@@ -122,6 +123,7 @@ void ewxMessageDialog::OnButtonClick( wxCommandEvent& event )
122123

123124
// ECCE_TEST_DIALOG_CLOSE=<seconds>: log the dialog to stderr, then dismiss it
124125
// after that long, so a headless run can see it and still end cleanly.
126+
// ECCE_TEST_DIALOG_ANSWER=yes|ok|cancel picks the button pressed (default ok).
125127
int ewxMessageDialog::ShowModal()
126128
{
127129
const char * secs = getenv("ECCE_TEST_DIALOG_CLOSE");
@@ -132,7 +134,11 @@ int ewxMessageDialog::ShowModal()
132134
(const char *)p_label->GetLabel().mb_str());
133135
fflush(stderr);
134136
wxTimer timer(this);
135-
Bind(wxEVT_TIMER, [this](wxTimerEvent&) { EndModal(wxID_OK); });
137+
const char * ans = getenv("ECCE_TEST_DIALOG_ANSWER");
138+
int id = wxID_OK;
139+
if (ans && !strcmp(ans, "yes")) id = wxID_YES;
140+
else if (ans && !strcmp(ans, "cancel")) id = wxID_CANCEL;
141+
Bind(wxEVT_TIMER, [this, id](wxTimerEvent&) { EndModal(id); });
136142
timer.StartOnce(atoi(secs) * 1000);
137143
return ewxDialog::ShowModal();
138144
}

‎tests/apps/geomtrace_stress.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def script(calcs):
124124
"""The scene script: calcs is [(url, steps)], the first one opened."""
125125
(a, na), (b, nb), (c, nc) = calcs
126126
return "\n".join([
127-
"gtfocus", "gtsweep", "gtexpect %d" % na,
127+
"gtfocus", "gttitle Total Energy", "gtsweep", "gtexpect %d" % na,
128128
# clicking a point of the plot shows that step's geometry
129129
"gtpick 0", "gtpick mid", "gtpick last",
130130
"gtplay 300 1", "gtsweep", "gtstop",

‎tests/launch/md_editors_test.py‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def summary(s, display, genv, wrappers, urls, png=None):
4646
stdout=open(logpath, "w"), stderr=subprocess.STDOUT,
4747
start_new_session=True)
4848
answers = {}
49+
menus = {}
4950
try:
5051
deadline = time.time() + 120
5152
while time.time() < deadline and not any(
@@ -55,19 +56,22 @@ def summary(s, display, genv, wrappers, urls, png=None):
5556
with open(cmd, "a") as h:
5657
for i, u in enumerate(urls):
5758
h.write("summary %s\n" % u)
59+
h.write("toolsmenu %s\n" % u)
5860
if png:
5961
h.write("snap %s\n" % os.path.join(png, "summary-%d.png" % i))
6062
deadline = time.time() + 90
6163
while time.time() < deadline and len(answers) < len(urls):
64+
log = open(logpath, errors="replace").read()
6265
for u in urls:
63-
m = re.search(r"ECCE_TEST_ORGANIZER: summary %s: (.*)" % re.escape(u),
64-
open(logpath, errors="replace").read())
65-
if m:
66+
m = re.search(r"ECCE_TEST_ORGANIZER: summary %s: (.*)" % re.escape(u), log)
67+
t = re.search(r"ECCE_TEST_ORGANIZER: toolsmenu %s: (.*)" % re.escape(u), log)
68+
if m and t:
6669
answers[u] = m.group(1)
70+
menus[u] = t.group(1)
6771
time.sleep(0.5)
6872
finally:
6973
stop(org)
70-
return answers
74+
return answers, menus
7175

7276

7377
def main():
@@ -135,12 +139,16 @@ def main():
135139
finally:
136140
ed.close()
137141

138-
answers = summary(s, display, genv, wrappers, list(opts.values()), args.png)
142+
answers, menus = summary(s, display, genv, wrappers, list(opts.values()), args.png)
139143
for code, url in opts.items():
140144
out = answers.get(url, "")
141145
tools = re.findall(r"tool=(.*?)(?= tool=|$)", out)
142146
check(("%s MD Optimize" % code) in tools,
143147
"the %s Optimize summary names its editor: %s" % (code, tools))
148+
items = re.findall(r"item=(.*?)(?= item=|$)", menus.get(url, ""))
149+
check(any(i.startswith("%s MD Optimize" % code) for i in items) and
150+
(code == "NWChem" or not any(i.startswith("NWChem MD") for i in items)),
151+
"the %s Optimize Tools menu names its editor: %s" % (code, items))
144152
check(tools and not any(t.endswith(":clipped") for t in tools),
145153
"no %s summary button clips its label" % code)
146154
finally:

‎tests/machregister/launcher_test.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,12 @@ def mpi_check(disp, build, tmp):
7474
g.write(os.path.join(fake, "mpirun"), "#!/bin/sh\n")
7575
os.chmod(os.path.join(fake, "mpirun"), 0o755)
7676

77-
def run(path, script):
77+
def run(path, script, answer=None):
7878
g.write(os.path.join(e.root, "lscript"), script)
7979
env = e.env(disp)
8080
env.pop("ECCE_MACHREG_SCRIPT", None)
81+
if answer:
82+
env["ECCE_TEST_DIALOG_ANSWER"] = answer
8183
env.update({"ECCE_REALUSER": "eccetest", "PATH": path,
8284
"ECCE_TEST_DIALOG_CLOSE": "1",
8385
"ECCE_LAUNCHER_SCRIPT": os.path.join(e.root, "lscript")})
@@ -107,6 +109,16 @@ def run(path, script):
107109
"a missing mpirun for ORCA on 4 cores is named")
108110
g.check("mpicheck NWChem: go" in out,
109111
"after Run on 1 core nothing more is asked")
112+
p = run(farm, """
113+
machine localhost
114+
procs 4
115+
mpicheck ORCA
116+
expect wsprocs 4
117+
quit
118+
""", answer="yes")
119+
clean(p, "the MPI check answered Launch anyway")
120+
g.check("ECCE_TEST_DIALOG:" in p.stdout and "mpicheck ORCA: go" in p.stdout,
121+
"Launch anyway goes on with the cores as set (4)")
110122
p = run(fake + os.pathsep + farm, """
111123
machine localhost
112124
procs 4

0 commit comments

Comments
 (0)