Пример #1
0
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;
}
Пример #3
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;
}
Пример #4
0
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;
}
Пример #5
0
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
  }
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
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)) {
Пример #9
0
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;
}
Пример #10
0
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;
}