00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "utilities.h"
00027 #include "vmdsock.h"
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031
00032 #if defined(ARCH_AIX4)
00033 #include <strings.h>
00034 #endif
00035
00036 #if defined(__irix)
00037 #include <bstring.h>
00038 #endif
00039
00040 #if defined(__hpux)
00041 #include <time.h>
00042 #endif
00043
00044 #include "MSMSInterface.h"
00045 #include "Inform.h"
00046
00047 #define MIN_PORT 1357
00048 #define MAX_PORT 9457
00049
00050
00051 int MSMSInterface::find_free_port(void) {
00052
00053 void *sock = vmdsock_create();
00054 if (!sock) return 0;
00055
00056 int port = 0;
00057
00058 for (int i=MIN_PORT; i<=MAX_PORT; i++) {
00059 if (vmdsock_bind(sock, i) == 0) {
00060 port = i;
00061 break;
00062 }
00063 }
00064 vmdsock_destroy(sock);
00065
00066 if (port == 0) {
00067 msgErr << "Could not find an available port between " <<
00068 MIN_PORT << " and " << MAX_PORT << "." << sendmsg;
00069 }
00070 return port;
00071 }
00072
00073
00074 const char *MSMSInterface::server_name(void) {
00075 const char *msms = getenv("MSMSSERVER");
00076 if (!msms) {
00077 #ifdef _MSC_VER
00078 msms = "msms.exe";
00079 #else
00080 msms = "msms";
00081 #endif
00082 }
00083
00084 return msms;
00085 }
00086
00087
00088
00089 int MSMSInterface::start_msms(int port) {
00090 const char *msms = server_name();
00091 char *s = new char[strlen(msms) + 100];
00092 sprintf(s, "%s -no_area -socketPort %d &", msms, port);
00093 msgInfo << "Starting MSMS with: '" << s << "'" << sendmsg;
00094 vmd_system(s);
00095 delete [] s;
00096 return 1;
00097 }
00098
00099
00100
00101
00102 void *MSMSInterface::conn_to_service_port(int port) {
00103 void *sock;
00104
00105 sock = vmdsock_create();
00106 if (!sock) return NULL;
00107 if (vmdsock_connect(sock, "localhost", port)) {
00108 vmdsock_destroy(sock);
00109 sock = NULL;
00110 }
00111 return sock;
00112 }
00113
00114
00115 int MSMSInterface::compute_from_socket(float probe_radius, float density,
00116 int n, int *ids, float *xyzr, int *flgs,
00117 int ) {
00118 if (xyzr == NULL) {
00119 err = BAD_RANGE;
00120 return err;
00121 }
00122
00123
00124 int port = find_free_port();
00125 if (port == 0) {
00126 err = NO_PORTS;
00127 return err;
00128 }
00129
00130
00131 start_msms(port);
00132
00133
00134 for (int loop=0; loop<100; loop++) {
00135 msms_server = conn_to_service_port(port);
00136 if (!msms_server) {
00137 if (loop!=0 && !(loop%50)) {
00138 msgInfo << "Waiting for MSMS server ..." << sendmsg;
00139 }
00140 vmd_msleep(loop);
00141 } else {
00142 break;
00143 }
00144 }
00145
00146 if (msms_server == 0) {
00147 msgErr << "Could not connect to MSMS server. " <<
00148 "Please check that the program '" << server_name() <<
00149 "' exists and is executable, or set the environment variable " <<
00150 "MSMSSERVER to point to the correct binary." << sendmsg;
00151 err = NO_CONNECTION;
00152 return err;
00153 }
00154
00155
00156
00157
00158 if (!call_msms(probe_radius, density, n, xyzr, flgs)) {
00159 return err;
00160 }
00161
00162
00163 int t;
00164 int surface_count = 0;
00165 do {
00166 t = msms_ended();
00167
00168 switch (t) {
00169 case 5: get_triangulated_ses(surface_count++); break;
00170 case 1: close_server(COMPUTED); break;
00171 default: break;
00172 }
00173 } while (t!=1 && msms_server != 0);
00174
00175 if (err != COMPUTED) {
00176 return err;
00177 }
00178
00179
00180
00181
00182
00183
00184 if (ids != NULL) {
00185 for (int i=0; i<atomids.num(); i++) {
00186 atomids[i] = ids[atomids[i]];
00187 }
00188 }
00189 return COMPUTED;
00190 }
00191
00192
00193 int MSMSInterface::check_for_input(int secs, int reps, int stage) {
00194 for (int count = 0; count < reps; count++) {
00195 int ret = vmdsock_selread(msms_server, secs);
00196 if (ret > 0) {
00197 return 1;
00198 }
00199
00200 if (ret == 0) {
00201
00202 msgInfo << "Waiting for data from MSMS(" << stage << ") ..." << sendmsg;
00203 } else {
00204
00205 msgErr << "Unknown error " << ret << "with MSMS interface!" << sendmsg;
00206 perror("Did you press Control-C? : ");
00207 break;
00208 }
00209 }
00210
00211 vmdsock_destroy(msms_server);
00212 return 0;
00213 }
00214
00215
00216 char *MSMSInterface::get_message(char *buffer) {
00217 int i,j;
00218 char *car;
00219
00220 if (!check_for_input(1, 10, 1)) {
00221 return NULL;
00222 }
00223
00224 for (i=0,car=buffer; car-buffer<255; car++) {
00225 j=vmdsock_read(msms_server, car, 1);
00226 if (j!=-1) {
00227 i++;
00228 if (*car=='\n') {*car='\0';break;}
00229 }
00230 }
00231
00232 if (*car!='\0')
00233 buffer[255]='\0';
00234
00235 return(buffer);
00236 }
00237
00238
00239 int MSMSInterface::call_msms(float probe_radius, float density,
00240 int n, float *xyzr, int *flgs) {
00241 int mask1 = 0;
00242 int mask2 = 1;
00243 int flag = 1;
00244
00245 char buffer[256] = { 0 };
00246 if (!get_message(buffer)) {
00247 msgErr << "Couldn't send initialization to MSMS" << sendmsg;
00248 close_server(NO_INITIALIZATION);
00249 return 0;
00250 }
00251
00252 vmdsock_write(msms_server,(char *)&probe_radius, sizeof(float));
00253 vmdsock_write(msms_server,(char *)&density, sizeof(float));
00254 vmdsock_write(msms_server,(char *)&mask1, sizeof(int));
00255 vmdsock_write(msms_server,(char *)&mask2, sizeof(int));
00256 vmdsock_write(msms_server,(char *)&n, sizeof(int));
00257 for (int i=0; i<n; i++) {
00258 vmdsock_write(msms_server,(char *)(xyzr+4L*i) , 4L*sizeof(float));
00259
00260
00261 if (flgs) {
00262 vmdsock_write(msms_server, (char *)(flgs+i), sizeof(int));
00263 } else {
00264 vmdsock_write(msms_server, (char *)&flag, sizeof(int));
00265 }
00266 }
00267
00268 return 1;
00269 }
00270
00271
00272 int MSMSInterface::msms_ended(void) {
00273 char buffer[256] = { 0 };
00274 int nread = 0;
00275 char c = '\0';
00276 int i;
00277
00278
00279
00280
00281 if (!check_for_input(10, 12, 2)) {
00282 msgErr << "No information from MSMS.. giving up." << sendmsg;
00283 close_server(MSMS_DIED);
00284 return 1;
00285 }
00286
00287 while (1) {
00288
00289 if (!check_for_input(1, 4, 3)) {
00290 msgErr << "No data from MSMS.. giving up." << sendmsg;
00291 close_server(MSMS_DIED);
00292 return 1;
00293 }
00294
00295 i = vmdsock_read(msms_server, &c, 1);
00296 if (i != -1 && i > 0) {
00297 buffer[nread] = c;
00298 nread++;
00299 if (c == '\n') {
00300
00301 buffer[nread-1] = '\0';
00302 if (strcmp(buffer,"MSMS END")==0) return(1);
00303 if (strcmp(buffer,"MSMS RS")==0) return(2);
00304 if (strcmp(buffer,"MSMS CS")==0) return(3);
00305 if (strcmp(buffer,"MSMS SEND DOTS")==0) return(4);
00306 if (strcmp(buffer,"MSMS RCF")==0) return(5);
00307
00308 msgErr << "Unknown MSMS message: " << buffer << sendmsg;
00309 return 1;
00310 }
00311 } else {
00312
00313
00314
00315 if (nread == 0)
00316 msgErr << "No data from MSMS.. giving up." << sendmsg;
00317
00318 close_server(COMPUTED);
00319
00320 return 1;
00321 }
00322 }
00323 }
00324
00325
00326 int MSMSInterface::get_blocking(char *str, int nbytes) {
00327 int i=0, to_be_read;
00328 char *cptr=str;
00329
00330
00331 if (!check_for_input(3, 10, 4)) {
00332 msgErr << "Failed in MSMSInterface::get_blocking" << sendmsg;
00333 return -1;
00334 };
00335
00336 for (to_be_read = nbytes; to_be_read > 0; cptr += i) {
00337 i = vmdsock_read(msms_server, cptr, to_be_read);
00338
00339 if (i==-1)
00340 return(nbytes - to_be_read);
00341
00342 to_be_read -= i;
00343 }
00344
00345 return nbytes;
00346 }
00347
00348
00349
00350 void MSMSInterface::get_triangulated_ses(int component) {
00351 int i, i1, i2, nf, ns;
00352 char *buffer;
00353 float *bf;
00354 int *bi, s1, s2, max;
00355
00356
00357 i1=get_blocking((char *)&nf, sizeof(int));
00358 if (i1 < 0) { close_server(MSMS_DIED); return; }
00359
00360
00361 i1=get_blocking((char *)&ns, sizeof(int));
00362 if (i1 < 0) { close_server(MSMS_DIED); return; }
00363
00364 s1 = nf*5L*sizeof(int);
00365 s2 = ns*(6L*sizeof(float) + sizeof(int));
00366
00367 max = (s2>s1) ? s2:s1;
00368 buffer = (char *)malloc(max*sizeof(char) + 1);
00369 if (buffer==NULL) {
00370 msgErr << "MSMS: allocation failed for buffer" << sendmsg;
00371 return;
00372 }
00373
00374
00375 i1 = get_blocking(buffer, s1*sizeof(char));
00376 if (i1 < 0) { close_server(MSMS_DIED); free(buffer); return; }
00377 bi = (int *)buffer;
00378 for (i=0;i<nf;i++) {
00379 MSMSFace face;
00380 face.vertex[0]=*bi++;
00381 face.vertex[1]=*bi++;
00382 face.vertex[2]=*bi++;
00383 face.surface_type=*bi++;
00384 face.anaface=*bi++;
00385 face.component = component;
00386 faces.append(face);
00387 }
00388
00389
00390 i2 = get_blocking(buffer,s2*sizeof(char));
00391 if (i2 < 0) { close_server(MSMS_DIED); free(buffer); return; }
00392 bf = (float *)buffer;
00393 for (i=0; i<ns; i++) {
00394 MSMSCoord norm, coord;
00395 norm.x[0]=*bf++;
00396 norm.x[1]=*bf++;
00397 norm.x[2]=*bf++;
00398 coord.x[0]=*bf++;
00399 coord.x[1]=*bf++;
00400 coord.x[2]=*bf++;
00401 norms.append(norm);
00402 coords.append(coord);
00403 }
00404
00405
00406 bi = (int *)bf;
00407 for (i=0;i<ns;i++) {
00408 atomids.append(*bi++);
00409 }
00410
00411 free(buffer);
00412 }
00413
00414
00415
00416 void MSMSInterface::close_server(int erno) {
00417 if (msms_server != 0) {
00418 err = erno;
00419 vmdsock_destroy(msms_server);
00420 msms_server = 0;
00421 }
00422 }
00423
00424 void MSMSInterface::clear() {
00425 atomids.clear();
00426 faces.clear();
00427 coords.clear();
00428 norms.clear();
00429 }
00430
00431
00432 class VMDTempFile {
00433 private:
00434 const char *m_filename;
00435 public:
00436 VMDTempFile(const char *fname) {
00437 m_filename = stringdup(fname);
00438 }
00439 ~VMDTempFile() {
00440 vmd_delete_file(m_filename);
00441 delete [] m_filename;
00442 }
00443 };
00444
00445
00446 int MSMSInterface::compute_from_file(float probe_radius, float density,
00447 int n, int *ids, float *xyzr, int *flgs,
00448 int ) {
00449 const char *msmsbin = server_name();
00450
00451
00452 char *dirname = vmd_tempfile("");
00453 char *ofilename = new char[strlen(dirname) + 100];
00454 sprintf(ofilename, "%svmdmsms.u%d.%d",
00455 dirname, vmd_getuid(), (int)(vmd_random() % 999));
00456 delete [] dirname;
00457 FILE *ofile = fopen(ofilename, "wt");
00458 if (!ofile) {
00459 delete [] ofilename;
00460 msgErr << "Failed to create MSMS atom radii input file" << sendmsg;
00461 return 0;
00462 }
00463
00464
00465
00466 char *facetfilename = new char[strlen(ofilename) + 6];
00467 char *vertfilename = new char[strlen(ofilename) + 6];
00468 sprintf(facetfilename, "%s.face", ofilename);
00469 sprintf(vertfilename, "%s.vert", ofilename);
00470
00471
00472 VMDTempFile otemp(ofilename);
00473 VMDTempFile ftemp(facetfilename);
00474 VMDTempFile vtemp(vertfilename);
00475
00476
00477
00478
00479 for (int i=0; i<n; i++) {
00480 fprintf(ofile, "%f %f %f %f\n",
00481 xyzr[4L*i], xyzr[4L*i+1], xyzr[4L*i+2], xyzr[4L*i+3]);
00482 }
00483 fclose(ofile);
00484
00485
00486
00487
00488 {
00489 char *msmscmd = new char[2*strlen(ofilename) + strlen(msmsbin) + 100];
00490 sprintf(msmscmd, "\"%s\" -if %s -of %s -probe_radius %5.3f -density %5.3f -no_area -no_header", msmsbin, ofilename, ofilename, probe_radius, density);
00491 vmd_system(msmscmd);
00492 delete [] msmscmd;
00493 }
00494
00495
00496 FILE *facetfile = fopen(facetfilename, "r");
00497 if (!facetfile) {
00498 msgErr << "Cannot read MSMS facet file: " << facetfilename << sendmsg;
00499
00500 return 0;
00501 }
00502 MSMSFace face;
00503 while (fscanf(facetfile, "%d %d %d %d %d",
00504 face.vertex+0, face.vertex+1, face.vertex+2, &face.surface_type,
00505 &face.anaface) == 5) {
00506 face.component = 0;
00507 face.vertex[0]--;
00508 face.vertex[1]--;
00509 face.vertex[2]--;
00510 faces.append(face);
00511 }
00512 fclose(facetfile);
00513
00514
00515 FILE *vertfile = fopen(vertfilename, "r");
00516 if (!vertfile) {
00517 msgErr << "Cannot read MSMS vertex file: " << vertfilename << sendmsg;
00518 return 0;
00519 }
00520 MSMSCoord norm, coord;
00521 int atomid;
00522 int l0fa;
00523 int l;
00524 while (fscanf(vertfile, "%f %f %f %f %f %f %d %d %d",
00525 coord.x+0, coord.x+1, coord.x+2,
00526 norm.x+0, norm.x+1, norm.x+2,
00527 &l0fa, &atomid, &l) == 9) {
00528 norms.append(norm);
00529 coords.append(coord);
00530 atomids.append(atomid-1);
00531 }
00532 fclose(vertfile);
00533
00534 if (ids) {
00535 for (int i=0; i<atomids.num(); i++) {
00536 atomids[i] = ids[atomids[i]];
00537 }
00538 }
00539 return 1;
00540 }
00541