00001
00007
00008
00009
00010
00011
00012 #if !defined(WIN32) || defined(__CYGWIN__)
00013 #include <unistd.h>
00014 #endif
00015 #include "InfoStream.h"
00016 #include "Node.decl.h"
00017 #include "Node.h"
00018 #ifdef DPMTA
00019 #include <pvm3.h>
00020 #endif
00021
00022 #include "ProcessorPrivate.h"
00023
00024 #define MIN_DEBUG_LEVEL 3
00025
00026 #include "Debug.h"
00027
00028 #include <stdio.h>
00029 #include <converse.h>
00030 #include "memusage.h"
00031 #include "IMDOutput.h"
00032
00033 #ifdef USE_COMM_LIB
00034 #include "ComlibManager.h"
00035 #endif
00036
00037 #include "Lattice.h"
00038 #include "main.decl.h"
00039 #include "main.h"
00040 #include "WorkDistrib.h"
00041 #include "PatchMgr.h"
00042 #include "Patch.h"
00043 #include "Compute.h"
00044 #include "ComputeMap.h"
00045 #include "ComputeMgr.h"
00046 #include "Molecule.h"
00047 #include "HomePatchList.h"
00048 #include "AtomMap.h"
00049 #include "Sequencer.h"
00050 #include "Controller.h"
00051 #include "NamdState.h"
00052 #include "Output.h"
00053 #include "ProxyMgr.h"
00054 #include "PatchMap.h"
00055 #include "PatchMap.inl"
00056 #include "Parameters.h"
00057 #include "SimParameters.h"
00058 #include "Communicate.h"
00059 #include "LdbCoordinator.h"
00060 #include "ScriptTcl.h"
00061 #include "ComputeMgr.decl.h"
00062 #include "ComputePmeMgr.decl.h"
00063 #include "ComputeGridForceMgr.decl.h"
00064 #include "OptPmeMgr.decl.h"
00065 #include "Sync.h"
00066 #include "BackEnd.h"
00067 #include "PDB.h"
00068
00069 #if(CMK_CCS_AVAILABLE && CMK_WEB_MODE)
00070 extern "C" void CApplicationInit();
00071 #endif
00072
00073 #include "DumpBench.h"
00074
00075 #ifdef MEM_OPT_VERSION
00076 #include "CollectionMgr.h"
00077 #include "CollectionMaster.h"
00078 #include "CollectionMgr.decl.h"
00079 #include "CollectionMaster.decl.h"
00080 #endif
00081
00082 #if USE_HPM
00083 extern "C" void HPM_Init(int);
00084 extern "C" void HPM_Start(char *label, int);
00085 extern "C" void HPM_Stop(char *label, int);
00086 extern "C" void HPM_Print(int, int);
00087 #endif
00088
00089
00090
00091
00092
00093
00094 int eventEndOfTimeStep;
00095 double startupTime;
00096
00097
00098
00099 Node::Node(GroupInitMsg *msg)
00100 {
00101 DebugM(4,"Creating Node\n");
00102 #if(CMK_CCS_AVAILABLE && CMK_WEB_MODE)
00103 CApplicationInit();
00104 #endif
00105 if (CkpvAccess(Node_instance) == 0) {
00106 CkpvAccess(Node_instance) = this;
00107 eventEndOfTimeStep = traceRegisterUserEvent("EndOfTimeStep");
00108 } else {
00109 NAMD_bug("Node::Node() - another instance of Node exists!");
00110 }
00111
00112 CkpvAccess(BOCclass_group) = msg->group;
00113 delete msg;
00114
00115 CkpvAccess(BOCclass_group).node = thisgroup;
00116
00117 startupPhase = 0;
00118
00119 molecule = NULL;
00120 parameters = NULL;
00121 simParameters = NULL;
00122 configList = NULL;
00123 pdb = NULL;
00124 state = NULL;
00125 output = NULL;
00126 imd = new IMDOutput;
00127
00128 #if USE_HPM
00129
00130 TopoManager *tmgr = new TopoManager();
00131 int x, y, z;
00132 tmgr->rankToCoordinates(CkMyPe(), x, y, z, localRankOnNode);
00133 delete tmgr;
00134 #endif
00135
00136 DebugM(4,"Creating PatchMap, AtomMap, ComputeMap\n");
00137 patchMap = PatchMap::Instance();
00138 atomMap = AtomMap::Instance();
00139 computeMap = ComputeMap::Instance();
00140
00141 DebugM(4,"Binding to BOC's\n");
00142 CProxy_PatchMgr pm(CkpvAccess(BOCclass_group).patchMgr);
00143 patchMgr = pm.ckLocalBranch();
00144 CProxy_ProxyMgr prm(CkpvAccess(BOCclass_group).proxyMgr);
00145 proxyMgr = prm.ckLocalBranch();
00146 CProxy_WorkDistrib wd(CkpvAccess(BOCclass_group).workDistrib);
00147 workDistrib = wd.ckLocalBranch();
00148 CProxy_ComputeMgr cm(CkpvAccess(BOCclass_group).computeMgr);
00149 computeMgr = cm.ckLocalBranch();
00150 CProxy_LdbCoordinator lc(CkpvAccess(BOCclass_group).ldbCoordinator);
00151 ldbCoordinator = lc.ckLocalBranch();
00152
00153 }
00154
00155
00156
00157
00158 Node::~Node(void)
00159 {
00160 delete output;
00161 delete computeMap;
00162 delete atomMap;
00163 delete patchMap;
00164 delete CkpvAccess(comm);
00165 }
00166
00167
00168
00169
00170 void Node::messageStartUp() {
00171 (CProxy_Node(CkpvAccess(BOCclass_group).node)).startup();
00172 }
00173
00174 void Node::startUp(CkQdMsg *qmsg) {
00175 delete qmsg;
00176 (CProxy_Node(CkpvAccess(BOCclass_group).node)).startup();
00177 }
00178
00179 SimParameters *node_simParameters;
00180 Parameters *node_parameters;
00181 Molecule *node_molecule;
00182
00183 extern void registerUserEventsForAllComputeObjs(void);
00184
00185 void Node::startup() {
00186 int gotoRun = false;
00187 double newTime;
00188
00189 if (!CkMyPe()) {
00190 if (!startupPhase) {
00191 iout << iINFO << "\n";
00192 startupTime = CmiWallTimer();
00193 iout << iINFO << "Entering startup at " << startupTime << " s, ";
00194 } else {
00195 newTime = CmiWallTimer();
00196 iout << iINFO << "Startup phase " << startupPhase-1 << " took "
00197 << newTime - startupTime << " s, ";
00198 startupTime = newTime;
00199 }
00200 iout << memusage_MB() << " MB of memory in use\n" << endi;
00201 fflush(stdout);
00202 }
00203
00204 switch (startupPhase) {
00205
00206 case 0:
00207 #ifdef CHARMIZE_NAMD
00208 populateAtomDisArrs(startupPhase);
00209 #endif
00210
00211 namdOneCommInit();
00212 break;
00213
00214 case 1:
00215
00216 if (CkMyPe()) {
00217 namdOneRecv();
00218 } else {
00219 namdOneSend();
00220 }
00221
00222 #ifdef CHARMIZE_NAMD
00223
00224 if(!CkMyPe()){
00225 AllCharmArrsMsg *arrsMsg = new AllCharmArrsMsg;
00226 arrsMsg->atomsDis = atomDisArr;
00227 ((CProxy_Node)thisgroup).sendCharmArrProxies(arrsMsg);
00228 }
00229 #endif
00230 break;
00231
00232 case 2:
00233
00234 simParameters = node_simParameters;
00235 parameters = node_parameters;
00236 molecule = node_molecule;
00237
00238 #if USE_HPM
00239 HPM_Init(localRankOnNode);
00240 #endif
00241
00242 #ifdef MEM_OPT_VERSION
00243
00244 if(!CkMyPe()){
00245 CkChareID collectionMaster;
00246 if(CkNumPes()>1 && simParameters->shiftIOToOne)
00247 collectionMaster = CProxy_CollectionMaster::ckNew(1);
00248 else
00249 collectionMaster = CProxy_CollectionMaster::ckNew(0);
00250
00251
00252 CollectionMasterHandler::Object()->setRealMaster(collectionMaster);
00253 CProxy_CollectionMgr cmgr(CkpvAccess(BOCclass_group).collectionMgr);
00254 SlaveInitMsg *bcmaster = new SlaveInitMsg;
00255 bcmaster->master = collectionMaster;
00256 cmgr.setCollectionMaster(bcmaster);
00257 }
00258 #endif
00259
00260
00261 threadInit();
00262
00263
00264 AtomMap::Object()->allocateMap(molecule->numAtoms);
00265
00266 if (!CkMyPe()) {
00267 if (simParameters->useOptPME)
00268 CkpvAccess(BOCclass_group).computePmeMgr = CProxy_OptPmeMgr::ckNew();
00269 else
00270 CkpvAccess(BOCclass_group).computePmeMgr = CProxy_ComputePmeMgr::ckNew();
00271 }
00272
00273 break;
00274
00275 case 3:
00276 if(simParameters->isSendSpanningTreeOn()) {
00277 ProxyMgr::Object()->setSendSpanning();
00278 }
00279 if(simParameters->isRecvSpanningTreeOn()) {
00280 ProxyMgr::Object()->setRecvSpanning();
00281 }
00282 #ifdef PROCTRACE_DEBUG
00283 DebugFileTrace::Instance("procTrace");
00284 #endif
00285
00286 if (!CkMyPe()) {
00287 output = new Output;
00288 workDistrib->patchMapInit();
00289
00290 #ifdef MEM_OPT_VERSION
00291
00292 workDistrib->preCreateHomePatches();
00293 #else
00294 workDistrib->createHomePatches();
00295 #endif
00296
00297 workDistrib->assignNodeToPatch();
00298 workDistrib->mapComputes();
00299 ComputeMap::Object()->printComputeMap();
00300
00301 registerUserEventsForAllComputeObjs();
00302
00303 workDistrib->sendMaps();
00304 #ifdef USE_NODEPATCHMGR
00305 CProxy_NodeProxyMgr npm(CkpvAccess(BOCclass_group).nodeProxyMgr);
00306
00307 npm.createProxyInfo(PatchMap::Object()->numPatches());
00308 #endif
00309 }
00310 {
00311 #if defined(NODEAWARE_PROXY_SPANNINGTREE) && defined(USE_NODEPATCHMGR)
00312 CProxy_NodeProxyMgr npm(CkpvAccess(BOCclass_group).nodeProxyMgr);
00313 if(CkMyRank()==0) {
00314
00315 npm[CkMyNode()].ckLocalBranch()->registerLocalProxyMgr(CkpvAccess(BOCclass_group).proxyMgr);
00316 }
00317 npm[CkMyNode()].ckLocalBranch()->registerLocalPatchMap(CkMyRank(), PatchMap::Object());
00318 #endif
00319 }
00320 break;
00321
00322 case 4:
00323 if ( simParameters->PMEOn ) {
00324 if ( simParameters->useOptPME ) {
00325 CProxy_OptPmeMgr pme(CkpvAccess(BOCclass_group).computePmeMgr);
00326 pme[CkMyPe()].initialize(new CkQdMsg);
00327 }
00328 else {
00329 CProxy_ComputePmeMgr pme(CkpvAccess(BOCclass_group).computePmeMgr);
00330 pme[CkMyPe()].initialize(new CkQdMsg);
00331 }
00332 }
00333 break;
00334
00335 case 5:
00336 if ( simParameters->PMEOn ) {
00337 if ( simParameters->useOptPME ) {
00338 CProxy_OptPmeMgr pme(CkpvAccess(BOCclass_group).computePmeMgr);
00339 pme[CkMyPe()].initialize_pencils(new CkQdMsg);
00340 }
00341 else {
00342 CProxy_ComputePmeMgr pme(CkpvAccess(BOCclass_group).computePmeMgr);
00343 pme[CkMyPe()].initialize_pencils(new CkQdMsg);
00344 }
00345 }
00346 if (!CkMyPe()) {
00347 #ifdef MEM_OPT_VERSION
00348 workDistrib->initAndSendHomePatch();
00349 #else
00350 workDistrib->distributeHomePatches();
00351 #endif
00352 }
00353 break;
00354
00355 case 6:
00356 if ( simParameters->PMEOn ) {
00357 if ( simParameters->useOptPME ) {
00358 CProxy_OptPmeMgr pme(CkpvAccess(BOCclass_group).computePmeMgr);
00359 pme[CkMyPe()].activate_pencils(new CkQdMsg);
00360 }
00361 else {
00362 CProxy_ComputePmeMgr pme(CkpvAccess(BOCclass_group).computePmeMgr);
00363 pme[CkMyPe()].activate_pencils(new CkQdMsg);
00364 }
00365 }
00366 proxyMgr->createProxies();
00367 if (!CkMyPe()) LdbCoordinator::Object()->createLoadBalancer();
00368 break;
00369
00370 case 7:
00371 if (!CkMyPe()) {
00372 ComputeMap::Object()->printComputeMap();
00373 }
00374 Sync::Object()->openSync();
00375 if (proxySendSpanning || proxyRecvSpanning )
00376 proxyMgr->buildProxySpanningTree();
00377 DebugM(4,"Creating Computes\n");
00378 computeMgr->createComputes(ComputeMap::Object());
00379 DebugM(4,"Building Sequencers\n");
00380 buildSequencers();
00381 DebugM(4,"Initializing LDB\n");
00382 LdbCoordinator::Object()->initialize(patchMap,computeMap);
00383 break;
00384
00385 case 8:
00386 {
00387
00388
00389
00390
00391
00392
00393 }
00394 #ifdef MEM_OPT_VERSION
00395 if(!CkMyPe()){
00396 molecule->delEachAtomSigs();
00397 molecule->delChargeSpace();
00398 if(!simParameters->freeEnergyOn)
00399 molecule->delMassSpace();
00400 molecule->delOtherEachAtomStructs();
00401
00402
00403 pdb->delPDBCoreData();
00404 }
00405
00406
00407
00408 if(simParameters->wrapAll || simParameters->wrapWater){
00409 int peOfCollectionMaster = 0;
00410 if(CkNumPes()>1 && simParameters->shiftIOToOne) peOfCollectionMaster = 1;
00411 if(CkNumPes()>1 && CkMyPe()!=peOfCollectionMaster)
00412 molecule->delClusterSigs();
00413 }else{
00414 molecule->delClusterSigs();
00415 }
00416 #endif
00417 gotoRun = true;
00418 break;
00419
00420 default:
00421 NAMD_bug("Startup Phase has a bug - check case statement");
00422 break;
00423
00424 }
00425
00426 startupPhase++;
00427 if (!CkMyPe()) {
00428 if (!gotoRun) {
00429 CkStartQD(CkIndex_Node::startUp((CkQdMsg*)0),&thishandle);
00430 } else {
00431 Node::messageRun();
00432 }
00433 }
00434 }
00435
00436 void Node::namdOneCommInit()
00437 {
00438 if (CkpvAccess(comm) == NULL) {
00439 CkpvAccess(comm) = new Communicate();
00440 #ifdef DPMTA
00441 pvmc_init();
00442 #endif
00443 }
00444 }
00445
00446 #ifdef CHARMIZE_NAMD
00447
00448 void Node::populateAtomDisArrs(int startupPhase){
00449 if(CkMyPe()) return;
00450 if(startupPhase) return;
00451
00452 int disArrSize = molecule->numAtoms/AtomsDisInfo::ATOMDISNUM;
00453 int remainAtoms = molecule->numAtoms%AtomsDisInfo::ATOMDISNUM;
00454
00455 int totalArrSize = disArrSize + (remainAtoms!=0);
00456 atomDisArr = CProxy_AtomsDisInfo::ckNew(totalArrSize);
00457
00458 int atomIndex = 0;
00459 Atom *allAtoms = molecule->getAllAtoms();
00460 for(int i=0; i<totalArrSize; i++){
00461 int actualAtomCnt = AtomsDisInfo::ATOMDISNUM;
00462 if(i==disArrSize) actualAtomCnt = remainAtoms;
00463
00464 AtomStaticInfoMsg *staticMsg = new(actualAtomCnt, 0)AtomStaticInfoMsg;
00465 staticMsg->actualNumAtoms = actualAtomCnt;
00466 for(int j=0; j<actualAtomCnt; j++, atomIndex++){
00467 staticMsg->atoms[j] = allAtoms[atomIndex];
00468 }
00469 atomDisArr[i].recvStaticInfo(staticMsg);
00470 }
00471 }
00472 #endif
00473
00474
00475
00476 void Node::namdOneRecv() {
00477 if ( CmiMyRank() ) return;
00478
00479 MIStream *conv_msg;
00480
00481
00482 simParameters = node_simParameters = new SimParameters;
00483
00484 parameters = node_parameters = new Parameters();
00485
00486 molecule = node_molecule = new Molecule(simParameters,parameters);
00487
00488 DebugM(4, "Getting SimParameters\n");
00489 conv_msg = CkpvAccess(comm)->newInputStream(0, SIMPARAMSTAG);
00490 simParameters->receive_SimParameters(conv_msg);
00491
00492 DebugM(4, "Getting Parameters\n");
00493 conv_msg = CkpvAccess(comm)->newInputStream(0, STATICPARAMSTAG);
00494 parameters->receive_Parameters(conv_msg);
00495
00496 DebugM(4, "Getting Molecule\n");
00497 conv_msg = CkpvAccess(comm)->newInputStream(0, MOLECULETAG);
00498 molecule->receive_Molecule(conv_msg);
00499
00500 DebugM(4, "Done Receiving\n");
00501 }
00502
00503 void Node::namdOneSend() {
00504 node_simParameters = simParameters;
00505 node_parameters = parameters;
00506 node_molecule = molecule;
00507
00508 MOStream *conv_msg;
00509
00510 DebugM(4, "Sending SimParameters\n");
00511 conv_msg = CkpvAccess(comm)->newOutputStream(ALLBUTME, SIMPARAMSTAG, BUFSIZE);
00512 simParameters->send_SimParameters(conv_msg);
00513
00514 DebugM(4, "Sending Parameters\n");
00515 conv_msg = CkpvAccess(comm)->newOutputStream(ALLBUTME, STATICPARAMSTAG, BUFSIZE);
00516 parameters->send_Parameters(conv_msg);
00517
00518 DebugM(4, "Sending Molecule\n");
00519 int bufSize = BUFSIZE;
00520 if(molecule->numAtoms>=1000000) bufSize = 16*BUFSIZE;
00521 conv_msg = CkpvAccess(comm)->newOutputStream(ALLBUTME, MOLECULETAG, bufSize);
00522 molecule->send_Molecule(conv_msg);
00523 }
00524
00525 void Node::sendCharmArrProxies(AllCharmArrsMsg *msg){
00526 #ifdef CHARMIZE_NAMD
00527 if(CkMyPe()){
00528 atomDisArr = msg->atomsDis;
00529 }
00530 delete msg;
00531 #else
00532 NAMD_die("sendCharmArrProxies should not be called in this case!");
00533 #endif
00534 }
00535
00536
00537
00538 void Node::threadInit() {
00539
00540 if (CthImplemented()) {
00541 CthSetStrategyDefault(CthSelf());
00542 } else {
00543 NAMD_bug("Node::startup() Oh no, tiny elvis, threads not implemented");
00544 }
00545 }
00546
00547
00548 void Node::buildSequencers() {
00549 HomePatchList *hpl = PatchMap::Object()->homePatchList();
00550 ResizeArrayIter<HomePatchElem> ai(*hpl);
00551
00552
00553 if ( ! CkMyPe() ) {
00554 Controller *controller = new Controller(state);
00555 state->useController(controller);
00556 }
00557
00558
00559 for (ai=ai.begin(); ai != ai.end(); ai++) {
00560 HomePatch *patch = (*ai).patch;
00561 Sequencer *sequencer = new Sequencer(patch);
00562 patch->useSequencer(sequencer);
00563 }
00564 }
00565
00566
00567
00568
00569
00570
00571 void Node::messageRun() {
00572 (CProxy_Node(CkpvAccess(BOCclass_group).node)).run();
00573 }
00574
00575
00576
00577
00578
00579
00580 void Node::run()
00581 {
00582
00583 if ( ! CkMyPe() ) {
00584 state->runController();
00585 }
00586
00587 DebugM(4, "Starting Sequencers\n");
00588
00589 HomePatchList *hpl = PatchMap::Object()->homePatchList();
00590 ResizeArrayIter<HomePatchElem> ai(*hpl);
00591 for (ai=ai.begin(); ai != ai.end(); ai++) {
00592 HomePatch *patch = (*ai).patch;
00593 patch->runSequencer();
00594 }
00595
00596 if (!CkMyPe()) {
00597 double newTime = CmiWallTimer();
00598 iout << iINFO << "Startup phase " << startupPhase-1 << " took "
00599 << newTime - startupTime << " s, "
00600 << memusage_MB() << " MB of memory in use\n";
00601 iout << iINFO << "Finished startup at " << newTime << " s, "
00602 << memusage_MB() << " MB of memory in use\n\n" << endi;
00603 fflush(stdout);
00604 }
00605
00606 }
00607
00608
00609
00610
00611
00612
00613 void Node::enableScriptBarrier() {
00614 CkStartQD(CkIndex_Node::scriptBarrier((CkQdMsg*)0),&thishandle);
00615 }
00616
00617 void Node::scriptBarrier(CkQdMsg *qmsg) {
00618 delete qmsg;
00619
00620 }
00621
00622 void Node::scriptParam(ScriptParamMsg *msg) {
00623 simParameters->scriptSet(msg->param,msg->value);
00624 delete msg;
00625 }
00626
00627 void Node::reloadCharges(const char *filename) {
00628 FILE *file = fopen(filename,"r");
00629 if ( ! file ) NAMD_die("node::reloadCharges():Error opening charge file.");
00630
00631 int n = molecule->numAtoms;
00632 float *charge = new float[n];
00633
00634 for ( int i = 0; i < n; ++i ) {
00635 if ( ! fscanf(file,"%f",&charge[i]) )
00636 NAMD_die("Node::reloadCharges():Not enough numbers in charge file.");
00637 }
00638
00639 fclose(file);
00640 CProxy_Node(thisgroup).reloadCharges(charge,n);
00641 delete [] charge;
00642 }
00643
00644 void Node::reloadCharges(float charge[], int n) {
00645 molecule->reloadCharges(charge,n);
00646 }
00647
00648
00649 void Node::sendEnableExitScheduler(void) {
00650
00651 CkQdMsg *msg = new CkQdMsg;
00652 CProxy_Node nodeProxy(thisgroup);
00653 nodeProxy[0].recvEnableExitScheduler(msg);
00654 }
00655
00656 void Node::recvEnableExitScheduler(CkQdMsg *msg) {
00657
00658 delete msg;
00659 enableExitScheduler();
00660 }
00661
00662 void Node::enableExitScheduler(void) {
00663 if ( CkMyPe() ) {
00664 sendEnableExitScheduler();
00665 } else {
00666 CkStartQD(CkIndex_Node::exitScheduler((CkQdMsg*)0),&thishandle);
00667 }
00668 }
00669
00670 void Node::exitScheduler(CkQdMsg *msg) {
00671
00672 CsdExitScheduler();
00673 delete msg;
00674 }
00675
00676 void Node::sendEnableEarlyExit(void) {
00677 CkQdMsg *msg = new CkQdMsg;
00678 CProxy_Node nodeProxy(thisgroup);
00679 nodeProxy[0].recvEnableEarlyExit(msg);
00680 }
00681
00682 void Node::recvEnableEarlyExit(CkQdMsg *msg) {
00683 delete msg;
00684 enableEarlyExit();
00685 }
00686
00687 void Node::enableEarlyExit(void) {
00688 if ( CkMyPe() ) {
00689 sendEnableEarlyExit();
00690 } else {
00691 CkStartQD(CkIndex_Node::earlyExit((CkQdMsg*)0),&thishandle);
00692 }
00693 }
00694
00695 void Node::earlyExit(CkQdMsg *msg) {
00696 iout << iERROR << "Exiting prematurely; see error messages above.\n" << endi;
00697 BackEnd::exit();
00698 delete msg;
00699 }
00700
00701
00702
00703
00704
00705 void Node::saveMolDataPointers(NamdState *state)
00706 {
00707 this->molecule = state->molecule;
00708 this->parameters = state->parameters;
00709 this->simParameters = state->simParameters;
00710 this->configList = state->configList;
00711 this->pdb = state->pdb;
00712 this->state = state;
00713 }
00714
00715
00716 void Node::startHPM() {
00717 #if USE_HPM
00718 HPM_Start("500 steps", localRankOnNode);
00719 #endif
00720 }
00721
00722 void Node::stopHPM() {
00723 #if USE_HPM
00724 HPM_Stop("500 steps", localRankOnNode);
00725 HPM_Print(CkMyPe(), localRankOnNode);
00726 #endif
00727 }
00728
00729
00730
00731
00732
00733 #include "Node.def.h"
00734