source: src/bin/mpqc/mpqc.cc@ 737c47

Last change on this file since 737c47 was 737c47, checked in by Frederik Heber <heber@…>, 13 years ago

MPQC now uses SamplingGrid as information container for sampled density.

  • Property mode set to 100644
File size: 54.3 KB
Line 
1//
2// mpqc.cc
3//
4// Copyright (C) 1996 Limit Point Systems, Inc.
5//
6// Author: Edward Seidl <seidl@janed.com>
7// Maintainer: LPS
8//
9// This file is part of MPQC.
10//
11// MPQC is free software; you can redistribute it and/or modify
12// it under the terms of the GNU General Public License as published by
13// the Free Software Foundation; either version 2, or (at your option)
14// any later version.
15//
16// MPQC is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with the MPQC; see the file COPYING. If not, write to
23// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24//
25// The U.S. Government is granted a limited license as per AL 91-7.
26//
27
28// This is needed to make GNU extensions available, such as
29// feenableexcept and fedisableexcept.
30#ifndef _GNU_SOURCE
31# define _GNU_SOURCE
32#endif
33
34#ifdef HAVE_CONFIG_H
35#include <scconfig.h>
36#endif
37
38#ifdef HAVE_TIME_H
39#include <time.h>
40#endif
41
42#include <scdirlist.h>
43
44#include <new>
45#include <stdexcept>
46#include <string.h>
47#include <unistd.h>
48#include <sys/stat.h>
49#include <fstream>
50
51#include <boost/bind.hpp>
52#include <boost/function.hpp>
53
54#include <scconfig.h>
55#ifdef HAVE_SSTREAM
56# include <sstream>
57#else
58# include <strstream.h>
59#endif
60
61#ifdef HAVE_SYS_RESOURCE_H
62# include <sys/resource.h>
63#endif
64#ifdef HAVE_SYS_TIME_H
65# include <sys/time.h>
66#endif
67
68#include <util/options/GetLongOpt.h>
69#include <util/class/scexception.h>
70#include <util/misc/newstring.h>
71#include <util/keyval/keyval.h>
72#include <util/state/state_bin.h>
73#include <util/group/message.h>
74#include <util/group/memory.h>
75#include <util/group/mstate.h>
76#include <util/group/thread.h>
77#include <util/group/pregtime.h>
78#include <util/misc/bug.h>
79#include <util/misc/formio.h>
80#include <util/misc/exenv.h>
81#ifdef HAVE_CHEMISTRY_CCA
82 #include <util/misc/ccaenv.h>
83#endif
84#include <util/render/render.h>
85
86#include <math/optimize/opt.h>
87
88#include <chemistry/molecule/coor.h>
89#include <chemistry/molecule/energy.h>
90#include <chemistry/molecule/molfreq.h>
91#include <chemistry/molecule/fdhess.h>
92#include <chemistry/molecule/formula.h>
93#include <chemistry/qc/wfn/wfn.h>
94
95// Force linkages:
96#include <util/group/linkage.h>
97#include <chemistry/qc/wfn/linkage.h>
98#include <chemistry/qc/scf/linkage.h>
99#include <chemistry/qc/dft/linkage.h>
100#include <chemistry/qc/mbpt/linkage.h>
101#ifdef HAVE_SC_SRC_LIB_CHEMISTRY_QC_MBPTR12
102# include <chemistry/qc/mbptr12/linkage.h>
103#endif
104#ifdef HAVE_SC_SRC_LIB_CHEMISTRY_QC_CINTS
105# include <chemistry/qc/cints/linkage.h>
106#endif
107//#include <chemistry/qc/psi/linkage.h>
108#include <util/state/linkage.h>
109#ifdef HAVE_SC_SRC_LIB_CHEMISTRY_QC_CC
110# include <chemistry/qc/cc/linkage.h>
111#endif
112#ifdef HAVE_SC_SRC_LIB_CHEMISTRY_QC_PSI
113# include <chemistry/qc/psi/linkage.h>
114#endif
115#ifdef HAVE_SC_SRC_LIB_CHEMISTRY_QC_INTCCA
116# include <chemistry/qc/intcca/linkage.h>
117#endif
118
119#ifdef HAVE_MPI
120#define MPICH_SKIP_MPICXX
121#include <mpi.h>
122#include <util/group/messmpi.h>
123#endif
124
125#ifdef HAVE_JOBMARKET
126// include headers that implement a archive in simple text format
127// otherwise BOOST_CLASS_EXPORT_IMPLEMENT has no effect
128#include <boost/archive/text_oarchive.hpp>
129#include <boost/archive/text_iarchive.hpp>
130#include <boost/bind.hpp>
131#include <boost/tokenizer.hpp>
132
133#include "JobMarket/Results/FragmentResult.hpp"
134#include "JobMarket/poolworker_main.hpp"
135#include "MPQCJob.h"
136
137#include "chemistry/qc/scf/scfops.h"
138
139#ifdef HAVE_MPQCDATA
140#include "Jobs/MPQCData.hpp"
141#endif
142
143#include <algorithm>
144#include <stdlib.h>
145#endif
146
147using namespace std;
148using namespace sc;
149
150#include "mpqcin.h"
151
152//////////////////////////////////////////////////////////////////////////
153
154const KeyValValueboolean truevalue(1), falsevalue(0);
155const char *devnull = "/dev/null";
156
157
158static void
159trash_stack_b(int &i, char *&ichar)
160{
161 char stack;
162 ichar = &stack;
163 ichar -= 10;
164 for (i=0; i<1000; i++) {
165 *ichar-- = 0xfe;
166 }
167}
168
169static void
170trash_stack()
171{
172 int i;
173 char *ichar;
174 trash_stack_b(i,ichar);
175}
176
177static void
178clean_up(void)
179{
180 MemoryGrp::set_default_memorygrp(0);
181 ThreadGrp::set_default_threadgrp(0);
182 SCMatrixKit::set_default_matrixkit(0);
183 Integral::set_default_integral(0);
184 RegionTimer::set_default_regiontimer(0);
185}
186
187static void
188final_clean_up(void)
189{
190 MessageGrp::set_default_messagegrp(0);
191}
192
193#include <signal.h>
194
195#ifdef HAVE_FENV_H
196# include <fenv.h>
197#endif
198
199static void
200print_unseen(const Ref<ParsedKeyVal> &parsedkv,
201 const char *input)
202{
203 if (parsedkv->have_unseen()) {
204 ExEnv::out0() << endl;
205 ExEnv::out0() << indent
206 << "The following keywords in \"" << input << "\" were ignored:"
207 << endl;
208 ExEnv::out0() << incindent;
209 parsedkv->print_unseen(ExEnv::out0());
210 ExEnv::out0() << decindent;
211 }
212}
213
214double EvaluateDensity(
215 SCVector3 &r,
216 Ref<Integral> &intgrl,
217 GaussianBasisSet::ValueData &vdat,
218 Ref<Wavefunction> &wfn);
219
220/** Places all known options into \a options and parses them from argc,argv.
221 *
222 * \param options options structure
223 * \param argc argument count
224 * \param argv argument array
225 * \return return value by GetLongOpt::parse() function
226 */
227int ParseOptions(
228 GetLongOpt &options,
229 int argc,
230 char **argv)
231{
232 options.usage("[options] [filename]");
233 options.enroll("f", GetLongOpt::MandatoryValue,
234 "the name of an object format input file", 0);
235 options.enroll("o", GetLongOpt::MandatoryValue,
236 "the name of the output file", 0);
237 options.enroll("n", GetLongOpt::MandatoryValue,
238 "listen for incoming object format input files", 0);
239 options.enroll("messagegrp", GetLongOpt::MandatoryValue,
240 "which message group to use", 0);
241 options.enroll("threadgrp", GetLongOpt::MandatoryValue,
242 "which thread group to use", 0);
243 options.enroll("memorygrp", GetLongOpt::MandatoryValue,
244 "which memory group to use", 0);
245 options.enroll("integral", GetLongOpt::MandatoryValue,
246 "which integral evaluator to use", 0);
247 options.enroll("l", GetLongOpt::MandatoryValue, "basis set limit", "0");
248 options.enroll("W", GetLongOpt::MandatoryValue,
249 "set the working directory", ".");
250 options.enroll("c", GetLongOpt::NoValue, "check input then exit", 0);
251 options.enroll("v", GetLongOpt::NoValue, "print the version number", 0);
252 options.enroll("w", GetLongOpt::NoValue, "print the warranty", 0);
253 options.enroll("L", GetLongOpt::NoValue, "print the license", 0);
254 options.enroll("k", GetLongOpt::NoValue, "print key/value assignments", 0);
255 options.enroll("i", GetLongOpt::NoValue, "convert simple to OO input", 0);
256 options.enroll("d", GetLongOpt::NoValue, "debug", 0);
257 options.enroll("h", GetLongOpt::NoValue, "print this message", 0);
258 options.enroll("cca-path", GetLongOpt::OptionalValue,
259 "cca component path", "");
260 options.enroll("cca-load", GetLongOpt::OptionalValue,
261 "cca components to load", "");
262
263 int optind = options.parse(argc, argv);
264
265 return optind;
266}
267
268/** Checks for each known option and acts accordingly.
269 *
270 * \param options option structure
271 * \param *output name of outputfile on return
272 * \param *outstream open output stream on return
273 */
274void ComputeOptions(
275 GetLongOpt &options,
276 const char *&output,
277 ostream *&outstream)
278{
279 output = options.retrieve("o");
280 outstream = 0;
281 if (output != 0) {
282 outstream = new ofstream(output);
283 ExEnv::set_out(outstream);
284 }
285
286 if (options.retrieve("h")) {
287 ExEnv::out0()
288 << indent << "MPQC version " << SC_VERSION << endl
289 << indent << "compiled for " << TARGET_ARCH << endl
290 << SCFormIO::copyright << endl;
291 options.usage(ExEnv::out0());
292 exit(0);
293 }
294
295 if (options.retrieve("v")) {
296 ExEnv::out0()
297 << indent << "MPQC version " << SC_VERSION << endl
298 << indent << "compiled for " << TARGET_ARCH << endl
299 << SCFormIO::copyright;
300 exit(0);
301 }
302
303 if (options.retrieve("w")) {
304 ExEnv::out0()
305 << indent << "MPQC version " << SC_VERSION << endl
306 << indent << "compiled for " << TARGET_ARCH << endl
307 << SCFormIO::copyright << endl
308 << SCFormIO::warranty;
309 exit(0);
310 }
311
312 if (options.retrieve("L")) {
313 ExEnv::out0()
314 << indent << "MPQC version " << SC_VERSION << endl
315 << indent << "compiled for " << TARGET_ARCH << endl
316 << SCFormIO::copyright << endl
317 << SCFormIO::license;
318 exit(0);
319 }
320
321 if (options.retrieve("d"))
322 SCFormIO::set_debug(1);
323
324 // set the working dir
325 if (strcmp(options.retrieve("W"),"."))
326 int retval = chdir(options.retrieve("W"));
327
328 // check that n and f/o are not given at the same time
329 if ((options.retrieve("n")) && ((options.retrieve("f")) || (options.retrieve("o")))) {
330 throw invalid_argument("-n must not be given with -f or -o");
331 }
332}
333
334/** Temporary structure for storing information from command-line
335 *
336 * This structure has been introduced to gather the various calls to GetLongOpts
337 * at one (initial) place and to abstract it from the source of command-lines.
338 * This temporary object can be set by other means, too. I.e. we become
339 * independent of usage in command-line programs.
340 */
341struct OptionValues {
342 const char *keyvalue; // option "k"
343 const char *debug; // option ""
344 int limit; // option "l"
345 const char *check; // option "c"
346 const char *simple_input; // option "i"
347 string executablename;
348
349#ifdef HAVE_CHEMISTRY_CCA
350 string cca_load; // option "cca-path"
351 string cc_path; // option "cca-load"
352#endif
353};
354
355/** Parse remainder options not treated by ComputeOptions() into temporary storage.
356 *
357 * \param options option structure to obtain values from
358 * \param values remaining option values which are processed later and now
359 * stored in a temporary structure
360 */
361void parseRemainderOptions(
362 GetLongOpt &options,
363 struct OptionValues &values,
364 int argc,
365 char **argv)
366{
367 values.keyvalue = options.retrieve("k");
368 values.debug = options.retrieve("d");
369 values.limit = atoi(options.retrieve("l"));
370 values.check = options.retrieve("c");
371 values.simple_input = options.retrieve("i");
372 values.executablename = argv[0];
373
374#ifdef HAVE_CHEMISTRY_CCA
375 values.cca_load = options.retrieve("cca-load");
376 values.cca_path = options.retrieve("cca-path");
377#endif
378}
379
380/** Sets object and generic input file names.
381 *
382 * \param object_input filename of object-oriented input
383 * \param generic_input filename of generic input
384 * \param options (command-line)option structure
385 * \param argc argument count
386 * \param argv argument array
387 */
388void getInputFileNames(
389 const char *&object_input,
390 const char *&generic_input,
391 GetLongOpt &options,
392 int optind,
393 int argc,
394 char **argv)
395{
396 // initialize keyval input
397 object_input = options.retrieve("f");
398 generic_input = 0;
399 if (argc - optind == 0) {
400 generic_input = 0;
401 }
402 else if (argc - optind == 1) {
403 generic_input = argv[optind];
404 }
405 else if (!options.retrieve("n")) {
406 options.usage();
407 throw invalid_argument("extra arguments given");
408 }
409
410 if (object_input == 0 && generic_input == 0) {
411 generic_input = "mpqc.in";
412 }
413 else if (object_input && !options.retrieve("n") && generic_input) {
414 options.usage();
415 throw invalid_argument("only one of -f and a file argument can be given");
416 }
417}
418
419/** Gets the MPI Message group.
420 *
421 * \param grp reference to obtained group
422 * \param argc argument count
423 * \param argv argument array
424 */
425void getMessageGroup(
426 Ref<MessageGrp> &grp,
427 int argc,
428 char **argv)
429{
430#if defined(HAVE_MPI) && defined(ALWAYS_USE_MPI)
431 grp = new MPIMessageGrp(&argc, &argv);
432#endif
433 if (grp.null()) grp = MessageGrp::initial_messagegrp(argc, argv);
434 if (grp.nonnull())
435 MessageGrp::set_default_messagegrp(grp);
436 else
437 grp = MessageGrp::get_default_messagegrp();
438}
439
440/** Sets the base name of output files.
441 *
442 * \param input input file name
443 * \param output output file name
444 */
445void setOutputBaseName(const char *input, const char *output)
446{
447 const char *basename_source;
448 if (output) basename_source = output;
449 else basename_source = input;
450 int nfilebase = (int) (::strrchr(basename_source, '.') - basename_source);
451 char *basename = new char[nfilebase + 1];
452 strncpy(basename, basename_source, nfilebase);
453 basename[nfilebase] = '\0';
454 SCFormIO::set_default_basename(basename);
455 delete[] basename;
456}
457
458/** Prints current key values.
459 *
460 * \param keyval key value structure
461 * \param opt optimization structure
462 * \param molname name of molecule
463 * \param restartfile name of restartfile
464 */
465void printOptions(
466 Ref<KeyVal> &keyval,
467 Ref<Optimize> &opt,
468 const char *molname,
469 const char *restartfile)
470{
471 int restart = keyval->booleanvalue("restart",truevalue);
472
473 int checkpoint = keyval->booleanvalue("checkpoint",truevalue);
474
475 int savestate = keyval->booleanvalue("savestate",truevalue);
476
477 int do_energy = keyval->booleanvalue("do_energy",truevalue);
478
479 int do_grad = keyval->booleanvalue("do_gradient",falsevalue);
480
481 int do_opt = keyval->booleanvalue("optimize",truevalue);
482
483 int do_pdb = keyval->booleanvalue("write_pdb",falsevalue);
484
485 int print_mole = keyval->booleanvalue("print_mole",truevalue);
486
487 int print_timings = keyval->booleanvalue("print_timings",truevalue);
488
489 // sanity checks for the benefit of reasonable looking output
490 if (opt.null()) do_opt=0;
491
492 ExEnv::out0() << endl << indent
493 << "MPQC options:" << endl << incindent
494 << indent << "matrixkit = <"
495 << SCMatrixKit::default_matrixkit()->class_name() << ">" << endl
496 << indent << "filename = " << molname << endl
497 << indent << "restart_file = " << restartfile << endl
498 << indent << "restart = " << (restart ? "yes" : "no") << endl
499 << indent << "checkpoint = " << (checkpoint ? "yes" : "no") << endl
500 << indent << "savestate = " << (savestate ? "yes" : "no") << endl
501 << indent << "do_energy = " << (do_energy ? "yes" : "no") << endl
502 << indent << "do_gradient = " << (do_grad ? "yes" : "no") << endl
503 << indent << "optimize = " << (do_opt ? "yes" : "no") << endl
504 << indent << "write_pdb = " << (do_pdb ? "yes" : "no") << endl
505 << indent << "print_mole = " << (print_mole ? "yes" : "no") << endl
506 << indent << "print_timings = " << (print_timings ? "yes" : "no")
507 << endl << decindent;
508
509}
510
511/** Saves the current state to checkpoint file.
512 *
513 * \param keyval key value structure
514 * \param opt optimization structure
515 * \param grp message group
516 * \param mole MolecularEnergy object
517 * \param molname name of molecule
518 * \param ckptfile name of check point file
519 */
520void saveState(
521 char *wfn_file,
522 int savestate,
523 Ref<Optimize> &opt,
524 Ref<MessageGrp> &grp,
525 Ref<MolecularEnergy> &mole,
526 char *&molname,
527 char *&ckptfile)
528{
529 // function stuff
530 if (savestate) {
531 if (opt.nonnull()) {
532 if (grp->me() == 0) {
533 ckptfile = new char[strlen(molname)+6];
534 sprintf(ckptfile,"%s.ckpt",molname);
535 }
536 else {
537 ckptfile = new char[strlen(devnull)+1];
538 strcpy(ckptfile, devnull);
539 }
540
541 StateOutBin so(ckptfile);
542 SavableState::save_state(opt.pointer(),so);
543 so.close();
544
545 delete[] ckptfile;
546 }
547
548 if (mole.nonnull()) {
549 if (grp->me() == 0) {
550 if (wfn_file == 0) {
551 wfn_file = new char[strlen(molname)+6];
552 sprintf(wfn_file,"%s.wfn",molname);
553 }
554 }
555 else {
556 delete[] wfn_file;
557 wfn_file = new char[strlen(devnull)+1];
558 strcpy(wfn_file, devnull);
559 }
560
561 StateOutBin so(wfn_file);
562 SavableState::save_state(mole.pointer(),so);
563 so.close();
564
565 }
566 }
567 delete[] wfn_file;
568}
569
570/** Sets up indentation and output modes.
571 *
572 * \param grp message group
573 */
574void setupSCFormIO(
575 Ref<MessageGrp> &grp
576 )
577{
578 SCFormIO::setindent(ExEnv::outn(), 2);
579 SCFormIO::setindent(ExEnv::errn(), 2);
580 SCFormIO::setindent(cout, 2);
581 SCFormIO::setindent(cerr, 2);
582
583 SCFormIO::set_printnode(0);
584 if (grp->n() > 1)
585 SCFormIO::init_mp(grp->me());
586}
587
588/** Initialises the timer.
589 *
590 * \param grp message group
591 * \param keyval key value structure
592 * \param tim timing structure
593 */
594void initTimings(
595 Ref<MessageGrp> &grp,
596 Ref<KeyVal> &keyval,
597 Ref<RegionTimer> &tim
598 )
599{
600 grp->sync(); // make sure nodes are sync'ed before starting timings
601 if (keyval->exists("timer")) tim << keyval->describedclassvalue("timer");
602 else tim = new ParallelRegionTimer(grp,"mpqc",1,1);
603 RegionTimer::set_default_regiontimer(tim);
604
605 if (tim.nonnull()) tim->enter("input");
606}
607
608/** Prints the header of the output.
609 *
610 * \param tim timing structure
611 */
612void makeAnnouncement(
613 Ref<RegionTimer> &tim
614 )
615{
616 const char title1[] = "MPQC: Massively Parallel Quantum Chemistry";
617 int ntitle1 = sizeof(title1);
618 const char title2[] = "Version " SC_VERSION;
619 int ntitle2 = sizeof(title2);
620 ExEnv::out0() << endl;
621 ExEnv::out0() << indent;
622 for (int i=0; i<(80-ntitle1)/2; i++) ExEnv::out0() << ' ';
623 ExEnv::out0() << title1 << endl;
624 ExEnv::out0() << indent;
625 for (int i=0; i<(80-ntitle2)/2; i++) ExEnv::out0() << ' ';
626 ExEnv::out0() << title2 << endl << endl;
627
628 const char *tstr = 0;
629#if defined(HAVE_TIME) && defined(HAVE_CTIME)
630 time_t t;
631 time(&t);
632 tstr = ctime(&t);
633#endif
634 if (!tstr) {
635 tstr = "UNKNOWN";
636 }
637
638 ExEnv::out0()
639 << indent << scprintf("Machine: %s", TARGET_ARCH) << endl
640 << indent << scprintf("User: %s@%s",
641 ExEnv::username(), ExEnv::hostname()) << endl
642 << indent << scprintf("Start Time: %s", tstr) << endl;
643}
644
645/** Parse the input configuration from char array into keyvalue container.
646 *
647 * \param parsedkv key value container to foll
648 * \param values temporary options value structure
649 * \param in_char_array char array with input file
650 * \param use_simple_input whether the format in \a in_char_array is simple (1)
651 * or object-oriented (0)
652 */
653void parseIntoKeyValue(
654 Ref<ParsedKeyVal> &parsedkv,
655 struct OptionValues &values,
656 char *&in_char_array,
657 int use_simple_input)
658{
659 if (use_simple_input) {
660 MPQCIn mpqcin;
661 char *simple_input_text = mpqcin.parse_string(in_char_array);
662 if (values.simple_input) {
663 ExEnv::out0() << "Generated object-oriented input file:" << endl
664 << simple_input_text
665 << endl;
666 exit(0);
667 }
668 parsedkv = new ParsedKeyVal();
669 parsedkv->parse_string(simple_input_text);
670 delete[] simple_input_text;
671 } else {
672 parsedkv = new ParsedKeyVal();
673 parsedkv->parse_string(in_char_array);
674 }
675}
676
677/** Parse the input file into the key value container.
678 *
679 * \param grp message group
680 * \param parsedkev keyvalue container on return
681 * \param values (command-line) options structure
682 * \param input input file name
683 * \param generic_input filename of generic input
684 * \param in_char_array char array with input file's contents on return
685 * \param use_simple_input whether the file contents is in simple format (1)
686 * or object-oriented (0)
687 */
688void parseInputfile(
689 Ref<MessageGrp> &grp,
690 Ref<ParsedKeyVal> &parsedkv,
691 struct OptionValues &values,
692 const char *&input,
693 const char *&generic_input,
694 char *&in_char_array,
695 int &use_simple_input
696 )
697{
698 // read the input file on only node 0
699 if (grp->me() == 0) {
700 ifstream is(input);
701#ifdef HAVE_SSTREAM
702 ostringstream ostrs;
703 is >> ostrs.rdbuf();
704 int n = 1 + strlen(ostrs.str().c_str());
705 in_char_array = strcpy(new char[n],ostrs.str().c_str());
706#else
707 ostrstream ostrs;
708 is >> ostrs.rdbuf();
709 ostrs << ends;
710 in_char_array = ostrs.str();
711 int n = ostrs.pcount();
712#endif
713 grp->bcast(n);
714 grp->bcast(in_char_array, n);
715 }
716 else {
717 int n;
718 grp->bcast(n);
719 in_char_array = new char[n];
720 grp->bcast(in_char_array, n);
721 }
722
723 if (generic_input && grp->me() == 0) {
724 MPQCIn mpqcin;
725 use_simple_input = mpqcin.check_string(in_char_array);
726 }
727 else {
728 use_simple_input = 0;
729 }
730 grp->bcast(use_simple_input);
731}
732
733/** Get the thread group.
734 *
735 * \param keyval keyvalue container
736 * \param thread thread group on return
737 * \param argc argument count
738 * \param argv argument array
739 */
740void getThreadGroup(
741 Ref<KeyVal> &keyval,
742 Ref<ThreadGrp> &thread,
743 int argc,
744 char **argv)
745{
746 //first try the commandline and environment
747 thread = ThreadGrp::initial_threadgrp(argc, argv);
748
749 // if we still don't have a group, try reading the thread group
750 // from the input
751 if (thread.null()) {
752 thread << keyval->describedclassvalue("thread");
753 }
754
755 if (thread.nonnull())
756 ThreadGrp::set_default_threadgrp(thread);
757 else
758 thread = ThreadGrp::get_default_threadgrp();
759}
760
761/** Get the memory group.
762 *
763 * \param keyval keyvalue container
764 * \param memory memory group on return
765 * \param argc argument count
766 * \param argv argument array
767 */
768void getMemoryGroup(
769 Ref<KeyVal> &keyval,
770 Ref<MemoryGrp> &memory,
771 int argc,
772 char **argv)
773{
774 // first try the commandline and environment
775 memory = MemoryGrp::initial_memorygrp(argc, argv);
776
777 // if we still don't have a group, try reading the memory group
778 // from the input
779 if (memory.null()) {
780 memory << keyval->describedclassvalue("memory");
781 }
782
783 if (memory.nonnull())
784 MemoryGrp::set_default_memorygrp(memory);
785 else
786 memory = MemoryGrp::get_default_memorygrp();
787}
788
789/** Prepares CCA component if available.
790 *
791 * \param keyval keyvalue container
792 * \param values parsed (command-line) options
793 */
794void prepareCCA(
795 Ref<KeyVal> &keyval,
796 struct OptionValues &values
797 )
798{
799#ifdef HAVE_CHEMISTRY_CCA
800 // initialize cca framework
801 KeyValValuestring emptystring("");
802 bool do_cca = keyval->booleanvalue("do_cca",falsevalue);
803
804 string cca_path(values.cca_path);
805 string cca_load(values.cca_load);
806 if(cca_path.size()==0)
807 cca_path = keyval->stringvalue("cca_path",emptystring);
808 if(cca_load.size()==0)
809 cca_load = keyval->stringvalue("cca_load",emptystring);
810
811 if( !do_cca && (cca_load.size() > 0 || cca_path.size() > 0) )
812 do_cca = true;
813
814 if(cca_path.size()==0) {
815 #ifdef CCA_PATH
816 cca_path = CCA_PATH;
817 #endif
818 }
819 if(cca_load.size()==0) {
820 cca_load += "MPQC.IntegralEvaluatorFactory";
821 }
822
823 if( cca_load.size() > 0 && cca_path.size() > 0 && do_cca ) {
824 string cca_args = "--path " + cca_path + " --load " + cca_load;
825 ExEnv::out0() << endl << indent << "Initializing CCA framework with args: "
826 << endl << indent << cca_args << endl;
827 CCAEnv::init( cca_args );
828 }
829#endif
830}
831
832/** Setup debugger.
833 *
834 * \param keyval keyvalue container
835 * \param grp message group
836 * \param debugger debugger structure
837 * \param options parsed command line options
838 */
839void setupDebugger(
840 Ref<KeyVal> &keyval,
841 Ref<MessageGrp> &grp,
842 Ref<Debugger> &debugger,
843 struct OptionValues &values)
844{
845 debugger << keyval->describedclassvalue("debug");
846 if (debugger.nonnull()) {
847 Debugger::set_default_debugger(debugger);
848 debugger->set_exec(values.executablename.c_str());
849 debugger->set_prefix(grp->me());
850 if (values.debug)
851 debugger->debug("Starting debugger because -d given on command line.");
852 }
853}
854
855/** Get integral factory.
856 *
857 * \param keyval keyvalue container
858 * \param integral integral group on return
859 * \param argc argument count
860 * \param argv argument array
861 */
862void getIntegralFactory(
863 Ref<KeyVal> &keyval,
864 Ref<Integral> &integral,
865 int argc,
866 char **argv)
867{
868 // first try commandline and environment
869 integral = Integral::initial_integral(argc, argv);
870
871 // if we still don't have a integral, try reading the integral
872 // from the input
873 if (integral.null()) {
874 integral << keyval->describedclassvalue("integrals");
875 }
876
877 if (integral.nonnull())
878 Integral::set_default_integral(integral);
879 else
880 integral = Integral::get_default_integral();
881
882}
883
884void performRestart(
885 Ref<KeyVal> &keyval,
886 Ref<MessageGrp> &grp,
887 Ref<Optimize> &opt,
888 Ref<MolecularEnergy> &mole,
889 char *&restartfile
890 )
891{
892 int restart = keyval->booleanvalue("restart",truevalue);
893 struct stat sb;
894 int statresult, statsize;
895 if (restart) {
896 if (grp->me() == 0) {
897 statresult = stat(restartfile,&sb);
898 statsize = (statresult==0) ? sb.st_size : 0;
899 }
900 grp->bcast(statresult);
901 grp->bcast(statsize);
902 }
903 if (restart && statresult==0 && statsize) {
904 BcastStateInBin si(grp,restartfile);
905 if (keyval->exists("override")) {
906 si.set_override(new PrefixKeyVal(keyval,"override"));
907 }
908 char *suf = strrchr(restartfile,'.');
909 if (!strcmp(suf,".wfn")) {
910 mole << SavableState::key_restore_state(si,"mole");
911 ExEnv::out0() << endl
912 << indent << "Restored <" << mole->class_name()
913 << "> from " << restartfile << endl;
914
915 opt << keyval->describedclassvalue("opt");
916 if (opt.nonnull())
917 opt->set_function(mole.pointer());
918 }
919 else {
920 opt << SavableState::key_restore_state(si,"opt");
921 if (opt.nonnull()) {
922 mole << opt->function();
923 ExEnv::out0() << endl << indent
924 << "Restored <Optimize> from " << restartfile << endl;
925 }
926 }
927 } else {
928 mole << keyval->describedclassvalue("mole");
929 opt << keyval->describedclassvalue("opt");
930 }
931}
932
933char *setMolecularCheckpointFile(
934 Ref<KeyVal> &keyval,
935 Ref<MessageGrp> &grp,
936 Ref<MolecularEnergy> &mole,
937 char *mole_ckpt_file
938 )
939{
940 int checkpoint = keyval->booleanvalue("checkpoint",truevalue);
941 int checkpoint_freq = keyval->intvalue("checkpoint_freq",KeyValValueint(1));
942 if (mole.nonnull()) {
943 MolecularFormula mf(mole->molecule());
944 ExEnv::out0() << endl << indent
945 << "Molecular formula " << mf.formula() << endl;
946 if (checkpoint) {
947 mole->set_checkpoint();
948 if (grp->me() == 0) mole->set_checkpoint_file(mole_ckpt_file);
949 else mole->set_checkpoint_file(devnull);
950 mole->set_checkpoint_freq(checkpoint_freq);
951 }
952 }
953}
954
955/** Checks whether limit on command-line exceeds the basis functions.
956 *
957 * \param mole molecular energy object
958 * \param values temporarily storage for (command-line) options
959 * \return 0 - not exceeded, 1 - exceeded
960 */
961int checkBasisSetLimit(
962 Ref<MolecularEnergy> &mole,
963 struct OptionValues &values
964 )
965{
966 int check = (values.check != (const char *)0);
967 int limit = values.limit;
968 if (limit) {
969 Ref<Wavefunction> wfn; wfn << mole;
970 if (wfn.nonnull() && wfn->ao_dimension()->n() > limit) {
971 ExEnv::out0() << endl << indent
972 << "The limit of " << limit << " basis functions has been exceeded."
973 << endl;
974 check = 1;
975 }
976 }
977 return check;
978}
979
980/** Performs the energy optimization.
981 *
982 * \param opt optimization object
983 * \param mole molecular energy object
984 * \return 0 - not read for frequency calculation, 1 - ready
985 */
986int performEnergyOptimization(
987 Ref<Optimize> &opt,
988 Ref<MolecularEnergy> &mole
989 )
990{
991 int ready_for_freq = 0;
992 int result = opt->optimize();
993 if (result) {
994 ExEnv::out0() << indent
995 << "The optimization has converged." << endl << endl;
996 ExEnv::out0() << indent
997 << scprintf("Value of the MolecularEnergy: %15.10f",
998 mole->energy())
999 << endl << endl;
1000 ready_for_freq = 1;
1001 } else {
1002 ExEnv::out0() << indent
1003 << "The optimization has NOT converged." << endl << endl;
1004 ready_for_freq = 0;
1005 }
1006 return ready_for_freq;
1007}
1008
1009/** Performs gradient calculation.
1010 *
1011 * \param mole molecular energy object
1012 */
1013void performGradientCalculation(
1014 Ref<MolecularEnergy> &mole
1015 )
1016{
1017 mole->do_gradient(1);
1018 ExEnv::out0() << endl << indent
1019 << scprintf("Value of the MolecularEnergy: %15.10f",
1020 mole->energy())
1021 << endl;
1022 if (mole->value_result().actual_accuracy()
1023 > mole->value_result().desired_accuracy()) {
1024 ExEnv::out0() << indent
1025 << "WARNING: desired accuracy not achieved in energy" << endl;
1026 }
1027 ExEnv::out0() << endl;
1028 // Use result_noupdate since the energy might not have converged
1029 // to the desired accuracy in which case grabbing the result will
1030 // start up the calculation again. However the gradient might
1031 // not have been computed (if we are restarting and the gradient
1032 // isn't in the save file for example).
1033 RefSCVector grad;
1034 if (mole->gradient_result().computed()) {
1035 grad = mole->gradient_result().result_noupdate();
1036 }
1037 else {
1038 grad = mole->gradient();
1039 }
1040 if (grad.nonnull()) {
1041 grad.print("Gradient of the MolecularEnergy:");
1042 if (mole->gradient_result().actual_accuracy()
1043 > mole->gradient_result().desired_accuracy()) {
1044 ExEnv::out0() << indent
1045 << "WARNING: desired accuracy not achieved in gradient" << endl;
1046 }
1047 }
1048}
1049
1050/** Performs frequency calculation.
1051 *
1052 * \param mole molecular energy object
1053 * \param molhess molecular hessian object
1054 * \param molfreq molecular frequency object
1055 */
1056void performFrequencyCalculation(
1057 Ref<MolecularEnergy> &mole,
1058 Ref<MolecularHessian> &molhess,
1059 Ref<MolecularFrequencies> &molfreq
1060
1061 )
1062{
1063 RefSymmSCMatrix xhessian;
1064 if (molhess.nonnull()) {
1065 // if "hess" input was given, use it to compute the hessian
1066 xhessian = molhess->cartesian_hessian();
1067 }
1068 else if (mole->hessian_implemented()) {
1069 // if mole can compute the hessian, use that hessian
1070 xhessian = mole->get_cartesian_hessian();
1071 }
1072 else if (mole->gradient_implemented()) {
1073 // if mole can compute gradients, use gradients at finite
1074 // displacements to compute the hessian
1075 molhess = new FinDispMolecularHessian(mole);
1076 xhessian = molhess->cartesian_hessian();
1077 }
1078 else {
1079 ExEnv::out0() << "mpqc: WARNING: Frequencies cannot be computed" << endl;
1080 }
1081
1082 if (xhessian.nonnull()) {
1083 char *hessfile = SCFormIO::fileext_to_filename(".hess");
1084 MolecularHessian::write_cartesian_hessian(hessfile,
1085 mole->molecule(), xhessian);
1086 delete[] hessfile;
1087
1088 molfreq->compute_frequencies(xhessian);
1089 // DEGENERACY IS NOT CORRECT FOR NON-SINGLET CASES:
1090 molfreq->thermochemistry(1);
1091 }
1092}
1093
1094/** Renders some objects.
1095 *
1096 * \param renderer renderer object
1097 * \param keyval keyvalue container
1098 * \param tim timing object
1099 * \param grp message group
1100 */
1101void renderObjects(
1102 Ref<Render> &renderer,
1103 Ref<KeyVal> &keyval,
1104 Ref<RegionTimer> &tim,
1105 Ref<MessageGrp> &grp
1106 )
1107{
1108 Ref<RenderedObject> rendered;
1109 rendered << keyval->describedclassvalue("rendered");
1110 Ref<AnimatedObject> animated;
1111 animated << keyval->describedclassvalue("rendered");
1112 if (rendered.nonnull()) {
1113 if (tim.nonnull()) tim->enter("render");
1114 if (grp->me() == 0) renderer->render(rendered);
1115 if (tim.nonnull()) tim->exit("render");
1116 }
1117 else if (animated.nonnull()) {
1118 if (tim.nonnull()) tim->enter("render");
1119 if (grp->me() == 0) renderer->animate(animated);
1120 if (tim.nonnull()) tim->exit("render");
1121 }
1122 else {
1123 if (tim.nonnull()) tim->enter("render");
1124 int n = keyval->count("rendered");
1125 for (int i=0; i<n; i++) {
1126 rendered << keyval->describedclassvalue("rendered",i);
1127 animated << keyval->describedclassvalue("rendered",i);
1128 if (rendered.nonnull()) {
1129 // make sure the object has a name so we don't overwrite its file
1130 if (rendered->name() == 0) {
1131 char ic[64];
1132 sprintf(ic,"%02d",i);
1133 rendered->set_name(ic);
1134 }
1135 if (grp->me() == 0) renderer->render(rendered);
1136 }
1137 else if (animated.nonnull()) {
1138 // make sure the object has a name so we don't overwrite its file
1139 if (animated->name() == 0) {
1140 char ic[64];
1141 sprintf(ic,"%02d",i);
1142 animated->set_name(ic);
1143 }
1144 if (grp->me() == 0) renderer->animate(animated);
1145 }
1146 }
1147 if (tim.nonnull()) tim->exit("render");
1148 }
1149}
1150
1151/** Save the molecule to PDB file.
1152 *
1153 * \param do_pdb whether to save as pdb (1) or not (0)
1154 * \param grp message group
1155 * \param mole molecular energy object
1156 * \param molname name of output file
1157 */
1158void saveToPdb(
1159 int do_pdb,
1160 Ref<MessageGrp> &grp,
1161 Ref<MolecularEnergy> &mole,
1162 const char *molname
1163 )
1164{
1165 if (do_pdb && grp->me() == 0) {
1166 char *ckptfile = new char[strlen(molname)+5];
1167 sprintf(ckptfile, "%s.pdb", molname);
1168 ofstream pdbfile(ckptfile);
1169 mole->molecule()->print_pdb(pdbfile);
1170 delete[] ckptfile;
1171 }
1172}
1173
1174void init()
1175{
1176 //trash_stack();
1177
1178 int i;
1179 atexit(clean_up);
1180
1181#ifdef HAVE_FEENABLEEXCEPT
1182 // this uses a glibc extension to trap on individual exceptions
1183# ifdef FE_DIVBYZERO
1184 feenableexcept(FE_DIVBYZERO);
1185# endif
1186# ifdef FE_INVALID
1187 feenableexcept(FE_INVALID);
1188# endif
1189# ifdef FE_OVERFLOW
1190 feenableexcept(FE_OVERFLOW);
1191# endif
1192#endif
1193
1194#ifdef HAVE_FEDISABLEEXCEPT
1195 // this uses a glibc extension to not trap on individual exceptions
1196# ifdef FE_UNDERFLOW
1197 fedisableexcept(FE_UNDERFLOW);
1198# endif
1199# ifdef FE_INEXACT
1200 fedisableexcept(FE_INEXACT);
1201# endif
1202#endif
1203
1204#if defined(HAVE_SETRLIMIT)
1205 struct rlimit rlim;
1206 rlim.rlim_cur = 0;
1207 rlim.rlim_max = 0;
1208 setrlimit(RLIMIT_CORE,&rlim);
1209#endif
1210}
1211
1212/** Performs the main work to calculate the ground state energies, gradients, etc.
1213 *
1214 * @param grp message group
1215 * @param values temporary value storage for parsed command-line
1216 * @param input input file name
1217 * @param generic_input generic input file name
1218 * @param in_char_array either NULL or contains char array with read input
1219 * @param argc argument count
1220 * @param argv argument array
1221 */
1222void mainFunction(
1223 Ref<MessageGrp> grp,
1224 struct OptionValues &values,
1225 const char *&output,
1226 const char *&input,
1227 const char *&generic_input,
1228 char *&in_char_array,
1229 int argc,
1230 char **argv
1231#ifdef HAVE_MPQCDATA
1232 , MPQCData &data
1233#endif
1234 )
1235{
1236 // get the basename for output files
1237 setOutputBaseName(input, output);
1238
1239 // parse input into keyvalue container
1240 Ref<ParsedKeyVal> parsedkv;
1241 int use_simple_input = 0; // default is object-oriented if in_char_array is given
1242 if (!in_char_array) // obtain from file
1243 parseInputfile(grp, parsedkv, values, input, generic_input, in_char_array, use_simple_input);
1244 parseIntoKeyValue(parsedkv, values, in_char_array, use_simple_input);
1245 delete[] in_char_array;
1246
1247 // prefix parsed values wit "mpqc"
1248 if (values.keyvalue) parsedkv->verbose(1);
1249 Ref<KeyVal> keyval = new PrefixKeyVal(parsedkv.pointer(),"mpqc");
1250
1251 // set up output classes
1252 setupSCFormIO(grp);
1253
1254 // initialize timing for mpqc
1255 Ref<RegionTimer> tim;
1256 initTimings(grp, keyval, tim);
1257
1258 // announce ourselves
1259 makeAnnouncement(tim);
1260
1261 // get the thread group.
1262 Ref<ThreadGrp> thread;
1263 getThreadGroup(keyval, thread, argc, argv);
1264
1265 // get the memory group.
1266 Ref<MemoryGrp> memory;
1267 getMemoryGroup(keyval, memory, argc, argv);
1268
1269 ExEnv::out0() << indent
1270 << "Using " << grp->class_name()
1271 << " for message passing (number of nodes = " << grp->n() << ")." << endl
1272 << indent
1273 << "Using " << thread->class_name()
1274 << " for threading (number of threads = " << thread->nthread() << ")." << endl
1275 << indent
1276 << "Using " << memory->class_name()
1277 << " for distributed shared memory." << endl
1278 << indent
1279 << "Total number of processors = " << grp->n() * thread->nthread() << endl;
1280
1281 // prepare CCA if available
1282 prepareCCA(keyval, values);
1283
1284 // now set up the debugger
1285 Ref<Debugger> debugger;
1286 setupDebugger(keyval, grp, debugger, values);
1287
1288 // now check to see what matrix kit to use
1289 if (keyval->exists("matrixkit"))
1290 SCMatrixKit::set_default_matrixkit(
1291 dynamic_cast<SCMatrixKit*>(
1292 keyval->describedclassvalue("matrixkit").pointer()));
1293
1294 // get the integral factory.
1295 Ref<Integral> integral;
1296 getIntegralFactory(keyval, integral, argc, argv);
1297 ExEnv::out0() << endl << indent
1298 << "Using " << integral->class_name()
1299 << " by default for molecular integrals evaluation" << endl << endl;
1300
1301 // create some filenames for molecule, checkpoint, basename of output
1302 const char *basename = SCFormIO::default_basename();
1303 KeyValValueString molnamedef(basename);
1304 char * molname = keyval->pcharvalue("filename", molnamedef);
1305 if (strcmp(molname, basename))
1306 SCFormIO::set_default_basename(molname);
1307
1308 char * ckptfile = new char[strlen(molname)+6];
1309 sprintf(ckptfile,"%s.ckpt",molname);
1310
1311 KeyValValueString restartfiledef(ckptfile);
1312 char * restartfile = keyval->pcharvalue("restart_file", restartfiledef);
1313
1314 char * wfn_file = keyval->pcharvalue("wfn_file");
1315 if (wfn_file == 0) {
1316 wfn_file = new char[strlen(molname)+6];
1317 sprintf(wfn_file,"%s.wfn",molname);
1318 }
1319 char *mole_ckpt_file = new char[strlen(wfn_file)+1];
1320 sprintf(mole_ckpt_file,"%s",wfn_file);
1321
1322 int savestate = keyval->booleanvalue("savestate",truevalue);
1323
1324 // setup molecular energy and optimization instances
1325 Ref<MolecularEnergy> mole;
1326 Ref<Optimize> opt;
1327
1328 // read in restart file if we do restart
1329 performRestart(keyval, grp, opt, mole, restartfile);
1330
1331 // setup molecule checkpoint file
1332 setMolecularCheckpointFile(keyval, grp, mole, mole_ckpt_file);
1333 delete[] mole_ckpt_file;
1334
1335 int checkpoint = keyval->booleanvalue("checkpoint",truevalue);
1336 if (checkpoint && opt.nonnull()) {
1337 opt->set_checkpoint();
1338 if (grp->me() == 0) opt->set_checkpoint_file(ckptfile);
1339 else opt->set_checkpoint_file(devnull);
1340 }
1341
1342 // see if frequencies are wanted
1343 Ref<MolecularHessian> molhess;
1344 molhess << keyval->describedclassvalue("hess");
1345 Ref<MolecularFrequencies> molfreq;
1346 molfreq << keyval->describedclassvalue("freq");
1347
1348 // check basis set limit
1349 const int check = checkBasisSetLimit(mole, values);
1350 if (check) {
1351 ExEnv::out0() << endl << indent
1352 << "Exiting since the check option is on." << endl;
1353 exit(0);
1354 }
1355
1356 // from now on we time the calculations
1357 if (tim.nonnull()) tim->change("calc");
1358
1359 int do_energy = keyval->booleanvalue("do_energy",truevalue);
1360
1361 int do_grad = keyval->booleanvalue("do_gradient",falsevalue);
1362
1363 int do_opt = keyval->booleanvalue("optimize",truevalue);
1364
1365 int do_pdb = keyval->booleanvalue("write_pdb",falsevalue);
1366
1367 int print_mole = keyval->booleanvalue("print_mole",truevalue);
1368
1369 int print_timings = keyval->booleanvalue("print_timings",truevalue);
1370
1371 // print all current options (keyvalues)
1372 printOptions(keyval, opt, molname, restartfile);
1373
1374 // see if any pictures are desired
1375 Ref<Render> renderer;
1376 renderer << keyval->describedclassvalue("renderer");
1377
1378 // If we have a renderer, then we will read in some more info
1379 // below. Otherwise we can get rid of the keyval's, to eliminate
1380 // superfluous references to objects that we might otherwise be
1381 // able to delete. We cannot read in the remaining rendering
1382 // objects now, since some of their KeyVal CTOR's are heavyweight,
1383 // requiring optimized geometries, etc.
1384 if (renderer.null()) {
1385 if (parsedkv.nonnull()) print_unseen(parsedkv, input);
1386 keyval = 0;
1387 parsedkv = 0;
1388 }
1389
1390 delete[] restartfile;
1391 delete[] ckptfile;
1392
1393 int ready_for_freq = 1;
1394 if (mole.nonnull()) {
1395 if (((do_opt && opt.nonnull()) || do_grad)
1396 && !mole->gradient_implemented()) {
1397 ExEnv::out0() << indent
1398 << "WARNING: optimization or gradient requested but the given"
1399 << endl
1400 << " MolecularEnergy object cannot do gradients."
1401 << endl;
1402 }
1403
1404 if (do_opt && opt.nonnull() && mole->gradient_implemented()) {
1405
1406 ready_for_freq = performEnergyOptimization(opt, mole);
1407
1408 } else if (do_grad && mole->gradient_implemented()) {
1409
1410 performGradientCalculation(mole);
1411
1412 } else if (do_energy && mole->value_implemented()) {
1413 ExEnv::out0() << endl << indent
1414 << scprintf("Value of the MolecularEnergy: %15.10f",
1415 mole->energy())
1416 << endl << endl;
1417 }
1418 }
1419
1420 // stop timing of calculations
1421 if (tim.nonnull()) tim->exit("calc");
1422
1423 // save this before doing the frequency stuff since that obsoletes the
1424 saveState(wfn_file, savestate, opt, grp, mole, molname, ckptfile);
1425
1426 // Frequency calculation.
1427 if (ready_for_freq && molfreq.nonnull()) {
1428 performFrequencyCalculation(mole, molhess, molfreq);
1429 }
1430
1431 if (renderer.nonnull()) {
1432 renderObjects(renderer, keyval, tim, grp);
1433
1434 Ref<MolFreqAnimate> molfreqanim;
1435 molfreqanim << keyval->describedclassvalue("animate_modes");
1436 if (ready_for_freq && molfreq.nonnull()
1437 && molfreqanim.nonnull()) {
1438 if (tim.nonnull()) tim->enter("render");
1439 molfreq->animate(renderer, molfreqanim);
1440 if (tim.nonnull()) tim->exit("render");
1441 }
1442 }
1443
1444 if (mole.nonnull()) {
1445 if (print_mole)
1446 mole->print(ExEnv::out0());
1447
1448 saveToPdb(do_pdb, grp, mole, molname);
1449
1450 }
1451 else {
1452 ExEnv::out0() << "mpqc: The molecular energy object is null" << endl
1453 << " make sure \"mole\" specifies a MolecularEnergy derivative"
1454 << endl;
1455 }
1456 if (parsedkv.nonnull()) print_unseen(parsedkv, input);
1457
1458 if (print_timings)
1459 if (tim.nonnull()) tim->print(ExEnv::out0());
1460
1461 // here, we may gather the results
1462 // we start to fill the MPQC_Data object
1463 {
1464 Ref<Wavefunction> wfn;
1465 wfn << mole;
1466// ExEnv::out0() << "The number of atomic orbitals: " << wfn->ao_dimension()->n() << endl;
1467// ExEnv::out0() << "The AO density matrix is ";
1468// wfn->ao_density()->print(ExEnv::out0());
1469// ExEnv::out0() << "The natural density matrix is ";
1470// wfn->natural_density()->print(ExEnv::out0());
1471// ExEnv::out0() << "The Gaussian basis is " << wfn->basis()->name() << endl;
1472// ExEnv::out0() << "The Gaussians sit at the following centers: " << endl;
1473// for (int nr = 0; nr< wfn->basis()->ncenter(); ++nr) {
1474// ExEnv::out0() << nr << " basis function has its center at ";
1475// for (int i=0; i < 3; ++i)
1476// ExEnv::out0() << wfn->basis()->r(nr,i) << "\t";
1477// ExEnv::out0() << endl;
1478// }
1479 // print the energy
1480 data.energies.total = mole->energy();
1481 data.energies.nuclear_repulsion = wfn->nuclear_repulsion_energy();
1482// data.energies.electron_repulsion = integral->electron_repulsion();
1483// data.energies.correlation = wfn->corr_energy();
1484 // taken from clscf.cc: CLSCF::scf_energy() (but see also Szabo/Ostlund)
1485 {
1486 RefSymmSCMatrix t = wfn->overlap();
1487 RefSymmSCMatrix cl_dens_ = wfn->ao_density();
1488
1489 SCFEnergy *eop = new SCFEnergy;
1490 eop->reference();
1491 Ref<SCElementOp2> op = eop;
1492 t.element_op(op,cl_dens_);
1493 op=0;
1494 eop->dereference();
1495
1496 data.energies.overlap = eop->result();
1497
1498 delete eop;
1499 t = 0;
1500 cl_dens_ = 0;
1501 }
1502// data.energies.kinetic = integral->kinetic();
1503 {
1504 RefSymmSCMatrix t = wfn->core_hamiltonian();
1505 RefSymmSCMatrix cl_dens_ = wfn->ao_density();
1506
1507 SCFEnergy *eop = new SCFEnergy;
1508 eop->reference();
1509 Ref<SCElementOp2> op = eop;
1510 t.element_op(op,cl_dens_);
1511 op=0;
1512 eop->dereference();
1513
1514 data.energies.hcore = eop->result();
1515
1516 delete eop;
1517 t = 0;
1518 cl_dens_ = 0;
1519 }
1520 ExEnv::out0() << endl << indent
1521 << scprintf("Value of the MolecularEnergy: %15.10f",
1522 mole->energy())
1523 << endl;
1524 // print the gradient
1525 RefSCVector grad;
1526 if (mole->gradient_result().computed()) {
1527 grad = mole->gradient_result().result_noupdate();
1528 }
1529 else {
1530 grad = mole->gradient();
1531 }
1532 if (grad.nonnull()) {
1533 data.forces.resize(grad.dim()/3);
1534 for (int j=0;j<grad.dim()/3; ++j) {
1535 data.forces[j].resize(3, 0.);
1536 }
1537 std::cout << "Gradient of the MolecularEnergy:" << std::endl;
1538 for (int j=0;j<grad.dim()/3; ++j) {
1539 std::cout << "\t";
1540 for (int i=0; i< 3; ++i) {
1541 data.forces[j][i] = grad[3*j+i];
1542 std::cout << grad[3*j+i] << "\t";
1543 }
1544 std::cout << endl;
1545 }
1546 }
1547 // times
1548 data.times.walltime = tim->get_wall_time();
1549 data.times.cputime = tim->get_cpu_time();
1550 data.times.flops = tim->get_flops();
1551
1552 // eigenvalues (this only works if we have a OneBodyWavefunction, i.e. SCF procedure)
1553 SCF *scf = require_dynamic_cast<SCF*>(wfn, "mainFunction");
1554 RefDiagSCMatrix evals = scf->eigenvalues();
1555
1556 for(int i=0;i<wfn->oso_dimension(); ++i) {
1557 data.energies.eigenvalues.push_back(evals(i));
1558 std::cout << i << "th eigenvalue is " << evals(i) << std::endl;
1559 }
1560
1561 // we now need to sample the density on the grid
1562 // 1. get max and min over all basis function positions
1563 assert( wfn->basis()->ncenter() > 0 );
1564 SCVector3 min( wfn->basis()->r(0,0), wfn->basis()->r(0,1), wfn->basis()->r(0,2) );
1565 SCVector3 max( wfn->basis()->r(0,0), wfn->basis()->r(0,1), wfn->basis()->r(0,2) );
1566 for (int nr = 1; nr< wfn->basis()->ncenter(); ++nr) {
1567 for (int i=0; i < 3; ++i) {
1568 if (wfn->basis()->r(nr,i) < min(i))
1569 min(i) = wfn->basis()->r(nr,i);
1570 if (wfn->basis()->r(nr,i) > max(i))
1571 max(i) = wfn->basis()->r(nr,i);
1572 }
1573 }
1574 std::cout << "Min is at " << min << " and max is at " << max << std::endl;
1575
1576 // 2. choose an appropriately large grid
1577 // we have to pay attention to capture the right amount of the exponential decay
1578 // and also to have a power of two size of the grid at best
1579 double boundary = 5.; // boundary extent around compact domain containing basis functions
1580 double delta = 1.; // step width in density sampling
1581
1582 // for the moment we always generate a grid of full size
1583 min.x() = data.density.begin[0];
1584 min.y() = data.density.begin[1];
1585 min.z() = data.density.begin[2];
1586 max.x() = min.x() + data.density.size;
1587 max.y() = min.y() + data.density.size;
1588 max.z() = min.z() + data.density.size;
1589 const int gridpoints = pow(2,data.density.level);
1590 delta = data.density.size / (double) gridpoints;
1591 std::cout << "Grid starts at " << min
1592 << " and ends at " << max
1593 << " with a delta of " << delta
1594 << " to get " << gridpoints << " gridpoints."
1595 << std::endl;
1596
1597 // 3. sample the atomic density
1598 int nbasis = wfn->basis()->nbasis();
1599 double *b_val = new double[nbasis];
1600 Ref<Integral> intgrl = Integral::get_default_integral();
1601 GaussianBasisSet::ValueData vdat(wfn->basis(), integral);
1602 SCVector3 r;
1603 data.density.sampled_grid.clear();
1604 data.density.sampled_grid.reserve(gridpoints*gridpoints*gridpoints);
1605 for (r.x() = min.x() ; r.x() < max.x(); r.x() += delta)
1606 for (r.y() = min.y() ; r.y() < max.y(); r.y() += delta)
1607 for (r.z() =min.z() ; r.z() < max.z(); r.z() += delta) {
1608 wfn->basis()->values(r, &vdat, b_val);
1609 double sum = 0.;
1610 for (int i=0; i<nbasis; i++)
1611 sum += wfn->ao_density()->get_element(i,i)*b_val[i];
1612 data.density.sampled_grid.push_back(sum);
1613 }
1614
1615// // GaussianShell is the actual orbital functions it seems ...
1616// //ExEnv::out0() << "There are the following Gaussian Shells: " << endl;
1617// SCVector3 r;
1618// r.x() = r.y() = r.z() = 10;
1619// ExEnv::out0() << "We get the following value at " << r << "." << endl;
1620// Ref<Integral> intgrl = Integral::get_default_integral();
1621// GaussianBasisSet::ValueData vdat(wfn->basis(), integral);
1622// ExEnv::out0() << "Value at (10,10,10) is " << EvaluateDensity(r, intgrl, vdat, wfn) << endl;
1623// boost::function<double (SCVector3 &r)> evaluator =
1624// boost::bind(&EvaluateDensity, _1, boost::ref(intgrl), boost::ref(vdat), boost::ref(wfn));
1625// ExEnv::out0() << "Check against values at " << r << "." << endl;
1626// int nbasis = wfn->basis()->nbasis();
1627// double *b_val = new double[nbasis];
1628// wfn->basis()->values(r, &vdat, b_val);
1629// for (int i=0; i<nbasis; i++) {
1630// //ExEnv::out0() << "Shell nr. " << nr << ": ";
1631// ExEnv::out0() << "Value at (10,10,10) is " << b_val[i] << endl;
1632// }
1633// // perform test integration of density
1634// double delta = 1.;
1635// double sum = 0.;
1636// for (r.x() = -10. ; r.x() < 10.; r.x() += delta)
1637// for (r.y() = -10. ; r.y() < 10.; r.y() += delta)
1638// for (r.z() = -10. ; r.z() < 10.; r.z() += delta) {
1639// wfn->basis()->values(r, &vdat, b_val);
1640// for (int i=0; i<nbasis; i++)
1641// sum += wfn->ao_density()->get_element(i,i)*b_val[i];
1642// }
1643// sum /= pow(20/delta,3);
1644// ExEnv::out0() << "Sum over domain [0:20]^3 with " << delta << " delta is " << sum << "." << endl;
1645// delete[] b_val;
1646 }
1647
1648 delete[] molname;
1649 SCFormIO::set_default_basename(0);
1650
1651 renderer = 0;
1652 molfreq = 0;
1653 molhess = 0;
1654 opt = 0;
1655 mole = 0;
1656 integral = 0;
1657 debugger = 0;
1658 thread = 0;
1659 tim = 0;
1660 keyval = 0;
1661 parsedkv = 0;
1662 memory = 0;
1663 clean_up();
1664
1665#if defined(HAVE_TIME) && defined(HAVE_CTIME)
1666 time_t t;
1667 time(&t);
1668 const char *tstr = ctime(&t);
1669#endif
1670 if (!tstr) {
1671 tstr = "UNKNOWN";
1672 }
1673 ExEnv::out0() << endl
1674 << indent << scprintf("End Time: %s", tstr) << endl;
1675}
1676
1677// static values object
1678OptionValues values;
1679
1680#ifdef HAVE_JOBMARKET
1681FragmentResult::ptr MPQCJob::Work()
1682{
1683 char mpqc[] = "mpqc" ;
1684 char **argv = new char*[1];
1685 argv[0] = &mpqc[0];
1686 int argc = 1;
1687// init();
1688//
1689// ExEnv::init(argc, argv);
1690//
1691// // parse commandline options
1692// GetLongOpt options;
1693// int optind = ParseOptions(options, argc, argv);
1694// const char *output = 0;
1695// ostream *outstream = 0;
1696// ComputeOptions(options, output, outstream);
1697// OptionValues values;
1698// parseRemainderOptions(options, values, argc, argv);
1699//
1700// // get the basename for output files
1701// char filename_template[] = "mpqc_temp_XXXXXX";
1702// output = mktemp(filename_template);
1703// setOutputBaseName(NULL, output);
1704
1705 // now comes the actual work
1706 int nfilebase = (int) inputfile.length();
1707 char *in_char_array = new char[nfilebase + 1];
1708 strncpy(in_char_array, inputfile.c_str(), nfilebase);
1709 in_char_array[nfilebase] = '\0';
1710 const char *input = 0;
1711 const char *generic_input = 0;
1712 Ref<MessageGrp> grp = MessageGrp::get_default_messagegrp();
1713 // create unique, temporary name and check whether it exists
1714 const char *output = NULL;
1715 std::ifstream test;
1716 do {
1717 char filename_template[] = "mpqc_temp_XXXXXX";
1718 output = mktemp(filename_template);
1719 test.open(output);
1720 } while (test.good());
1721 // put info how to sample the density into MPQCData
1722 MPQCData data(begin, size, level);
1723// now call work horse
1724 mainFunction(grp, values, output, input, generic_input, in_char_array, argc, argv, data);
1725// delete[] in_char_array;
1726
1727// if (output != 0) {
1728// ExEnv::set_out(&cout);
1729// delete outstream;
1730// }
1731// delete[] argv;
1732//
1733 // place into returnstream
1734 std::stringstream returnstream;
1735 boost::archive::text_oarchive oa(returnstream);
1736 oa << data;
1737
1738 FragmentResult::ptr s( new FragmentResult(getId(), returnstream.str()) );
1739 return s;
1740}
1741#endif
1742
1743// we need to explicitly instantiate the serialization functions as
1744// its is only serialized through its base class FragmentJob
1745BOOST_CLASS_EXPORT_IMPLEMENT(MPQCJob)
1746
1747int
1748try_main(int argc, char *argv[])
1749{
1750 init();
1751
1752 ExEnv::init(argc, argv);
1753
1754 // parse commandline options
1755 GetLongOpt options;
1756 int optind = ParseOptions(options, argc, argv);
1757 const char *output = 0;
1758 ostream *outstream = 0;
1759 ComputeOptions(options, output, outstream);
1760 parseRemainderOptions(options, values, argc, argv);
1761
1762 // get input file names, either object-oriented or generic
1763 const char *object_input = 0;
1764 const char *generic_input = 0;
1765 getInputFileNames(object_input, generic_input, options, optind, argc, argv);
1766 const char *input;
1767 if (object_input) input = object_input;
1768 if (generic_input) input = generic_input;
1769
1770 // get the message group. first try the commandline and environment
1771 Ref<MessageGrp> grp;
1772 getMessageGroup(grp, argc, argv);
1773
1774 // check if we got option "-n"
1775 int exitflag = 0;
1776#ifdef HAVE_JOBMARKET
1777 if (options.retrieve("n")) {
1778 /// create new argc, argv and call by splitting with tokenizer
1779 std::string networkstring(options.retrieve("n"));
1780 typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
1781 boost::char_separator<char> sep(" ");
1782 tokenizer tok(networkstring, sep);
1783 // simple count because tokenizer has now size()
1784 int argc_network = 0;
1785 for(tokenizer::iterator beg=tok.begin(); beg!=tok.end();++beg)
1786 ++argc_network;
1787 // argv[0] is program name
1788 char **argv_network = new char*[argc_network+1];
1789 argv_network[0] = new char[5];
1790 strcpy(argv_network[0], "mpqc");
1791 // then we place each token as a new argument
1792 argc_network = 1;
1793 for(tokenizer::iterator beg=tok.begin(); beg!=tok.end();++beg){
1794 const size_t strlength = (*beg).length();
1795 const char *strarray = beg->c_str();
1796 //std::cout << "Token " << argc_network << " is " << strarray << ", length " << strlength << endl;
1797 argv_network[argc_network] = new char[strlength+1];
1798 strcpy(argv_network[argc_network], strarray);
1799 argv_network[argc_network][strlength] = '\0';
1800 for (size_t index = 0; index < strlength; ++index)
1801 if (argv_network[argc_network][index] == '+')
1802 argv_network[argc_network][index] = '-';
1803 ++argc_network;
1804 }
1805 /// and start listening for MPQCJobs
1806 exitflag = poolworker_main(argc_network, argv_network);
1807 /// remove the artifical [argv,argv] again
1808 for (int i=0;i<argc_network;++i)
1809 delete[] argv_network[i];
1810 delete[] argv_network;
1811 } else
1812#endif
1813 {
1814 // if not, work on the command line input
1815 char *in_char_array = 0;
1816#ifdef HAVE_MPQCDATA
1817 MPQCData data;
1818 mainFunction(grp, values, output, input, generic_input, in_char_array, argc, argv, data);
1819#else
1820 mainFunction(grp, values, output, input, generic_input, in_char_array, argc, argv);
1821#endif
1822 }
1823
1824 if (output != 0) {
1825 ExEnv::set_out(&cout);
1826 delete outstream;
1827 }
1828
1829 grp = 0;
1830 final_clean_up();
1831
1832 return exitflag;
1833}
1834
1835
1836double EvaluateDensity(SCVector3 &r, Ref<Integral> &intgrl, GaussianBasisSet::ValueData &vdat, Ref<Wavefunction> &wfn)
1837{
1838 ExEnv::out0() << "We get the following values at " << r << "." << endl;
1839 int nbasis = wfn->basis()->nbasis();
1840 double *b_val = new double[nbasis];
1841 wfn->basis()->values(r, &vdat, b_val);
1842 double sum=0.;
1843 for (int i=0; i<nbasis; i++)
1844 sum += b_val[i];
1845 delete[] b_val;
1846 return sum;
1847}
1848
1849int
1850main(int argc, char *argv[])
1851{
1852 try {
1853 try_main(argc, argv);
1854 }
1855 catch (SCException &e) {
1856 cout << argv[0] << ": ERROR: SC EXCEPTION RAISED:" << endl
1857 << e.what()
1858 << endl;
1859 clean_up();
1860 throw;
1861 }
1862 catch (bad_alloc &e) {
1863 cout << argv[0] << ": ERROR: MEMORY ALLOCATION FAILED:" << endl
1864 << e.what()
1865 << endl;
1866 clean_up();
1867 throw;
1868 }
1869 catch (exception &e) {
1870 cout << argv[0] << ": ERROR: EXCEPTION RAISED:" << endl
1871 << e.what()
1872 << endl;
1873 clean_up();
1874 throw;
1875 }
1876 catch (...) {
1877 cout << argv[0] << ": ERROR: UNKNOWN EXCEPTION RAISED" << endl;
1878 clean_up();
1879 throw;
1880 }
1881 return 0;
1882}
1883
1884/////////////////////////////////////////////////////////////////////////////
1885
1886// Local Variables:
1887// mode: c++
1888// c-file-style: "ETS"
1889// End:
Note: See TracBrowser for help on using the repository browser.