Tool *UIVR::create_tool(const char *type) { Displayable *parent = &(app->scene->root); Tool *newtool = NULL; if(!strupncmp(type, "grab", 10)) newtool = new GrabTool(tool_serialno++, app, parent); else if(!strupncmp(type, "joystick", 10)) newtool = new JoystickTool(tool_serialno++, app, parent); else if(!strupncmp(type, "tug", 10)) newtool = new TugTool(tool_serialno++,app, parent); else if(!strupncmp(type, "pinch", 10)) newtool = new PinchTool(tool_serialno++,app, parent); else if(!strupncmp(type, "spring", 10)) newtool = new SpringTool(tool_serialno++,app, parent); else if(!strupncmp(type, "print", 10)) newtool = new PrintTool(tool_serialno++, app, parent); #ifdef VMDVRPN // XXX why is only this tool protected by the ifdef?? else if(!strupncmp(type, "rotate", 10)) newtool = new RotateTool(tool_serialno++,app, parent); #endif else { msgErr << "Unrecognized tool type " << type << sendmsg; msgErr << "possiblities are:"; for(int i=0;i<num_tool_types();i++) msgErr << " " << tool_types.name(i); msgErr << sendmsg; return NULL; } newtool->On(); newtool->grabs = 0; return newtool; }
static int replacefileextension(char * s, const char * oldextension, const char * newextension) { int sz, extsz; sz = strlen(s); extsz = strlen(oldextension); if (strlen(newextension) != strlen(oldextension)) return -1; if (extsz > sz) return -1; if (strupncmp(s + (sz - extsz), oldextension, extsz)) { return -1; } strcpy(s + (sz - extsz), newextension); return 0; }
int text_cmd_user(ClientData cd, Tcl_Interp *interp, int argc, const char *argv[]) { VMDApp *app = (VMDApp *)cd; if(argc < 3) { Tcl_SetResult(interp, (char *) "user list keys\n" "user print keys\n" "user add key <character> <command>", TCL_STATIC); return TCL_ERROR; } if(!strupncmp(argv[1], "add", CMDLEN)) { if (!strupncmp(argv[2], "key", CMDLEN)) { if(argc < 5) return TCL_ERROR; // check this is a valid string if (check_canonical_form(argv[3])) { const char *combstr = argv[4]; const char *desc = NULL; if (argc > 5) desc = argv[5]; int indx = app->userKeys.typecode(argv[3]); if (indx < 0) { app->userKeys.add_name(argv[3], stringdup(combstr)); } else { delete [] app->userKeys.data(indx); app->userKeys.set_data(indx, stringdup(combstr)); } if (desc) { indx = app->userKeyDesc.typecode(argv[3]); if (indx < 0) { app->userKeyDesc.add_name(argv[3], stringdup(desc)); } else { delete [] app->userKeyDesc.data(indx); app->userKeys.set_data(indx, stringdup(desc)); } } } else { Tcl_AppendResult(interp, "user key ", argv[3], " is not valid", NULL); return TCL_ERROR; } } else return TCL_ERROR; } else if(!strupncmp(argv[1], "list", CMDLEN)) { // return definitions of current items if (argc != 3) { return TCL_ERROR; } if (!strcmp(argv[2], "keys")) { int num = app->userKeys.num(); for (int i=0; i<num; i++) { // return tuples of {keystroke command description} Tcl_AppendResult(interp, i==0?"":" ", "{", NULL); Tcl_AppendElement(interp, app->userKeys.name(i)); Tcl_AppendElement(interp, (const char *) app->userKeys.data(i)); int desc_typecode = app->userKeyDesc.typecode(app->userKeys.name(i)); if (desc_typecode >= 0) { Tcl_AppendElement(interp, (const char *) app->userKeyDesc.data(i)); } else { Tcl_AppendElement(interp, ""); } Tcl_AppendResult(interp, "}", NULL); } return TCL_OK; } else { return TCL_ERROR; } // will never get here } else if(!strupncmp(argv[1], "print", CMDLEN)) { // print out definitions of current items Tcl_AppendResult(interp, "Keyboard shortcuts:\n", "-------------------\n", NULL); for (int i=0; i<app->userKeys.num(); i++) { const char *key = app->userKeys.name(i); Tcl_AppendResult(interp, "'", key, "' : ", app->userKeys.data(i), "\n", NULL); if (app->userKeyDesc.typecode(key) >= 0) { Tcl_AppendResult(interp, " Description: ", app->userKeyDesc.data(key), NULL); } } } else return TCL_ERROR; // if here, everything worked out ok return TCL_OK; }
int text_cmd_plugin(ClientData cd, Tcl_Interp *interp, int argc, const char *argv[]) { VMDApp *app = (VMDApp *)cd; if (!app) return TCL_ERROR; // plugin dlopen <filename> if (argc == 3 && !strupncmp(argv[1], "dlopen", CMDLEN)) { int rc = app->plugin_dlopen(argv[2]); if (rc < 0) { Tcl_AppendResult(interp, "Unable to dlopen plugin file ", argv[2], NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } // plugin update -- updates list of plugins if (argc == 2 && !strupncmp(argv[1], "update", CMDLEN)) { app->plugin_update(); return TCL_OK; } // plugin list [type]: returns list of category/name pairs. If optional // type is specified, return only plugins of that type. if ((argc == 2 || argc == 3) && !strupncmp(argv[1], "list", CMDLEN)) { const char *type = NULL; if (argc == 3) type = argv[2]; PluginList pluginlist; app->list_plugins(pluginlist, type); const int num = pluginlist.num(); Tcl_Obj *result = Tcl_NewListObj(0, NULL); for (int i=0; i<num; i++) { vmdplugin_t *p = pluginlist[i]; Tcl_Obj *listelem = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, listelem, Tcl_NewStringObj(p->type,-1)); Tcl_ListObjAppendElement(interp, listelem, Tcl_NewStringObj(p->name,-1)); Tcl_ListObjAppendElement(interp, result, listelem); } Tcl_SetObjResult(interp, result); return TCL_OK; } // plugin info <type> <name> <varname> // Puts plugin information for the specified plugin into the array variable // specified by varname. The following array keys will be used: type, // name, author, majorversion, minorversion, reentrant. // returns 1 if plugin information was found, or 0 if no plugin information // is available for that type and name. if (argc == 5 && !strupncmp(argv[1], "info", CMDLEN)) { vmdplugin_t *p = app->get_plugin(argv[2], argv[3]); if (!p) { Tcl_SetResult(interp, (char *) "0", TCL_STATIC); return TCL_OK; } char major[32], minor[32], reentrant[32]; sprintf(major, "%d", p->majorv); sprintf(minor, "%d", p->minorv); sprintf(reentrant, "%d", p->is_reentrant); if (!Tcl_SetVar2(interp,argv[4], "type", p->type, TCL_LEAVE_ERR_MSG) || !Tcl_SetVar2(interp,argv[4], "name", p->name, TCL_LEAVE_ERR_MSG) || !Tcl_SetVar2(interp,argv[4], "author", p->author, TCL_LEAVE_ERR_MSG) || !Tcl_SetVar2(interp,argv[4], "majorversion", major, TCL_LEAVE_ERR_MSG) || !Tcl_SetVar2(interp,argv[4], "minorversion", minor, TCL_LEAVE_ERR_MSG) || !Tcl_SetVar2(interp,argv[4], "reentrant", reentrant, TCL_LEAVE_ERR_MSG)) { Tcl_AppendResult(interp, "Unable to return plugin information in variable ", argv[4], NULL); return TCL_ERROR; } Tcl_SetResult(interp, (char *) "1", TCL_STATIC); return TCL_OK; } Tcl_AppendResult(interp, "Usage: \n\tplugin dlopen <filename> -- Load plugins from a dynamic library\n", "\tplugin update -- Update the list of plugins in the GUI\n", "\tplugin list [<plugin type>] -- List all plugins of the given type\n", "\tplugin info <type> <name> <arrayname> -- Store info about plugin in array\n", NULL); return TCL_ERROR; }
extern "C" void *vmd_mpi_parallel_for_scheduler(void *voidparms) { parallel_for_parms *parfor = (parallel_for_parms *) voidparms; // Run the for loop management code on node zero. // Do the work on all the other nodes... #if defined(VMDTHREADS) int i; wkf_tasktile_t curtile; while (wkf_shared_iterator_next_tile(&parfor->iter, 1, &curtile) != WKF_SCHED_DONE) { i = curtile.start; #else int i; for (i=parfor->loop.start; i<parfor->loop.end; i++) { #endif int reqnode; MPI_Status rcvstat; MPI_Recv(&reqnode, 1, MPI_INT, MPI_ANY_SOURCE, VMD_MPI_TAG_FOR_REQUEST, MPI_COMM_WORLD, &rcvstat); MPI_Send(&i, 1, MPI_INT, reqnode, VMD_MPI_TAG_FOR_REQUEST, MPI_COMM_WORLD); } // tell all nodes we're done with all of the work int node; for (node=1; node<parfor->numnodes; node++) { int reqnode; MPI_Status rcvstat; MPI_Recv(&reqnode, 1, MPI_INT, MPI_ANY_SOURCE, VMD_MPI_TAG_FOR_REQUEST, MPI_COMM_WORLD, &rcvstat); i=-1; // indicate that the for loop is completed MPI_Send(&i, 1, MPI_INT, reqnode, VMD_MPI_TAG_FOR_REQUEST, MPI_COMM_WORLD); } return NULL; } #endif int text_cmd_parallel(ClientData cd, Tcl_Interp *interp, int argc, const char *argv[]) { VMDApp *app = (VMDApp *)cd; if(argc<2) { Tcl_SetResult(interp, (char *) "Parallel job query commands:\n" " parallel nodename\n" " parallel noderank\n" " parallel nodecount\n" "Parallel collective operations (all nodes MUST participate):\n" " parallel allgather <object>\n" " parallel allreduce <tcl reduction proc> <object>\n" " parallel barrier\n" " parallel for <startcount> <endcount> <tcl callback proc> <user data>", TCL_STATIC); return TCL_ERROR; } // XXX hack to make Swift/T cooperate with VMD when using VMD's MPI // communicator if (!strcmp(argv[1], "swift_clone_communicator")) { swift_mpi_init(interp); return TCL_OK; } // return the MPI node name if (!strcmp(argv[1], "nodename")) { Tcl_Obj *tcl_result = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj(app->par_name(), strlen(app->par_name()))); Tcl_SetObjResult(interp, tcl_result); return TCL_OK; } // return the MPI node rank if (!strcmp(argv[1], "noderank")) { Tcl_Obj *tcl_result = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewIntObj(app->par_rank())); Tcl_SetObjResult(interp, tcl_result); return TCL_OK; } // return the MPI node count if (!strcmp(argv[1], "nodecount")) { Tcl_Obj *tcl_result = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewIntObj(app->par_size())); Tcl_SetObjResult(interp, tcl_result); return TCL_OK; } // execute an MPI barrier if(!strupncmp(argv[1], "barrier", CMDLEN) && argc==2) { app->par_barrier(); return TCL_OK; } // Execute a parallel for loop across all nodes // // parallel for <startcount> <endcount> <callback proc> <user data>", // if(!strupncmp(argv[1], "for", CMDLEN)) { int isok = (argc == 6); int N = app->par_size(); int start, end; if (Tcl_GetInt(interp, argv[2], &start) != TCL_OK || Tcl_GetInt(interp, argv[3], &end) != TCL_OK) { isok = 0; } // // If there's only one node, short-circuit the parallel for // if (N == 1) { if (!isok) { Tcl_SetResult(interp, (char *) "invalid parallel for, missing parameter", TCL_STATIC); return TCL_ERROR; } // run for loop on one node... int i; for (i=start; i<=end; i++) { char istr[128]; sprintf(istr, "%d", i); if (Tcl_VarEval(interp, argv[4], " ", istr, " {", argv[5], "} ", NULL) != TCL_OK) { Tcl_SetResult(interp, (char *) "error occured during parallel for", TCL_STATIC); } } return TCL_OK; } #if defined(VMDMPI) int allok = 0; // Check all node result codes before we continue with the reduction MPI_Allreduce(&isok, &allok, 1, MPI_INT, MPI_LAND, MPI_COMM_WORLD); // XXX we may want to verify that all nodes are going to call the same // reduction proc here before continuing further. if (!allok) { Tcl_SetResult(interp, (char *) "invalid parallel for, missing parameter on one or more nodes", TCL_STATIC); return TCL_ERROR; } // Run the for loop management code on node zero. // Do the work on all the other nodes... int i; if (app->par_rank() == 0) { // use multithreaded code path parallel_for_parms parfor; memset(&parfor, 0, sizeof(parfor)); parfor.numnodes = N; parfor.loop.start=start; parfor.loop.end=end+1; wkf_shared_iterator_init(&parfor.iter); wkf_shared_iterator_set(&parfor.iter, &parfor.loop); #if defined(VMDTHREADS) // run the MPI scheduler in a new child thread wkf_thread_t pft; wkf_thread_create(&pft, vmd_mpi_parallel_for_scheduler, &parfor); // run the Tcl in the main thread wkf_tasktile_t curtile; while (wkf_shared_iterator_next_tile(&parfor.iter, 1, &curtile) != WKF_SCHED_DONE) { i = curtile.start; char istr[128]; sprintf(istr, "%d", i); if (Tcl_VarEval(interp, argv[4], " ", istr, " {", argv[5], "} ", NULL) != TCL_OK) { Tcl_SetResult(interp, (char *) "error occured during parallel for", TCL_STATIC); } } // join up with the MPI scheduler thread wkf_thread_join(pft, NULL); #else // if no threads, node zero only runs the scheduler and doesn't do work vmd_mpi_parallel_for_scheduler(&parfor); #endif wkf_shared_iterator_destroy(&parfor.iter); } else { char istr[128]; int done=0; int mynode=app->par_rank(); while (!done) { MPI_Send(&mynode, 1, MPI_INT, 0, VMD_MPI_TAG_FOR_REQUEST, MPI_COMM_WORLD); MPI_Status rcvstat; MPI_Recv(&i, 1, MPI_INT, MPI_ANY_SOURCE, VMD_MPI_TAG_FOR_REQUEST, MPI_COMM_WORLD, &rcvstat); if (i == -1) { done = 1; } else { sprintf(istr, "%d", i); if (Tcl_VarEval(interp, argv[4], " ", istr, " {", argv[5], "} ", NULL) != TCL_OK) { Tcl_SetResult(interp, (char *) "error occured during parallel for", TCL_STATIC); } } } } #endif return TCL_OK; } // Execute an allgather producing a Tcl list of the per-node contributions // // parallel allgather <object> // if(!strupncmp(argv[1], "allgather", CMDLEN)) { int isok = (argc == 3); #if defined(VMDMPI) int allok = 0; int i; // Check all node result codes before we continue with the gather MPI_Allreduce(&isok, &allok, 1, MPI_INT, MPI_LAND, MPI_COMM_WORLD); if (!allok) { Tcl_SetResult(interp, (char *) "invalid parallel gather, missing parameter on one or more nodes", TCL_STATIC); return TCL_ERROR; } // Collect parameter size data so we can allocate result buffers // before executing the gather int *szlist = new int[app->par_size()]; szlist[app->par_rank()] = strlen(argv[2])+1; #if defined(USE_MPI_IN_PLACE) // MPI >= 2.x implementations (e.g. NCSA/Cray Blue Waters) MPI_Allgather(MPI_IN_PLACE, 1, MPI_INT, &szlist[0], 1, MPI_INT, MPI_COMM_WORLD); #else // MPI 1.x MPI_Allgather(&szlist[app->par_rank()], 1, MPI_INT, &szlist[0], 1, MPI_INT, MPI_COMM_WORLD); #endif int totalsz = 0; int *displist = new int[app->par_size()]; for (i=0; i<app->par_size(); i++) { displist[i]=totalsz; totalsz+=szlist[i]; } char *recvbuf = new char[totalsz]; memset(recvbuf, 0, totalsz); // Copy this node's data into the correct array position strcpy(&recvbuf[displist[app->par_rank()]], argv[2]); // Perform the parallel gather #if defined(USE_MPI_IN_PLACE) // MPI >= 2.x implementations (e.g. NCSA/Cray Blue Waters) MPI_Allgatherv(MPI_IN_PLACE, szlist[app->par_rank()], MPI_BYTE, &recvbuf[0], szlist, displist, MPI_BYTE, MPI_COMM_WORLD); #else // MPI 1.x MPI_Allgatherv(&recvbuf[displist[app->par_rank()]], szlist[app->par_rank()], MPI_BYTE, &recvbuf[0], szlist, displist, MPI_BYTE, MPI_COMM_WORLD); #endif // Build Tcl result from the array of results Tcl_Obj *tcl_result = Tcl_NewListObj(0, NULL); for (i=0; i<app->par_size(); i++) { Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj(&recvbuf[displist[i]], szlist[i]-1)); } Tcl_SetObjResult(interp, tcl_result); delete [] recvbuf; delete [] displist; delete [] szlist; return TCL_OK; #else if (!isok) { Tcl_SetResult(interp, (char *) "invalid parallel gather, missing parameter on one or more nodes", TCL_STATIC); return TCL_ERROR; } Tcl_Obj *tcl_result = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, tcl_result, Tcl_NewStringObj(argv[2], strlen(argv[2]))); Tcl_SetObjResult(interp, tcl_result); return TCL_OK; #endif } // // Execute an All-Reduce across all of the nodes. // The user must provide a Tcl proc that performs the appropriate reduction // operation for a pair of data items, resulting in a single item. // Since the user may pass floating point data or perform reductions // that give very slightly different answers depending on the order of // operations, the architecture or the host, or whether reductions on // a given host are occuring on the CPU or on a heterogeneous accelerator // or GPU of some kind, we must ensure that all nodes get a bit-identical // result. When heterogeneous accelerators are involved, we can really // only guarantee this by implementing the All-Reduce with a // Reduce-then-Broadcast approach, where the reduction collapses the // result down to node zero, which then does a broadcast to all peers. // // parallel allreduce <tcl reduction proc> <object> // if(!strupncmp(argv[1], "allreduce", CMDLEN)) { int isok = (argc == 4); int N = app->par_size(); // // If there's only one node, short-circuit the full parallel reduction // if (N == 1) { if (!isok) { Tcl_SetResult(interp, (char *) "invalid parallel reduction, missing parameter", TCL_STATIC); return TCL_ERROR; } // return our result, no other reduction is necessary Tcl_SetObjResult(interp, Tcl_NewStringObj(argv[3], strlen(argv[3]))); return TCL_OK; } #if 1 && defined(VMDMPI) // // All-Reduce implementation based on a ring reduction followed by a // broadcast from node zero. This implementation gaurantees strict // ordering and will properly handle the case where one or more nodes // perform their reduction with slightly differing floating point // rounding than others (e.g. using GPUs, heterogeneous nodes, etc), // and it works with any number of nodes. While NOT latency-optimal, // this implementation is close to bandwidth-optimal which is helpful // for workstation clusters on non-switched networks or networks with // switches that cannot operate in a fully non-blocking manner. // int allok = 0; // Check all node result codes before we continue with the reduction MPI_Allreduce(&isok, &allok, 1, MPI_INT, MPI_LAND, MPI_COMM_WORLD); // XXX we may want to verify that all nodes are going to call the same // reduction proc here before continuing further. if (!allok) { Tcl_SetResult(interp, (char *) "invalid parallel reduction, missing parameter on one or more nodes", TCL_STATIC); return TCL_ERROR; } // copy incoming data into initial "result" object Tcl_Obj *resultobj = Tcl_NewStringObj((const char *) argv[3], strlen(argv[3])+1); // A ring-based all-reduce implementation which should be // close to bandwidth-optimal, at the cost of additional latency. int src=app->par_rank(); // src node is this node int Ldest = (N + src + 1) % N; // compute left peer int Rdest = (N + src - 1) % N; // compute right peer MPI_Status status; if (src != 0) { int recvsz = 0; // Post blocking receive for data size MPI_Recv(&recvsz, 1, MPI_INT, Ldest, VMD_MPI_TAG_ALLREDUCE_ARGLENGTH, MPI_COMM_WORLD, &status); // Allocate or resize receive buffer char * recvbuf = (char *) malloc(recvsz); // Post non-blocking receive for data MPI_Recv(recvbuf, recvsz, MPI_BYTE, Ldest, VMD_MPI_TAG_ALLREDUCE_PAYLOAD, MPI_COMM_WORLD, &status); // Perform reduction // Perform the reduction operation on our existing and incoming data. // We build a Tcl command string with the user-defined proc, this // node's previous resultand, and the incoming data, and evaluate it. if (Tcl_VarEval(interp, argv[2], " ", Tcl_GetString(resultobj), " ", recvbuf, NULL) != TCL_OK) { printf("Error occured during reduction!\n"); } // Prep for next reduction step. Set result object to result of // the latest communication/reduction phase. resultobj = Tcl_GetObjResult(interp); // Free the receive buffer free(recvbuf); } // // All nodes // char *sendbuf = Tcl_GetString(resultobj); int sendsz = strlen(sendbuf)+1; // Post blocking send for data size MPI_Send(&sendsz, 1, MPI_INT, Rdest, VMD_MPI_TAG_ALLREDUCE_ARGLENGTH, MPI_COMM_WORLD); // Post blocking send for data MPI_Send(sendbuf, sendsz, MPI_BYTE, Rdest, VMD_MPI_TAG_ALLREDUCE_PAYLOAD, MPI_COMM_WORLD); if (src == 0) { int recvsz = 0; // Post blocking receive for data size MPI_Recv(&recvsz, 1, MPI_INT, Ldest, VMD_MPI_TAG_ALLREDUCE_ARGLENGTH, MPI_COMM_WORLD, &status); // Allocate or resize receive buffer char * recvbuf = (char *) malloc(recvsz); // Post non-blocking receive for data MPI_Recv(recvbuf, recvsz, MPI_BYTE, Ldest, VMD_MPI_TAG_ALLREDUCE_PAYLOAD, MPI_COMM_WORLD, &status); // Perform reduction // Perform the reduction operation on our existing and incoming data. // We build a Tcl command string with the user-defined proc, this // node's previous result and the incoming data, and evaluate it. if (Tcl_VarEval(interp, argv[2], " ", Tcl_GetString(resultobj), " ", recvbuf, NULL) != TCL_OK) { printf("Error occured during reduction!\n"); } // Prep for next reduction step. Set result object to result of // the latest communication/reduction phase. resultobj = Tcl_GetObjResult(interp); // Free the receive buffer free(recvbuf); } // // Broadcast final result from root to peers // if (src == 0) { // update send buffer for root node before broadcast sendbuf = Tcl_GetString(resultobj); sendsz = strlen(sendbuf)+1; MPI_Bcast(&sendsz, 1, MPI_INT, 0, MPI_COMM_WORLD); MPI_Bcast(sendbuf, sendsz, MPI_BYTE, 0, MPI_COMM_WORLD); } else { int recvsz = 0; MPI_Bcast(&recvsz, 1, MPI_INT, 0, MPI_COMM_WORLD); // Allocate or resize receive buffer char * recvbuf = (char *) malloc(recvsz); MPI_Bcast(recvbuf, recvsz, MPI_BYTE, 0, MPI_COMM_WORLD); // Set the final Tcl result if necessary Tcl_SetObjResult(interp, Tcl_NewStringObj(recvbuf, recvsz-1)); // Free the receive buffer free(recvbuf); } return TCL_OK; #elif defined(VMDMPI) // // Power-of-two-only hypercube/butterfly/recursive doubling // All-Reduce implementation. This implementation can't be used // in the case that we have either a non-power-of-two node count or // in the case where we have heterogeneous processing units that may // yield different floating point rounding. For now we leave this // implementation in the code for performance comparisons until we work // out the changes necessary to make it closer to bandwidth-optimal, // heterogeneous-safe, and non-power-of-two capable. // int allok = 0; int i; // Check all node result codes before we continue with the reduction MPI_Allreduce(&isok, &allok, 1, MPI_INT, MPI_LAND, MPI_COMM_WORLD); // XXX we may want to verify that all nodes are going to call the same // reduction proc here before continuing further. if (!allok) { Tcl_SetResult(interp, (char *) "invalid parallel reduction, missing parameter on one or more nodes", TCL_STATIC); return TCL_ERROR; } // Calculate number of reduction phases required int log2N; for (log2N=0; N>1; N>>=1) { log2N++; // XXX bail out of we don't have a power-of-two node count, // at least until we implement 3-2 reduction phases if ((N & 1) && (N > 1)) { Tcl_SetResult(interp, (char *) "parallel allreduce only allowed for even power-of-two node count", TCL_STATIC); return TCL_ERROR; } } N = app->par_size(); // copy incoming data into initial "result" object Tcl_Obj *resultobj = Tcl_NewStringObj((const char *) argv[3], strlen(argv[3])+1); // An all-reduce tree with hypercube connectivity with // log2(N) communication/reduction phases. At each phase, we compute // the peer/destination node we will communicate with using an XOR of // our node ID with the current hypercube dimension. If we have an // incomplete hypercube topology (e.g. non-power-of-two node count), // we have to do special 3-2 communication rounds (not implemented yet). // The current implementation requires that all existing nodes // participate, and that they contribute a valid data item. // If we wish to support reductions where a node may not contribute, // we would need to handle that similarly to a peer node that doesn't // exist, but we would likely determine this during the parameter length // exchange step. int src=app->par_rank(); // src node is this node for (i=0; i<log2N; i++) { int mask = 1 << i; // generate bitmask to use in the XOR int dest = src ^ mask; // XOR src node with bitmask to find dest node Tcl_Obj *oldresultobj = resultobj; // track old result // Check to make sure dest node exists for non-power-of-two // node counts (an incomplete hypercube). If not, skip to the next // communication/reduction phase. if (dest < N) { char *sendbuf = Tcl_GetString(oldresultobj); int sendsz = strlen(sendbuf)+1; int recvsz = 0; MPI_Request handle; MPI_Status status; // // Exchange required receive buffer size for data exchange with peer // // Post non-blocking receive for data size MPI_Irecv(&recvsz, 1, MPI_INT, dest, VMD_MPI_TAG_ALLREDUCE_ARGLENGTH, MPI_COMM_WORLD, &handle); // Post blocking send for data size MPI_Send(&sendsz, 1, MPI_INT, dest, VMD_MPI_TAG_ALLREDUCE_ARGLENGTH, MPI_COMM_WORLD); // Wait for non-blocking receive of data size to complete MPI_Wait(&handle, &status); // printf("src[%d], dest[%d], value '%s', recvsz: %d\n", src, dest, sendbuf, recvsz); // Allocate or resize receive buffer char * recvbuf = (char *) malloc(recvsz); // // Exchange the data payload // // Post non-blocking receive for data MPI_Irecv(recvbuf, recvsz, MPI_BYTE, dest, VMD_MPI_TAG_ALLREDUCE_PAYLOAD, MPI_COMM_WORLD, &handle); // Post blocking send for data MPI_Send(sendbuf, sendsz, MPI_BYTE, dest, VMD_MPI_TAG_ALLREDUCE_PAYLOAD, MPI_COMM_WORLD); // Wait for receive of data MPI_Wait(&handle, &status); // Perform the reduction operation on our existing and incoming data. // We build a Tcl command string with the user-defined proc, this // node's previous result and the incoming data, and evaluate it. if (Tcl_VarEval(interp, argv[2], " ", sendbuf, " ", recvbuf, NULL) != TCL_OK) { printf("Error occured during reduction!\n"); } // Free the receive buffer free(recvbuf); // Prep for next reduction step. Set result object to result of // the latest communication/reduction phase. resultobj = Tcl_GetObjResult(interp); } } // Set the final Tcl result if necessary Tcl_SetObjResult(interp, resultobj); return TCL_OK; #endif }
int text_cmd_label(ClientData cd, Tcl_Interp *interp, int argc, const char *argv[]) { VMDApp *app = (VMDApp *)cd; if (argc < 2) { Tcl_SetResult(interp, (char *) "label add [Atoms|Bonds|Angles|Dihedrals] {atoms as <molid>/<atomid>}\n" "label addspring <molid> <atomid> <atomid> <k>\n" "label list -- return label categories\n" "label list <category> -- return id's of labels in given category\n" "label [show|hide|delete] <category> [index] -- \n\tControl specific label or all labels in category\n" "label graph <category> <index> -- Return a list of values for the given label\n\tfor all animation frames\n" "label textsize [<newsize>]\n" , TCL_STATIC); return TCL_ERROR; } if(!strupncmp(argv[1], "add", CMDLEN)) { if(argc > 3) { int n = argc-3; const char **items = argv+3; int *molid= new int[n]; int *atmid = new int[n]; int i; for(i=0; i < n; i++) { if (find_atom_from_name(interp, items[i], molid+i, atmid+i)) break; } int rc = -1; if(i == n) { // all successfully parsed rc = app->label_add(argv[2], argc-3, molid, atmid, NULL, 0.0f, 1); } delete [] molid; delete [] atmid; if (rc < 0) { Tcl_AppendResult(interp, "\nUnable to add label.", NULL); return TCL_ERROR; } } else return TCL_ERROR; } else if(!strupncmp(argv[1],"addspring",CMDLEN)) { /* add a spring */ if(argc != 6) { Tcl_AppendResult(interp, "usage: label addspring <molid> <atomid> <atomid> <k>", NULL); return TCL_ERROR; } int molid[2]; int atomid[2]; float k; sscanf(argv[2],"%d",molid); /* convert all of the args to numbers */ sscanf(argv[3],"%d",atomid); sscanf(argv[4],"%d",atomid+1); sscanf(argv[5],"%f",&k); molid[1]=molid[0]; if (app->label_add("Springs", 2, molid, atomid, NULL, k, 1) < 0) { Tcl_AppendResult(interp, "Unable to add spring.", NULL); return TCL_ERROR; } } else if(!strupncmp(argv[1], "list", CMDLEN)) { if(argc == 3) { int cat = app->geometryList->geom_list_index(argv[2]); if (cat < 0) { Tcl_AppendResult(interp, "graph list category '", argv[2], "' was not found", NULL); return TCL_ERROR; } // go through the list by hand GeomListPtr glist = app->geometryList->geom_list(cat); int gnum = glist->num(); char s[30]; GeometryMol *g; for (int i=0; i<gnum; i++) { g = (*glist)[i]; Tcl_AppendResult(interp, i==0 ? "" : " ", "{", NULL); for (int j=0; j<g->items(); j++) { // append the molecule id/atom index sprintf(s, "%d %d", g -> obj_index(j), g -> com_index(j)); Tcl_AppendElement(interp, s); } // and the value and the status sprintf(s, "%f", g->ok() ? g->calculate() : 0.0); Tcl_AppendElement(interp, s); Tcl_AppendElement(interp, g -> displayed() ? "show" : "hide"); Tcl_AppendResult(interp, "}", NULL); } return TCL_OK; } else if (argc == 2) { // return the main categories for (int i=0; i<app->geometryList -> num_lists(); i++) { Tcl_AppendElement(interp, app->geometryList -> geom_list_name(i)); } return TCL_OK; } else return TCL_ERROR; } else if(!strupncmp(argv[1], "show", CMDLEN) || !strupncmp(argv[1], "hide", CMDLEN)) { int item; if(argc == 3 || (argc == 4 && !strupncmp(argv[3], "all", CMDLEN))) item = (-1); else if(argc == 4) { if (Tcl_GetInt(interp, argv[3], &item) != TCL_OK) { Tcl_AppendResult(interp, " in label ", argv[1], NULL); return TCL_ERROR; } } else return TCL_ERROR; app->label_show(argv[2], item, !strupncmp(argv[1], "show", CMDLEN)); // XXX check return code } else if(!strupncmp(argv[1], "delete", CMDLEN)) { int item; if(argc == 3 || (argc == 4 && !strupncmp(argv[3], "all", CMDLEN))) { item = (-1); } else if(argc == 4) { if (Tcl_GetInt(interp, argv[3], &item) != TCL_OK) { Tcl_AppendResult(interp, " in label ", argv[1], NULL); return TCL_ERROR; } } else { return TCL_ERROR; } app->label_delete(argv[2], item); // XXX check return code } else if(!strupncmp(argv[1], "graph", CMDLEN) && argc > 3) { int item; if (Tcl_GetInt(interp, argv[3], &item) != TCL_OK) { return TCL_ERROR; }; // find the geometry int cat = app->geometryList->geom_list_index(argv[2]); if (cat < 0) { Tcl_AppendResult(interp, "Invalid geometry type: ", argv[2], NULL); return TCL_ERROR; } // get the correct geometry pointer GeomListPtr glist = app->geometryList -> geom_list(cat); int gnum = glist -> num(); if (item < 0 || item >= gnum) { sprintf(interp -> result, "label %s index %d out of range", argv[2], item); return TCL_ERROR; } // compute all the values GeometryMol *g = (*glist)[item]; if (!g->has_value()) { Tcl_AppendResult(interp, "Geometry type ", argv[2], " has no values to graph.", NULL); return TCL_ERROR; } ResizeArray<float> gValues(1024); if (!g->calculate_all(gValues)) { interp->result = (char *) "label has no value"; return TCL_ERROR; } if (argc > 4) { // save the values in the given filename const char *filename = argv[4]; FILE *outfile = fopen(filename, "w"); if (!outfile) { Tcl_AppendResult(interp, "Cannot write graph data to file ", filename, NULL); return TCL_ERROR; } for (int i=0; i<gValues.num(); i++) { fprintf(outfile, "%f %f\n", float(i), gValues[i]); } fclose(outfile); } else { char s[20]; for (int count = 0; count < gValues.num(); count++) { sprintf(s, "%f", gValues[count]); Tcl_AppendElement(interp, s); } } } else if (!strupncmp(argv[1], "textsize", CMDLEN)) { if (argc == 2) { // return the current size Tcl_SetObjResult(interp, Tcl_NewDoubleObj(app->label_get_textsize())); return TCL_OK; } else if (argc == 3) { // set new size double newsize = 1; if (Tcl_GetDouble(interp, argv[2], &newsize) != TCL_OK) return TCL_ERROR; if (!app->label_set_textsize((float) newsize)) { Tcl_AppendResult(interp, "label textsize: Unable to set size to ", argv[2], NULL); return TCL_ERROR; } } else { Tcl_SetResult(interp, "label textsize: wrong number of arguments", TCL_STATIC); return TCL_ERROR; } } else if (!strupncmp(argv[1], "textoffset", CMDLEN)) { if (argc == 4) { // return current offset; const char *geomtype = argv[2]; int geom; if (Tcl_GetInt(interp, argv[3], &geom) != TCL_OK) return TCL_ERROR; const float *offset = app->geometryList->getTextOffset(geomtype, geom); if (!offset) { Tcl_SetResult(interp, "label textoffset: Invalid geometry specified", TCL_STATIC); return TCL_ERROR; } Tcl_Obj *result = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, result, Tcl_NewDoubleObj(offset[0])); Tcl_ListObjAppendElement(interp, result, Tcl_NewDoubleObj(offset[1])); Tcl_SetObjResult(interp, result); } else if (argc == 5) { const char *geomtype = argv[2]; int geom; if (Tcl_GetInt(interp, argv[3], &geom) != TCL_OK) return TCL_ERROR; float x, y; if (sscanf(argv[4], "%f %f", &x, &y) != 2) { Tcl_AppendResult(interp, "Could not understand argument to label textoffset:", argv[2], NULL); return TCL_ERROR; } if (!app->label_set_textoffset(geomtype, geom, x, y)) { Tcl_SetResult(interp, "label textoffset: Invalid geometry specified", TCL_STATIC); return TCL_ERROR; } } else { Tcl_SetResult(interp, "label textoffset: wrong number of arguments", TCL_STATIC); return TCL_ERROR; } } else if (!strupncmp(argv[1], "textformat", CMDLEN)) { if (argc == 4) { // return current format const char *geomtype = argv[2]; int geom; if (Tcl_GetInt(interp, argv[3], &geom) != TCL_OK) return TCL_ERROR; const char *format = app->geometryList->getTextFormat(geomtype, geom); if (!format) { Tcl_SetResult(interp, "label textformat: Invalid geometry specified", TCL_STATIC); return TCL_ERROR; } Tcl_SetResult(interp, (char *)format, TCL_VOLATILE); } else if (argc == 5) { const char *geomtype = argv[2]; int geom; if (Tcl_GetInt(interp, argv[3], &geom) != TCL_OK) return TCL_ERROR; if (!app->label_set_textformat(geomtype, geom, argv[4])) { Tcl_SetResult(interp, "label textformat failed.", TCL_STATIC); return TCL_ERROR; } } else { Tcl_SetResult(interp, "label textoffset: wrong number of arguments", TCL_STATIC); return TCL_ERROR; } } return TCL_OK; }
int text_cmd_tool(ClientData cd, Tcl_Interp *interp, int argc, const char *argv[]) { VMDApp *app = (VMDApp *)cd; CommandQueue *cmdQueue = app->commandQueue; char buf[400]; if(argc<2) { Tcl_SetResult(interp, (char *) "tool create <type> [<name> [<name> ...]]\n" "tool change <type> [<toolid>]\n" "tool scale <scale> [<toolid>]\n" "tool scaleforce <scale> [<toolid>]\n" "tool offset <x> <y> <z> [<toolid>]\n" "tool delete [<toolid>]\n" #if 0 "tool info [<toolid>]\n" #endif "tool rep <toolid> <mol id> <rep id>\n" "tool adddevice <name> [<toolid>]\n" "tool removedevice <name> [<toolid>]\n" "tool callback on/off", TCL_STATIC); return TCL_ERROR; } /* creating a new tool with some number of USLs */ if(!strupncmp(argv[1], "create", CMDLEN) && argc>=3) { if (!app->tool_create(argv[2], argc-3, argv+3)) { Tcl_AppendResult(interp, "Failed to create new tool.", NULL); return TCL_ERROR; } return TCL_OK; } /* changing the tool but preserving the sensor */ if(!strupncmp(argv[1], "change", CMDLEN) && (argc==4 || argc==3)) { int i=0; if(argc==4) { // default to 0 if (Tcl_GetInt(interp, argv[3], &i) != TCL_OK) return TCL_ERROR; } if (!app->tool_change_type(i, argv[2])) { Tcl_AppendResult(interp, "Unable to change tool type.", NULL); return TCL_ERROR; } return TCL_OK; } /* Setting the scale of a tool */ if(!strupncmp(argv[1], "scale", CMDLEN) && (argc==3 || argc==4)) { int i=0; double dscale=0.0; float scale=0.0f; if(argc==4) { // default to 0 if (Tcl_GetInt(interp, argv[3], &i) != TCL_OK) return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[2], &dscale) != TCL_OK) return TCL_ERROR; scale = (float)dscale; if (app->tool_set_position_scale(i, scale)) { return TCL_OK; } Tcl_AppendResult(interp, "Unable to set position scale", NULL); return TCL_ERROR; } /* Setting the scale of the force on a tool */ if(!strupncmp(argv[1], "scaleforce", CMDLEN) && (argc==3 || argc==4)) { int i=0; double dscale=0; float scale=0; if(argc==4) { // default to 0 if (Tcl_GetInt(interp, argv[3], &i) != TCL_OK) return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[2], &dscale) != TCL_OK) return TCL_ERROR; scale = (float)dscale; if (app->tool_set_force_scale(i, scale)) return TCL_OK; Tcl_AppendResult(interp, "Unable to set force scale", NULL); return TCL_ERROR; } /* Setting the scale of the spring on a tool */ if(!strupncmp(argv[1], "scalespring", CMDLEN) && (argc==3 || argc==4)) { int i=0; double dscale=0; float scale=0; if(argc==4) { // default to 0 if (Tcl_GetInt(interp, argv[3], &i) != TCL_OK) return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[2], &dscale) != TCL_OK) return TCL_ERROR; scale = (float)dscale; if (app->tool_set_spring_scale(i, scale)) return TCL_OK; Tcl_AppendResult(interp, "Unable to set spring scale", NULL); return TCL_ERROR; } /* Setting the offset of a tool */ if(!strupncmp(argv[1], "offset", CMDLEN) && (argc==5 || argc==6)) { int i=0,j; double d_offset[3]; float offset[3]; if(argc==6) { // default to 0 if (Tcl_GetInt(interp, argv[5], &i) != TCL_OK) return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[2], &d_offset[0]) != TCL_OK) return TCL_ERROR; if (Tcl_GetDouble(interp, argv[3], &d_offset[1]) != TCL_OK) return TCL_ERROR; if (Tcl_GetDouble(interp, argv[4], &d_offset[2]) != TCL_OK) return TCL_ERROR; for(j=0;j<3;j++) offset[j] = (float)d_offset[j]; cmdQueue->runcommand(new CmdToolOffset(offset,i)); sprintf(buf,"Setting offset of tool %i.", i); Tcl_AppendResult(interp, buf, NULL); return TCL_OK; } /* deleting a tool */ if(!strupncmp(argv[1], "delete", CMDLEN) && (argc==3 || argc==2)) { int i=0; if(argc==3) { // default to 0 if (Tcl_GetInt(interp, argv[2], &i) != TCL_OK) return TCL_ERROR; } cmdQueue->runcommand(new CmdToolDelete(i)); sprintf(buf,"Deleting tool %i.\n",i); Tcl_AppendResult(interp, buf, NULL); return TCL_OK; } #if 0 // XXX /* getting info about a tool */ if(!strupncmp(argv[1], "info", CMDLEN) && (argc==3 || argc==2)) { int i=0; Tool *tool; if(argc==3) { // default to 0 if (Tcl_GetInt(interp, argv[2], &i) != TCL_OK) return TCL_ERROR; } tool = vmdGlobal.uiVR->gettool(i); if(tool==NULL) { Tcl_AppendResult(interp, "No such tool.", NULL); return TCL_ERROR; } sprintf(buf,"Info for tool %i (%s)\n",i,tool->type_name()); Tcl_AppendResult(interp,buf, NULL); const float *pos = tool->position(); const Matrix4 *rot = tool->orientation(); if(pos==NULL) { Tcl_AppendResult(interp, "Tool has no position!", NULL); return TCL_ERROR; } sprintf(buf,"Postion: %.2f %.2f %.2f\n" "Orientation: %.2f %.2f %.2f\n" " %.2f %.2f %.2f\n" " %.2f %.2f %.2f\n", pos[0],pos[1],pos[2], rot->mat[4*0+0],rot->mat[4*0+1],rot->mat[4*0+2], rot->mat[4*1+0],rot->mat[4*1+1],rot->mat[4*1+2], rot->mat[4*2+0],rot->mat[4*2+1],rot->mat[4*2+2]); Tcl_AppendResult(interp,buf, NULL); int j=0; char *devices[5]; const float *offset; float scale; offset = tool->getoffset(); if(offset==NULL) { Tcl_AppendResult(interp, "tool info:\n", "NULL Offset...?\n", NULL); return TCL_ERROR; } scale = tool->getscale(); tool->getdevices(devices); JString buf2; while(devices[j]!=NULL) { buf2 += devices[j++]; buf2 += " "; } sprintf(buf,"Scale: %.2f\n" "Offset: %.2f %.2f %.2f\n" "USL: %s\n", scale, offset[0], offset[1], offset[2], (const char *)buf2); Tcl_AppendResult(interp,buf, NULL); return TCL_OK; } #endif /* Assigning a representation to a tool */ if(!strupncmp(argv[1], "rep", CMDLEN)) { if (argc != 3 && argc != 5) { Tcl_AppendResult(interp, "tool rep usage:\n", "Usage: tool rep toolnum [molid repnum]", NULL); return TCL_ERROR; } int toolnum, molid, repnum; toolnum = atoi(argv[2]); if (argc == 5) { molid = atoi(argv[3]); repnum = atoi(argv[4]); } else { molid = repnum = -1; } cmdQueue->runcommand(new CmdToolRep(toolnum, molid, repnum)); return TCL_OK; } /* Adding a device to a tool */ if(!strupncmp(argv[1], "adddevice", CMDLEN) && (argc == 3 || argc == 4)) { int i=0; if(argc==4) { // default to 0 if (Tcl_GetInt(interp, argv[3], &i) != TCL_OK) return TCL_ERROR; } cmdQueue->runcommand(new CmdToolAddDevice(argv[2],i)); return TCL_OK; } /* Removing a device to a tool */ if(!strupncmp(argv[1], "removedevice", CMDLEN) && (argc == 3 || argc == 4)) { int i=0; if(argc==4) { // default to 0 if (Tcl_GetInt(interp, argv[3], &i) != TCL_OK) return TCL_ERROR; } cmdQueue->runcommand(new CmdToolDeleteDevice(argv[2],i)); return TCL_OK; } /* Turning on callbacks for a tool */ if(!strupncmp(argv[1], "callback", CMDLEN)) { if(argc==3) { int on=-1; if (Tcl_GetBoolean(interp, argv[2], &on) != TCL_OK) return TCL_ERROR; if(on!=-1) { cmdQueue->runcommand(new CmdToolCallback(on)); return TCL_OK; } } Tcl_AppendResult(interp," tool callback usage:\n", "Usage: tool callback on/off [<toolid>]",NULL); return TCL_ERROR; } return TCL_ERROR; }
int text_cmd_render(ClientData cd, Tcl_Interp *interp, int argc, const char *argv[]) { VMDApp *app = (VMDApp *)cd; if (argc >= 3) { char *extstr = NULL; if (argc > 3) extstr = combine_arguments(argc, argv, 3); if (!strupncmp(argv[1], "options", CMDLEN)) { const char *opt = app->filerender_option(argv[2], NULL); if (!opt) { Tcl_AppendResult(interp, "render:\n", "No rendering method '", argv[2], "' available.", NULL); return TCL_ERROR; } if (extstr == NULL) { //print the option Tcl_AppendResult(interp, opt, NULL); } else { app->filerender_option(argv[2], extstr); delete [] extstr; } return TCL_OK; } else if (!strupncmp(argv[1], "default", CMDLEN)) { const char *opt = app->filerender_default_option(argv[2]); if (!opt) { Tcl_AppendResult(interp, "render:\n", "No rendering method '", argv[2], "' available.", NULL); return TCL_ERROR; } Tcl_AppendResult(interp, opt, NULL); return TCL_OK; } else if (!strupncmp(argv[1], "hasaa", CMDLEN)) { CHECK_RENDER(argv[2]) Tcl_SetObjResult(interp, Tcl_NewIntObj(app->filerender_has_antialiasing(argv[2]))); return TCL_OK; } else if (!strupncmp(argv[1], "aasamples", CMDLEN)) { int aasamples = -1; if (argc ==4) { if (Tcl_GetInt(interp, argv[3], &aasamples) != TCL_OK) return TCL_ERROR; } CHECK_RENDER(argv[2]) Tcl_SetObjResult(interp, Tcl_NewIntObj(app->filerender_aasamples(argv[2], aasamples))); return TCL_OK; } else if (!strupncmp(argv[1], "aosamples", CMDLEN)) { int aosamples = -1; if (argc ==4) { if (Tcl_GetInt(interp, argv[3], &aosamples) != TCL_OK) return TCL_ERROR; } CHECK_RENDER(argv[2]) Tcl_SetObjResult(interp, Tcl_NewIntObj(app->filerender_aosamples(argv[2], aosamples))); return TCL_OK; } else if (!strupncmp(argv[1], "imagesize", CMDLEN)) { int w=0, h=0; CHECK_RENDER(argv[2]) if (argc == 4) { int listn; const char **listelem; if (Tcl_SplitList(interp, argv[3], &listn, &listelem) != TCL_OK) { return TCL_ERROR; } if (listn != 2) { Tcl_SetResult(interp, (char *) "Image size list must have two elements", TCL_STATIC); Tcl_Free((char *)listelem); } if (Tcl_GetInt(interp, listelem[0], &w) != TCL_OK || Tcl_GetInt(interp, listelem[1], &h) != TCL_OK) { Tcl_Free((char *)listelem); return TCL_ERROR; } Tcl_Free((char *)listelem); } else if (argc != 3 && argc > 4) { Tcl_SetResult(interp, (char *) "Usage: render imagesize <method> {width height}", TCL_STATIC); return TCL_ERROR; } if (!app->filerender_imagesize(argv[2], &w, &h)) { Tcl_SetResult(interp, (char *) "Unable to set/get image size.", TCL_STATIC); return TCL_ERROR; } char tmpstring[128]; sprintf(tmpstring, "%d %d", w, h); Tcl_SetResult(interp, tmpstring, TCL_VOLATILE); return TCL_OK; } else if (!strupncmp(argv[1], "hasimagesize", CMDLEN)) {
int text_cmd_menu(ClientData cd, Tcl_Interp *interp, int argc, const char *argv[]) { VMDApp *app = (VMDApp *)cd; int retval = TCL_OK; // make sure a menu was named if (argc < 2) retval = TCL_HELP; if (argc == 2 && !strupncmp(argv[1], "list", CMDLEN)) { // return a list of the available menus for (int i=0; i<app->num_menus(); i++) Tcl_AppendElement(interp, app->menu_name(i)); } #ifdef VMDTK else if (argc > 1 && !strupncmp(argv[1], "tk", CMDLEN)) { #ifndef MACVMD if ((argc == 5 || argc == 6 ) && !strupncmp(argv[2], "add", CMDLEN)) { VMDMenu *menu = new VMDTkMenu(argv[3], argv[4], app, interp); if (!app->add_menu(menu)) { delete menu; char buf[50]; sprintf(buf, "Unable to add menu %s.\n", argv[3]); Tcl_SetResult(interp, buf, TCL_VOLATILE); retval = TCL_ERROR; } else { // tell VMD that this is a menu extension if (argc==6) app->menu_add_extension(argv[3],argv[5]); else app->menu_add_extension(argv[3],argv[3]); // tell Tcl that a new menu extension has been added Tcl_SetVar(interp, "vmd_menu_extension", argv[3], TCL_GLOBAL_ONLY); } } else if ((argc == 5 || argc == 6 ) && !strupncmp(argv[2], "register", CMDLEN)) { VMDTkMenu *menu = new VMDTkMenu(argv[3], NULL, app, interp); menu->register_proc(argv[4]); if (!app->add_menu(menu)) { delete menu; char buf[50]; sprintf(buf, "Unable to add menu %s\n", argv[3]); Tcl_SetResult(interp, buf, TCL_VOLATILE); retval = TCL_ERROR; } else { // tell VMD that this is a menu extension if (argc==6) app->menu_add_extension(argv[3],argv[5]); else app->menu_add_extension(argv[3],argv[3]); // tell Tcl that a new menu extension has been added Tcl_SetVar(interp, "vmd_menu_extension", argv[3], TCL_GLOBAL_ONLY); } } else if (argc == 4 && !strupncmp(argv[2], "remove", CMDLEN)) { if (!app->remove_menu(argv[3])) { char buf[50]; sprintf(buf, "Unable to remove menu %s\n", argv[3]); Tcl_SetResult(interp, buf, TCL_VOLATILE); retval = TCL_ERROR; } else app->menu_remove_extension(argv[3]); } else retval = TCL_HELP; #else /* MACVMD just eats it, and does nothing presently */ #endif } #endif else if (argc == 4 && !strupncmp(argv[2], "selectmol", CMDLEN)) { // undocumented command for internal use only! int ind; if (Tcl_GetInt(interp, argv[3], &ind) != TCL_OK) retval = TCL_HELP; else app->menu_select_mol(argv[1], ind); } else if(argc == 3) { if(!strupncmp(argv[2],"on",CMDLEN)) app->menu_show(argv[1], 1); else if (!strupncmp(argv[2],"off",CMDLEN)) app->menu_show(argv[1], 0); else if (!strupncmp(argv[2],"loc",CMDLEN)) { int x, y; if (app->menu_location(argv[1], x, y)) { char buf[20]; sprintf(buf, "%d %d", x, y); Tcl_SetResult(interp, buf, TCL_VOLATILE); } else { Tcl_AppendResult(interp, "menu loc: menu '", argv[1], "' does not exist.", NULL); retval = TCL_ERROR; } } else if (!strupncmp(argv[2], "status", CMDLEN)) Tcl_AppendResult(interp, app->menu_status(argv[1]) ? "on" : "off", NULL); else retval = TCL_HELP; } else if (argc == 5 && !strupncmp(argv[2],"move",CMDLEN)) app->menu_move(argv[1], atoi(argv[3]), atoi(argv[4])); else retval = TCL_HELP; if (retval == TCL_HELP) { Tcl_SetResult(interp, (char *) "Usage:\n" "\tmenu list -- returns list of available menus\n" "\tmenu <name> on -- turn menu with given name on\n" "\tmenu <name> off -- turn menu with given name off\n" "\tmenu <name> status -- returns 'on' or 'off'\n" "\tmenu <name> loc -- returns current position of menu\n" "\tmenu <name> move x y -- move menu to given position\n" "\tmenu tk add <name> <tk window> [<menu path>]\n" "\t -- add Tk menu to Extensions\n" "\tmenu tk register <name> <procname> [<menu path>]\n" "\t -- same as 'add', but <procname> returns tk window handle.\n" "\tmenu tk remove <name> -- remove menu from Extensions\n" "The Tk 'menu' command is also available.", TCL_STATIC); retval = TCL_ERROR; } return retval; }
int text_cmd_mobile(ClientData cd, Tcl_Interp *interp, int argc, const char *argv[]) { VMDApp *app = (VMDApp *)cd; if (argc < 3 || argc > 6) { // if here, something went wrong, so return an error message mobile_usage(interp); return TCL_ERROR; } if (!strupncmp(argv[1], "mode", CMDLEN)) { int m1 = Mobile::OFF; // see if these are string values if (!strupncmp(argv[2], "off", CMDLEN)) m1 = Mobile::OFF; else if (!strupncmp(argv[2], "move", CMDLEN)) m1 = Mobile::MOVE; else if (!strupncmp(argv[2], "animate", CMDLEN)) m1 = Mobile::ANIMATE; else if (!strupncmp(argv[2], "tracker", CMDLEN)) m1 = Mobile::TRACKER; else if (!strupncmp(argv[2], "user", CMDLEN)) m1 = Mobile::USER; else mobile_usage(interp); // error if (!app->mobile_set_mode(m1)) { Tcl_AppendResult(interp, "Unable to set Mobile mode to ", argv[2], argc > 3 ? argv[3] : NULL, NULL); // if here, something went wrong, so return an error message mobile_usage(interp); return TCL_ERROR; } } else if(!strupncmp(argv[1], "port", CMDLEN)) { int port; if (sscanf(argv[2], "%d", &port) == 1) { if (!app->mobile_network_port(port)) { // if here, something went wrong, so return an error message mobile_usage(interp); return TCL_ERROR; } } else { // if here, something went wrong, so return an error message mobile_usage(interp); return TCL_ERROR; } } else if(!strupncmp(argv[1], "get", CMDLEN)) { if (!strupncmp(argv[2], "mode", CMDLEN)) { Tcl_AppendResult(interp, Mobile::get_mode_str((Mobile::MoveMode)app->mobile_get_mode()), NULL); } else if (!strupncmp(argv[2], "clientList", CMDLEN)) { ResizeArray <JString *>* ip; ResizeArray <JString *>* nick; ResizeArray <bool>* active; app->mobile_get_client_list( nick, ip, active); for (int i=0; i<nick->num(); i++) { Tcl_AppendResult(interp, " {", NULL); Tcl_AppendResult(interp, " {", NULL); // here's what we've got.. // (const char *)(*(*nick)[i]) // now to explain it.... // (const char *) Tcl_AppendResult needs a char* // (* ) We have a JString* in ResizeArray that we want to be a JString // (*nick) we have a ResizeArray ptr that we want to be a ResizeArray // [i] specific array elem Tcl_AppendResult(interp, (const char *)(*(*nick)[i]), NULL); Tcl_AppendResult(interp, "}", NULL); Tcl_AppendResult(interp, " {", NULL); Tcl_AppendResult(interp, (const char *)(*(*ip)[i]), NULL); Tcl_AppendResult(interp, "}", NULL); Tcl_AppendResult(interp, " {", NULL); char tmp[10]; sprintf(tmp, "%d", (*active)[i]); Tcl_AppendResult(interp, tmp, NULL); Tcl_AppendResult(interp, "}", NULL); Tcl_AppendResult(interp, " }", NULL); } } else if (!strupncmp(argv[2], "port", CMDLEN)) { char tmpstr[20]; sprintf(tmpstr, "%d", app->mobile_get_network_port()); Tcl_AppendResult(interp, tmpstr, NULL); } else if (!strupncmp(argv[2], "APIsupported", CMDLEN)) { char tmpstr[20]; sprintf(tmpstr, "%d", app->mobile_get_APIsupported()); Tcl_AppendResult(interp, tmpstr, NULL); } else mobile_usage(interp); // error } else if(!strupncmp(argv[1], "sendMsg", CMDLEN)) { if (argc >= 6) { if (!app->mobile_sendMsg(argv[2], argv[3], argv[4], argv[5])) { // if here, something went wrong, so return an error message mobile_usage(interp); return TCL_ERROR; } } else mobile_usage(interp); // error } else if(!strupncmp(argv[1], "set", CMDLEN)) { if (!strupncmp(argv[2], "activeClient", CMDLEN)) { if (argc >= 5) { if (!app->mobile_set_activeClient(argv[3], argv[4])) { // Tcl_AppendResult(interp, "Unable to set activeClient to ", // argv[2], argc > 3 ? argv[3] : NULL, NULL); // if here, something went wrong, so return an error message mobile_usage(interp); return TCL_ERROR; } } else mobile_usage(interp); // error } else mobile_usage(interp); // error } else { // if here, something went wrong, so return an error message mobile_usage(interp); return TCL_ERROR; } // if here, everything worked out ok return TCL_OK; }