00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 #include <math.h>
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include "Measure.h"
00025 
00026 class Vector3D;
00027 class IndexList;
00028 class AtomData;
00029 class MolData;
00030 class AtomList;
00031 class AtomGrid;
00032 class GridList;
00033 class AtomGridCell;
00034 
00035 
00036 
00037 
00038 class Vector3D {
00039 public:
00040    const Vector3D operator+(const Vector3D w ) const {
00041       Vector3D v;
00042       v.x = x + w.x;
00043       v.y = y + w.y;
00044       v.z = z + w.z;
00045       return v;
00046    }
00047    
00048    const Vector3D operator-(const Vector3D w ) const {
00049       Vector3D v;
00050       v.x = x - w.x;
00051       v.y = y - w.y;
00052       v.z = z - w.z;
00053       return v;
00054    }
00055    
00056    const Vector3D operator*(double s) const {
00057       Vector3D v;
00058       v.x = s*x;
00059       v.y = s*y;
00060       v.z = s*z;
00061       return v;
00062    }
00063    
00064    double length() const { return sqrt(x*x + y*y + z*z); }
00065    double length2() const { return x*x + y*y + z*z; }
00066    double x,y,z;
00067 };
00068 
00069 Vector3D operator*(double s, Vector3D v) {
00070    v.x *= s;
00071    v.y *= s;
00072    v.z *= s;
00073    return v;
00074 }
00075 
00076 Vector3D operator/(Vector3D v, double s) {
00077    v.x /= s;
00078    v.y /= s;
00079    v.z /= s;
00080    return v;
00081 }
00082 
00083 
00084 
00085 
00086 class IndexList {
00087 public:
00088    IndexList() {
00089       num=0;
00090       maxnum=16;
00091       list = new int[16];
00092    }
00093    
00094    ~IndexList() {
00095       if (list != 0)
00096          delete [] list;
00097    }
00098    
00099    void add(const int val) {
00100       
00101       
00102       if (num == maxnum) {
00103          maxnum = (int)(maxnum * 1.5 + 1);
00104          int* oldlist = list;
00105          list = new int[maxnum];
00106          int i;
00107          for(i=0;i<num;i++) {
00108             list[i] = oldlist[i];
00109          }
00110          delete [] oldlist;
00111       }
00112       
00113       
00114       list[num] = val;
00115       num++;
00116    }
00117    
00118    int size() {
00119       return num;
00120    }
00121    
00122    int get(const int i) const { return list[i]; }
00123    
00124 private:
00125    int num;
00126    int maxnum;
00127    int* list;
00128 };
00129 
00130 
00131 
00132 
00133 class AtomData {
00134 public:
00135    int index;
00136    Vector3D coord;
00137 };
00138 
00139 
00140 
00141 
00142 
00143 
00144 class MolData {
00145 public:
00146    MolData() {
00147       coords = 0;
00148    }
00149    
00150    ~MolData() {
00151       if ( coords != 0) {
00152          delete [] coords;
00153       }
00154    }
00155    
00156    static MolData* readFile(const char* fname,
00157                             double gridspacing, double radius, double threshold);
00158 
00159    static MolData* readData(const int *indx, const float *coords, const int count,
00160                             const Vector3D o,
00161                             const Vector3D a, const Vector3D b, const Vector3D c,
00162                             const double gridspacing, const double radius, 
00163                             const double threshold,
00164                             const bool periodic);
00165    
00166    void wrapCoords(const AtomGrid* grid);
00167    
00168    AtomList* findAtomsGrid(const AtomGrid* grid);
00169    double getRadius() const { return radius; }
00170    double getActualRadius() const { return actual_radius; }
00171    
00172    double gridspacing;
00173    double radius;
00174    double threshold;
00175    double actual_radius;
00176    Vector3D origin;
00177    Vector3D basisa;
00178    Vector3D basisb;
00179    Vector3D basisc;
00180    int count;
00181    AtomData* coords;
00182    bool periodic;
00183 };
00184 
00185 
00186 
00187 
00188 
00189 class AtomList {
00190 public:
00191    AtomList(const int sz) {
00192       size = sz;
00193       index_list = new int[sz];
00194       count = 0;
00195    }
00196    
00197    ~AtomList() {
00198       if (index_list != 0) {
00199          delete [] index_list;
00200       }
00201    }
00202    
00203    void add(const int index) { index_list[count] = index; count++; }
00204    
00205    void storeFile(const char* fname) const 
00206    {
00207       FILE* outf = fopen(fname,"w");
00208       if (outf == NULL) {
00209          printf("Couldn't open file %s\n",fname);
00210          exit(-1);
00211       }
00212       
00213       int i;
00214       for(i=0; i < count; i++) {
00215          if (fprintf(outf,"%d\n",index_list[i]) < 0) {
00216             printf("Store file error %d %s\n",i,fname);
00217             exit(-2);
00218          }
00219       }
00220       
00221       fclose(outf);
00222       return;
00223    }
00224    
00225    void storeData(int **surf, int *surf_count) const 
00226    {
00227       *surf_count = count;
00228       *surf = new int[count];
00229       int i;
00230       for(i=0; i < count; i++) {
00231          (*surf)[i] = index_list[i];
00232       }
00233       
00234       return;
00235    }
00236    
00237 private:
00238    int* index_list;
00239    int count;
00240    int size;
00241 };
00242 
00243 
00244 
00245 
00246 
00247 class GridList {
00248 public:
00249    GridList(AtomGrid* thegrid, const int gridn)
00250    {
00251       n = gridn;
00252       if (n != 0)
00253          items = new Vector3D[n];
00254       else
00255          items = 0;
00256       
00257       indx = 0;
00258       grid = thegrid;
00259       shuffle_vec = scramble_array(n);
00260    }
00261    
00262    ~GridList() {
00263       if (items != 0)
00264          delete [] items;
00265       if (shuffle_vec != 0)
00266          delete [] shuffle_vec;
00267    }
00268    
00269    int add(const int i, const int j, const int k);
00270    Vector3D get(const int i) const {
00271       if (i < 0 || i >= n)
00272          return Vector3D(); 
00273       
00274       return items[i];
00275    }
00276    
00277    int getNum() const { return indx; }
00278    
00279 private:
00280    int n;
00281    int indx;
00282    AtomGrid* grid;
00283    int* shuffle_vec;
00284    Vector3D* items;
00285    static int* scramble_array(const int n);
00286 };
00287 
00288 
00289 
00290 
00291 
00292 
00293 class AtomGridCell {
00294 public:
00295    AtomGridCell(AtomGrid* in_ag, int in_mina, int in_maxa, int in_minb, 
00296                 int in_maxb, int in_minc, int in_maxc)
00297    {
00298       
00299       
00300       
00301       
00302       
00303       ag = in_ag;
00304       mina = in_mina;
00305       maxa = in_maxa;
00306       minb = in_minb;
00307       maxb = in_maxb;
00308       minc = in_minc;
00309       maxc = in_maxc;
00310       
00311       na = maxa-mina+1;
00312       nb = maxb-minb+1;
00313       nc = maxc-minc+1;
00314       
00315       noneset = true;
00316       getlistcalled = false;
00317       cellmap = 0;
00318       count=0;
00319       gridlist=0;
00320    }
00321    
00322    ~AtomGridCell()
00323    {
00324       if (cellmap != 0)
00325          delete [] cellmap;
00326    }
00327    
00328    int set(const int i, const int j, const int k);
00329    bool get(const int i, const int j, const int k) const;
00330    const GridList* get_list();
00331    
00332 private:
00333    void build_list();
00334    AtomGrid* ag;
00335    int mina;
00336    int maxa;
00337    int minb;
00338    int maxb;
00339    int minc;
00340    int maxc;
00341    int na;
00342    int nb;
00343    int nc;
00344    bool noneset;
00345    bool getlistcalled;
00346    bool* cellmap;
00347    int count;
00348    GridList* gridlist;
00349 };
00350 
00351 
00352 
00353 
00354 class AtomGrid {
00355 public:
00356    AtomGrid(const MolData* mdata);
00357    
00358    ~AtomGrid() {
00359       int i,j,k;
00360       for(i=0; i < cna; i++)
00361          for(j=0; j < cnb; j++)
00362             for(k=0; k < cnc; k++) {
00363                delete cellgrid[((i*cnb)+j)*cnc+k];
00364             }
00365       delete [] cellgrid;
00366       delete [] celli;
00367       delete [] cellj;
00368       delete [] cellk;
00369    }
00370    
00371    
00372    
00373    
00374    bool get(const int i, const int j, const int k) const 
00375    {
00376       
00377       bool ret;
00378       if (i >= 0 && i < na && j >= 0 && j < nb && k >= 0 && k < nc) {
00379          const int ii = celli[i];
00380          const int jj = cellj[j];
00381          const int kk = cellk[k];
00382          const int indx = ((ii*cnb)+jj)*cnc+kk;
00383          ret = cellgrid[indx]->get(i,j,k);
00384       } else {
00385          ret = false;
00386       }
00387       return ret;
00388    }
00389    
00390    
00391    
00392    
00393    int set(const int i, const int j, const int k) {
00394       
00395       if ( i < 0 || i >= na || j < 0 || j >= nb || k < 0 || k >= nc )
00396          return -1;
00397       
00398       const int ii = celli[i];
00399       const int jj = cellj[j];
00400       const int kk = cellk[k];
00401       return cellgrid[((ii*cnb)+jj)*cnc+kk]->set(i,j,k);
00402    }
00403    
00404    
00405    
00406    
00407    
00408    
00409    Vector3D get_ijk(const Vector3D vv) const 
00410    {
00411       Vector3D ijk;
00412       const Vector3D v = vv - origin;
00413       
00414       
00415       
00416       ijk.x = (inv_abc[0][0] * v.x + inv_abc[0][1] * v.y + inv_abc[0][2] * v.z)
00417          * na;
00418       ijk.y = (inv_abc[1][0] * v.x + inv_abc[1][1] * v.y + inv_abc[1][2] * v.z)
00419          * nb;
00420       ijk.z = (inv_abc[2][0] * v.x + inv_abc[2][1] * v.y + inv_abc[2][2] * v.z)
00421          * nc;
00422       
00423       return ijk;
00424    }
00425    
00426    
00427    
00428    
00429    
00430    
00431    void get_cijk(const Vector3D vv, int& i, int& j, int& k) const 
00432    {
00433       Vector3D ijk = get_ijk(vv);
00434       
00435       ijk.x = fmod(ijk.x,na);
00436       if (ijk.x < 0)
00437          ijk.x += na;
00438       ijk.y = fmod(ijk.y,nb);
00439       if (ijk.y < 0)
00440          ijk.y += nb;
00441       ijk.z = fmod(ijk.z,nc);
00442       if (ijk.z < 0)
00443          ijk.z += nc;
00444       
00445       i = celli[(int)(floor(ijk.x))];
00446       j = cellj[(int)(floor(ijk.y))];
00447       k = cellk[(int)(floor(ijk.z))];
00448       return;
00449    }
00450    
00451    
00452    
00453    
00454    
00455    
00456    Vector3D get_xyz(const Vector3D ijk) const
00457    {
00458       Vector3D v = grida * ijk.x / na + gridb * ijk.y / nb + gridc * ijk.z / nc 
00459       + origin;
00460       return v;
00461    }
00462    
00463    
00464    
00465    
00466    
00467    Vector3D get_xyz(const int i, const int j, const int k) const 
00468    {
00469       const double id = (i+0.5) / na;
00470       const double jd = (j+0.5) / nb;
00471       const double kd = (k+0.5) / nc;
00472       
00473       Vector3D v = grida * id + gridb * jd + gridc * kd + origin;
00474       return v;
00475    }
00476    
00477    
00478    
00479    
00480    
00481    const GridList* get_cell(const int i, const int j, const int k) const
00482    {
00483       if (i>=0 && i<cna && j>=0 && j<cnb && k>=0 && k<cnc) {
00484          return cellgrid[((i*cnb)+j)*cnc+k]->get_list();
00485       } 
00486       return 0;
00487    }
00488    
00489    Vector3D wrap_xyz(const Vector3D xyz) const
00490    {
00491       Vector3D gridcoord = get_ijk(xyz);
00492       gridcoord.x = fmod(gridcoord.x,na);
00493       if (gridcoord.x < 0)
00494          gridcoord.x += na;
00495       gridcoord.y = fmod(gridcoord.y,nb);
00496       if (gridcoord.y < 0)
00497          gridcoord.y += nb;
00498       gridcoord.z = fmod(gridcoord.z,nc);
00499       if (gridcoord.z < 0)
00500          gridcoord.z += nc;
00501       
00502       const Vector3D ret = get_xyz(gridcoord);
00503       
00504       
00505       
00506       
00507       
00508       return ret;
00509    }
00510    
00511    int get_na() const { return na; }
00512    int get_nb() const { return nb; }
00513    int get_nc() const { return nc; }
00514    
00515    int get_cna() const { return cna; }
00516    int get_cnb() const { return cnb; }
00517    int get_cnc() const { return cnc; }
00518    
00519    Vector3D findAtomBox(const double radius) const;
00520    void build(const MolData* mol_data);
00521    void store(char* fname);
00522    void print();
00523    static int* scramble_array(const int n);
00524    
00525 private:
00526       void Inverse3(const double m[3][3], double inv[3][3]) const;
00527    double Cofactor3(const double mat[3][3],const int i, const int j) const;
00528    
00529    
00530    Vector3D origin;
00531    Vector3D grida;
00532    Vector3D gridb;
00533    Vector3D gridc;
00534    double inv_abc[3][3];
00535    int na;
00536    int nb;
00537    int nc;
00538    
00539    int cna;
00540    int cnb;
00541    int cnc;
00542    AtomGridCell** cellgrid;
00543    int* celli;
00544    int* cellj;
00545    int* cellk;
00546    bool periodic;
00547 };
00548 
00549 
00550 MolData* MolData::readFile(const char* fname, double gridspacing, 
00551                            double radius, double threshold) {
00552   MolData *data = new MolData;
00553   data->gridspacing = gridspacing;
00554   data->radius = radius;
00555   data->threshold = threshold;
00556   data->actual_radius = radius+threshold;
00557    
00558    
00559   FILE* inpf = fopen(fname,"r");
00560   if (inpf == NULL) {
00561     printf("Couldn't open file %s\n",fname);
00562     exit(-1);
00563   }
00564    
00565   int n_read=0;
00566   n_read += fscanf(inpf,"%lf %lf %lf",
00567                    &(data->origin.x),&(data->origin.y),&(data->origin.z)); 
00568   n_read += fscanf(inpf,"%lf %lf %lf",
00569                    &(data->basisa.x),&(data->basisa.y),&(data->basisa.z)); 
00570   n_read += fscanf(inpf,"%lf %lf %lf",
00571                    &(data->basisb.x),&(data->basisb.y),&(data->basisb.z)); 
00572   n_read += fscanf(inpf,"%lf %lf %lf",
00573                    &(data->basisc.x),&(data->basisc.y),&(data->basisc.z));
00574   n_read += fscanf(inpf,"%d",&(data->count));
00575    
00576   if (n_read != 13) {
00577     printf("Error reading header (%d)",n_read);
00578     exit(-2);
00579   }
00580    
00581   data->coords = new AtomData[data->count];
00582   int i;
00583   for (i=0; i<data->count; i++) {
00584     n_read = fscanf(inpf,"%d %lf %lf %lf",
00585                     &(data->coords[i].index),
00586                     &(data->coords[i].coord.x),
00587                     &(data->coords[i].coord.y),
00588                     &(data->coords[i].coord.z));
00589     if (n_read != 4) {
00590        printf("Error reading atom %d (%d)",i,n_read);
00591        exit(-2);
00592     }
00593   }
00594   fclose(inpf);
00595   return data;
00596 }
00597 
00598 
00599 MolData* MolData::readData(const int *indx, const float *coords, 
00600                            const int count,
00601                            const Vector3D o,
00602                            const Vector3D a,
00603                            const Vector3D b,
00604                            const Vector3D c,
00605                            const double gridspacing,
00606                            const double radius,
00607                            const double threshold,
00608                            const bool periodic)
00609 {
00610   MolData *data = new MolData;
00611   data->gridspacing = gridspacing;
00612   data->radius = radius;
00613   data->threshold = threshold;
00614   data->actual_radius = radius+threshold;
00615   data->periodic = periodic;
00616    
00617   data->origin=o;
00618   data->basisa = a;
00619   data->basisb = b;
00620   data->basisc = c;
00621   data->count = count;
00622         
00623   data->coords = new AtomData[data->count];
00624   int i;
00625   int ind=0;
00626   for (i=0; i<data->count; i++) {
00627     data->coords[i].index = indx[i];
00628     data->coords[i].coord.x = coords[ind];
00629     data->coords[i].coord.y = coords[ind+1];
00630     data->coords[i].coord.z = coords[ind+2];
00631     ind += 3;
00632   }
00633   return data;
00634 }
00635 
00636 
00637 void MolData::wrapCoords(const AtomGrid* grid) {
00638   int i;
00639   for(i=0; i < count; i++) {
00640     coords[i].coord = grid->wrap_xyz(coords[i].coord);
00641   }
00642 }
00643 
00644 
00645 int GridList::add(const int i, const int j, const int k) {
00646   if (indx >= n)
00647     return -1;
00648    
00649   const int i2 = shuffle_vec[indx];
00650   items[i2].x = i;
00651   items[i2].y = j;
00652   items[i2].z = k;
00653   indx++;
00654   return indx-1;
00655 }
00656 
00657 
00658 int AtomGridCell::set(const int i, const int j, const int k) {
00659   if (i<mina || i>maxa || j<minb || j>maxb || k<minc || k>maxc ) {
00660     return -1;
00661   }
00662   if (getlistcalled) {
00663     return -2;
00664   }
00665    
00666   if (noneset) {
00667     cellmap = new bool[na*nb*nc];
00668     int m;
00669     for (m=na*nb*nc-1; m >= 0; m--)
00670       cellmap[m] = false;
00671     noneset = false;
00672     
00673   }
00674    
00675   const int ii = i - mina;
00676   const int jj = j - minb;
00677   const int kk = k - minc;
00678   const int indx = ((ii*nb)+jj)*nc+kk;
00679   if (!cellmap[indx]) {
00680     count++;
00681   } 
00682   cellmap[indx] = true;
00683  
00684   return 0;
00685 }
00686 
00687 
00688 bool AtomGridCell::get(const int i, const int j, const int k) const {
00689   
00690   
00691   
00692   if (i<mina || i>maxa || j<minb || j>maxb || k<minc || k>maxc )
00693     return false;
00694 
00695   if (noneset)
00696     return false;
00697    
00698   const int ii = i - mina;
00699   const int jj = j - minb;
00700   const int kk = k - minc;
00701   return cellmap[((ii*nb)+jj)*nc+kk];
00702 }
00703 
00704 
00705 const GridList* AtomGridCell::get_list() {
00706   if (!getlistcalled) {
00707     build_list();
00708   }
00709   return gridlist;
00710 }
00711 
00712 
00713 void AtomGridCell::build_list() {
00714   
00715   getlistcalled = true;
00716   int sz = na*nb*nc;
00717   bool* vac = new bool[sz];
00718   int i;
00719   for (i=0; i < sz; i++)
00720     vac[i] = false;
00721    
00722   int tot=0;
00723   int grid_idx = 0;
00724   for(i=mina; i <= maxa; i++) {
00725     
00726     int j;
00727     for (j=minb; j <= maxb; j++) {
00728       
00729       int k;
00730       for (k=minc; k <= maxc; grid_idx++, k++) {
00731         if (!get(i,j,k)) {
00732           
00733           
00734           
00735           bool all_vac = true;
00736           if (i > mina && i < maxa 
00737               && j > minb && j < maxb
00738               && k > minc && k < maxc) {
00739             int ii;
00740             for (ii=-1; ii <= 1; ii++) {
00741               int jj;
00742               for (jj=-1; jj <= 1; jj++) {
00743                 int kk;
00744                 for (kk=-1; kk <= 1; kk++) {
00745                   if (get(i+ii,j+jj,k+kk)) {
00746                     
00747                     
00748                     all_vac = false;
00749                     break;
00750                   }
00751                 }
00752                 if (!all_vac)
00753                   break;
00754               }
00755               if (!all_vac)
00756                 break;
00757             }
00758           } else {
00759             all_vac = false;
00760           }
00761           if (!all_vac) {
00762             
00763             vac[grid_idx] = true;
00764             tot++;
00765             
00766           } 
00767         } 
00768       }
00769       
00770     }
00771   }
00772   gridlist = new GridList(ag,tot);
00773   grid_idx = 0;
00774   int gi;
00775   for (gi=mina; gi <= maxa; gi++) {
00776     int gj;
00777     for (gj=minb; gj <= maxb; gj++) {
00778       int gk;
00779       for (gk=minc; gk <= maxc; grid_idx++, gk++) {
00780         if (vac[grid_idx]) {
00781           
00782           gridlist->add(gi,gj,gk);
00783         }
00784       }
00785     }
00786   }
00787 
00788   
00789   
00790   
00791   delete [] vac;
00792 }
00793 
00794 
00795 AtomGrid::AtomGrid(const MolData* mdata) {
00796   
00797   
00798   
00799   origin = mdata->origin;
00800   grida = mdata->basisa;
00801   gridb = mdata->basisb;
00802   gridc = mdata->basisc;
00803   na = (int)ceil(mdata->basisa.length() / mdata->gridspacing);
00804   nb = (int)ceil(mdata->basisb.length() / mdata->gridspacing);
00805   nc = (int)ceil(mdata->basisc.length() / mdata->gridspacing);
00806   periodic = mdata->periodic;
00807    
00808   
00809   
00810   
00811   printf("Grid %d %d %d\n",na,nb,nc);
00812   printf("Origin %f %f %f\n",origin.x,origin.y,origin.z);
00813    
00814   double a[3][3];
00815    
00816   a[0][0] = grida.x;
00817   a[0][1] = gridb.x;
00818   a[0][2] = gridc.x;
00819   a[1][0] = grida.y;
00820   a[1][1] = gridb.y;
00821   a[1][2] = gridc.y;
00822   a[2][0] = grida.z;
00823   a[2][1] = gridb.z;
00824   a[2][2] = gridc.z;
00825   Inverse3(a,this->inv_abc);
00826    
00827   printf("a...\n");
00828   printf("%f %f %f\n",a[0][0],a[0][1],a[0][2]);
00829   printf("%f %f %f\n",a[1][0],a[1][1],a[1][2]);
00830   printf("%f %f %f\n",a[2][0],a[2][1],a[2][2]);
00831   
00832   printf("inv a...\n");
00833   printf("%f %f %f\n",inv_abc[0][0],inv_abc[0][1],inv_abc[0][2]);
00834   printf("%f %f %f\n",inv_abc[1][0],inv_abc[1][1],inv_abc[1][2]);
00835   printf("%f %f %f\n",inv_abc[2][0],inv_abc[2][1],inv_abc[2][2]);
00836    
00837   
00838   Vector3D cellsz = findAtomBox(mdata->getActualRadius());
00839   printf("cellsz=%f, %f, %f\n",cellsz.x,cellsz.y,cellsz.z);
00840    
00841   cna = (int)(floor(na/cellsz.x));
00842   cnb = (int)(floor(nb/cellsz.y));
00843   cnc = (int)(floor(nc/cellsz.z));
00844   if (cna==0) {
00845     cna = 1;
00846   }
00847   if (cnb==0) {
00848     cnb = 1;
00849   }
00850   if (cnc==0) {
00851     cnc = 1;
00852   }
00853    
00854   printf("na=%d, %d, %d\n",na,nb,nc);
00855   printf("cna=%d, %d, %d\n",cna,cnb,cnc);
00856    
00857   
00858   cellgrid = new AtomGridCell*[cna*cnb*cnc];
00859   
00860   celli = new int[na+1];
00861   celli[na] = cna;
00862   cellj = new int[nb+1];
00863   cellj[nb] = cnb;
00864   cellk = new int[nc+1];
00865   cellk[nc] = cnc;
00866    
00867   int* gridi = new int[cna+1];
00868   gridi[cna] = na;
00869   int* gridj = new int[cnb+1];
00870   gridj[cnb] = nb;
00871   int* gridk = new int[cnc+1];
00872   gridk[cnc] = nc;
00873    
00874   
00875   int mina = 0;
00876   int maxa;
00877   int i;
00878   for (i=0; i < cna; i++) {
00879     maxa = ((i+1) * na) / cna - 1;
00880     
00881     int ii;
00882     for (ii=mina; ii<= maxa; ii++) {
00883       celli[ii] = i;
00884       
00885     }
00886     gridi[i] = mina;
00887     int minb = 0;
00888     int maxb;
00889     int j;
00890     for(j=0; j < cnb; j++) {
00891       maxb = ((j+1) * nb) / cnb - 1;
00892       if (i==0) {
00893         for (int jj=minb; jj<= maxb; jj++)
00894           cellj[jj] = j;
00895       }
00896       gridj[j] = minb;
00897       int minc = 0;
00898       int maxc;
00899       int k;
00900       for (k=0; k < cnc; k++) {
00901         maxc = ((k+1) * nc) / cnc - 1;
00902         if (i==0 && j==0) {
00903           for (int kk=minc; kk<= maxc; kk++)
00904             cellk[kk] = k;
00905         }
00906         gridk[k] = minc;
00907         minc = maxc+1;
00908       }
00909       minb = maxb+1;
00910     }
00911     mina = maxa+1;
00912   }
00913    
00914   
00915   int ci;
00916   for (ci=0; ci < cna; ci++) {
00917     int cj;
00918     for (cj=0; cj < cnb; cj++) {
00919       int ck;
00920       for (ck=0; ck < cnc; ck++) {
00921         
00922         cellgrid[((ci*cnb)+cj) * cnc + ck] = 
00923           new AtomGridCell(this,gridi[ci],gridi[ci+1]-1,
00924                                 gridj[cj],gridj[cj+1]-1,
00925                                 gridk[ck],gridk[ck+1]-1);
00926       }
00927     }
00928   }
00929 
00930   delete[] gridi;
00931   delete[] gridj;
00932   delete[] gridk;
00933 }
00934 
00935 
00936 int* GridList::scramble_array(const int n) {
00937    return AtomGrid::scramble_array(n); 
00938 }
00939 
00940 
00941 int* AtomGrid::scramble_array(const int n) {
00942   if (n < 1) return 0;
00943    
00944   int* a = new int[n];
00945   a[0]=n-1;
00946   if (n == 1) return a;
00947   a[1] = 0;
00948   if (n == 2) return a;
00949    
00950   bool* b = new bool[n];
00951   int i;
00952   for (i=0; i<n; i++)
00953     b[i] = true;
00954    
00955   int howmany = 1;
00956   int incr = (n >> 1);
00957   
00958    
00959   int nxt=2;
00960   while (nxt < n) {
00961     int i;
00962     for (i=0; i < howmany; i++) {
00963       
00964       int nxtval = a[i+1] + incr;
00965       
00966       if (b[nxtval])  {
00967         a[nxt++] = nxtval;
00968         
00969         b[nxtval] = false;
00970       } 
00971       
00972       if (nxt > n-1)
00973         break;
00974     }
00975     howmany <<= 1;
00976     incr >>= 1;
00977     if (incr == 0)
00978       break;
00979   }
00980 
00981   for (i=1; i < n; i++) {
00982     if (nxt >= n) break;
00983     if (b[i])
00984       a[nxt++] = i;
00985   }
00986 
00987   delete [] b;
00988   return a;
00989 }
00990 
00991 
00992 Vector3D AtomGrid::findAtomBox(const double radius) const {
00993   
00994   Vector3D cornerx[8];
00995   Vector3D dx, dy, dz;
00996    
00997   const Vector3D o = origin;
00998   dx.y = dx.z = dy.x = dy.z = dz.x = dz.y = 0;
00999   dx.x = dy.y = dz.z = radius;
01000   cornerx[0] = o;
01001   cornerx[1] = o + dx;
01002   cornerx[2] = o + dy;
01003   cornerx[3] = o + dz;
01004   cornerx[4] = cornerx[1] + dy;
01005   cornerx[5] = cornerx[1] + dz;
01006   cornerx[6] = cornerx[2] + dz;
01007   cornerx[7] = cornerx[4] + dz;  
01008    
01009   
01010   Vector3D ijk = get_ijk(cornerx[0]);
01011   double dimax = ijk.x;
01012   double djmax = ijk.y;
01013   double dkmax = ijk.z;
01014   
01015   int i;
01016   for (i=1; i<8; i++) {
01017     ijk = get_ijk(cornerx[i]);
01018     if (ijk.x > dimax)
01019       dimax = ijk.x;
01020     if (ijk.y > djmax)
01021       djmax = ijk.y;
01022     if (ijk.z > dkmax)
01023       dkmax = ijk.z;
01024   }
01025   Vector3D vec;
01026    
01027   vec.x = dimax;
01028   vec.y = djmax;
01029   vec.z = dkmax;
01030    
01031   return vec;
01032 }
01033 
01034 
01035 void AtomGrid::build(const MolData* mdata) {
01036   
01037   
01038   Vector3D bb = findAtomBox(mdata->getRadius());
01039    
01040   const int imax = (int)ceil(bb.x);
01041   const int jmax = (int)ceil(bb.y);
01042   const int kmax = (int)ceil(bb.z);
01043    
01044   printf("Box=%d, %d, %d\n",imax,jmax,kmax);
01045   const double rsq = mdata->getRadius() * mdata->getRadius();
01046   int atomi;
01047   for (atomi=0; atomi<mdata->count; atomi++) {
01048     Vector3D atom = mdata->coords[atomi].coord;
01049 
01050 
01051     Vector3D atomijk = get_ijk(atom);
01052     const int ai = (int)atomijk.x;
01053     const int aj = (int)atomijk.y;
01054     const int ak = (int)atomijk.z;
01055     int i;
01056     for (i=ai-imax; i <= ai+imax; i++) {
01057       int ii = i;
01058       if (i < 0) {
01059         if (periodic) {
01060           ii += na;
01061         } else continue;
01062       } else if (i >= na) {
01063         if (periodic) {
01064           ii -= na;
01065         } else continue;
01066       }
01067 
01068       int j;
01069       for(j=aj-jmax; j <= aj+jmax; j++) {
01070         int jj = j;
01071         if (j < 0) {
01072           if (periodic) {
01073             jj += nb;
01074           } else continue;
01075         } else if (j >= nb) {
01076           if (periodic) {
01077             jj -= nb;
01078           } else continue;
01079         }
01080   
01081         
01082         
01083         int k;
01084         for (k=0; k <= kmax; k++) {
01085           int k_no_wrap = ak+k;
01086           int kk = k_no_wrap;
01087           if (k_no_wrap < 0) {
01088             if (periodic) {
01089               kk += nc;
01090             } else continue;
01091           } else if (k_no_wrap >= nc) {
01092             if (periodic) {
01093               kk -= nc;
01094             } else continue;
01095           }
01096            
01097           
01098           if (get(ii,jj,kk))
01099             continue;
01100                
01101           const Vector3D v = get_xyz(i,j,k_no_wrap);
01102           const Vector3D dv = v - atom;
01103           if (dv.length2() <= rsq) {
01104             set(ii,jj,kk);
01105           } else {
01106             break;
01107           }
01108         }
01109 
01110         for (k=1; k <= kmax; k++) {
01111           int k_no_wrap = ak-k;
01112           int kk = k_no_wrap;
01113           if (k_no_wrap < 0) {
01114             if (periodic) {
01115               kk += nc;
01116             } else continue;
01117           } else if (k_no_wrap >= nc) {
01118             if (periodic) {
01119               kk -= nc;
01120             } else continue;
01121           }
01122           
01123           
01124           if (get(ii,jj,kk))
01125             continue;
01126           
01127           const Vector3D v = get_xyz(i,j,k_no_wrap);
01128           const Vector3D dv = v - atom;
01129           if (dv.length2() <= rsq) {
01130             set(ii,jj,kk);
01131           } else {
01132             break;
01133           }
01134         }
01135       }
01136     }
01137   }
01138   return;
01139 }
01140 
01141 
01142 void AtomGrid::print() {
01143   int k;
01144   for (k=0; k<nc; k++) {
01145     int i;
01146     for (i=0; i<na; i++) {
01147       printf("%d:",i);
01148       int j;
01149       for (j=0; j<nb; j++) {
01150         if (get(i,j,k))
01151           printf("1");
01152         else printf("0");
01153       }
01154       printf("\n");
01155     }
01156     printf("%d:-------------------------------------------------------\n",k);
01157   }
01158 }
01159 
01160 
01161 void AtomGrid::store(char* fname) {
01162   FILE* outf = fopen(fname,"w");
01163   if (outf == NULL) {
01164     printf("Couldn't open file %s\n",fname);
01165     exit(-1);
01166   }
01167    
01168   int k;
01169   for (k=0; k<nc; k++) {
01170     int i;
01171     for (i=0; i<na; i++) {
01172       int j;
01173       for (j=0; j<nb; j++) {
01174         if (!get(i,j,k)) {
01175           Vector3D v = get_xyz(i,j,k);
01176           if (fprintf(outf,"%f %f %f\n",v.x,v.y,v.z) < 0) {
01177             printf("Store grid error %s\n",fname);
01178             exit(-2);
01179           }
01180         }
01181       }
01182     }
01183   }
01184    
01185   fclose(outf);
01186   return;
01187 }
01188 
01189 
01190 void AtomGrid::Inverse3(const double m[3][3], double inv[3][3]) const {
01191   
01192   int i,j;
01193   for (i=0; i<3; i++)
01194     for (j=0; j<3; j++)
01195       inv[i][j] = Cofactor3(m,i,j);
01196   
01197   
01198   const double det = m[0][0] * inv[0][0] 
01199                    + m[0][1] * inv[1][0]
01200                    + m[0][2] * inv[2][0];
01201    
01202   
01203   
01204   
01205    
01206   for (i=0; i<3; i++)
01207     for (j=0; j<3; j++)
01208       inv[i][j] /= det;
01209   
01210   return;
01211 }
01212 
01213 
01214 double AtomGrid::Cofactor3(const double mat[3][3],
01215                            const int i, const int j) const {
01216   int cols[3][2] = { {1,2}, {0,2}, {0,1}};
01217    
01218   const int row1 = cols[j][0];
01219   const int row2 = cols[j][1];
01220   
01221   const int col1 = cols[i][0];
01222   const int col2 = cols[i][1];
01223   
01224   const double a = mat[row1][col1];
01225   const double b = mat[row1][col2];
01226   const double c = mat[row2][col1];
01227   const double d = mat[row2][col2];
01228   
01229   const double det = a*d-b*c;
01230   if (((i+j) % 2) != 0)
01231     return -det;
01232   else
01233     return det;
01234 }
01235 
01236 
01237 AtomList* MolData::findAtomsGrid(const AtomGrid* grid) {
01238   
01239   AtomList *al = new AtomList(count);
01240   const double r = getActualRadius();
01241   const double rsq = r*r;
01242   const Vector3D atom_box = grid->findAtomBox(radius);
01243 
01244   int atomi;
01245   for (atomi=0; atomi<count; atomi++) {
01246     Vector3D atom = coords[atomi].coord;
01247 
01248 
01249     int i0, j0, k0;
01250     bool found = false;
01251       
01252     grid->get_cijk(atom,i0,j0,k0);
01253     bool cell_outside = false;
01254 
01255     int di;
01256     for (di=-1; !found && di <= 1; di++) {
01257       int ci = i0 + di;
01258       int cna = grid->get_cna();
01259       int wrapi = 0;
01260       if (ci<0) {
01261         ci += cna;
01262         wrapi = grid->get_na();
01263         if (!periodic)
01264           cell_outside = true;
01265       } else if (ci >= cna) {
01266         ci -= cna;
01267         wrapi = -grid->get_na();
01268         if (!periodic)
01269           cell_outside = true;
01270       }
01271 
01272       int dj;
01273       for (dj=-1; !found && dj <= 1; dj++) {
01274         int cj = j0 + dj;
01275         int cnb = grid->get_cnb();
01276         int wrapj = 0;
01277         if (cj<0) {
01278           cj += cnb;
01279           wrapj = grid->get_nb();
01280           if (!periodic)
01281             cell_outside = true;
01282         } else if (cj >= cnb) {
01283           cj -= cnb;
01284           wrapj = grid->get_nb();
01285           if (!periodic)
01286             cell_outside = true;
01287         }
01288 
01289         int dk;
01290         for (dk=-1; !found && dk <= 1; dk++) {
01291           int ck = k0 + dk;
01292           int cnc = grid->get_cnc();
01293           int wrapk = 0;
01294           if (ck<0) {
01295             ck += cnc;
01296             wrapk = grid->get_nc();
01297             if (!periodic)
01298               cell_outside = true;
01299           } else if (ck >= cnc) {
01300             ck -= cnc;
01301             wrapk = -grid->get_nc();
01302             if (!periodic)
01303               cell_outside = true;
01304           }
01305 
01306           
01307           
01308           if (!periodic && cell_outside) {
01309             const Vector3D atom_grid = grid->get_ijk(atom);
01310             const Vector3D corner0 = atom_grid - atom_box;
01311             bool addit = false;
01312             if (corner0.x < 0 || corner0.y < 0 || corner0.z < 0) {
01313               addit = true;
01314             } else {
01315               const Vector3D corner1 = atom_grid + atom_box;
01316               if (corner1.x >= grid->get_na() 
01317                   || corner1.y >= grid->get_nb() 
01318                   || corner1.z >= grid->get_nc() )
01319                 addit = true;
01320             }
01321             if (addit) {
01322               al->add(coords[atomi].index);
01323               found = true;
01324             }
01325             cell_outside = false;
01326           }
01327 
01328           const GridList* list = grid->get_cell(ci,cj,ck);
01329 
01330 
01331 
01332           int gli;
01333           for (gli=0; !found && gli < list->getNum(); gli++) {
01334 
01335             Vector3D gridpt = list->get(gli);
01336             gridpt.x += wrapi;
01337             gridpt.y += wrapj;
01338             gridpt.z += wrapk;
01339             const Vector3D v = grid->get_xyz(gridpt);
01340             const Vector3D dv = v - atom;
01341             if (dv.length2() <= rsq) {
01342               al->add(coords[atomi].index);
01343               found = true;
01344 
01345             }
01346           }
01347         }
01348       }
01349     }
01350   }
01351 
01352   return al;
01353 }
01354 
01355 
01356 int msmain(int argc,char *argv[]) {
01357   if (argc != 6) {
01358     printf("Usage: %s grid-res vac-radius selection-dist coord-file index-file\n", argv[0]);
01359      return 0;
01360   }
01361    
01362   double res = strtod(argv[1],NULL); 
01363   double radius = strtod(argv[2],NULL); 
01364   double select_dist = strtod(argv[3],NULL); 
01365    
01366   printf("Reading\n");
01367   MolData* mol_data = MolData::readFile(argv[4],res,radius,select_dist);
01368   printf("Building grid\n");
01369   AtomGrid* atom_grid = new AtomGrid(mol_data);
01370   mol_data->wrapCoords(atom_grid);
01371   atom_grid->build(mol_data);
01372    
01373   
01374   
01375    
01376   printf("Searching grid\n");
01377   AtomList* atom_list = mol_data->findAtomsGrid(atom_grid);
01378   printf("Storing\n");
01379   atom_list->storeFile(argv[5]);
01380    
01381   delete atom_list;
01382   delete atom_grid;
01383   delete mol_data;
01384   
01385   return 0;
01386 }
01387 
01388 
01389 void measure_surface_int(const double res, const double radius, 
01390                          const double select_dist,
01391                          const bool periodic,
01392                          const double a, const double b, const double c, 
01393                          const double alpha, const double beta, const double gamma,
01394                          int *indices, float *coords, int count,
01395                          int **surf, int *n_surf
01396                          ) 
01397 {
01398   if (periodic)
01399     printf("System periodic\n");
01400   else
01401     printf("System not periodic\n");
01402 
01403   printf("Reading\n");
01404   Vector3D uo;
01405   Vector3D ua;
01406   Vector3D ub;
01407   Vector3D uc;
01408    
01409   
01410   double xmin = coords[0];
01411   double xmax = coords[0];
01412   double ymin = coords[1];
01413   double ymax = coords[1];
01414   double zmin = coords[2];
01415   double zmax = coords[2];
01416   int ind;
01417   int i;
01418   for(i=1, ind=3; i < count; i++, ind += 3) {
01419     if (coords[ind] < xmin)
01420       xmin = coords[ind];
01421     if (coords[ind] > xmax)
01422       xmax = coords[ind];
01423     if (coords[ind+1] < ymin)
01424       ymin = coords[ind+1];
01425     if (coords[ind+1] > ymax)
01426       ymax = coords[ind+1];
01427     if (coords[ind+2] < zmin)
01428       zmin = coords[ind+2];
01429     if (coords[ind+2] > zmax)
01430       zmax = coords[ind+2];
01431   }
01432   uo.x = 0.5*(xmin+xmax);
01433   uo.y = 0.5*(ymin+ymax);
01434   uo.z = 0.5*(zmin+zmax);
01435    
01436   double cosbc = cos(DEGTORAD(alpha));
01437   double cosac = cos(DEGTORAD(beta));
01438   double sinab, cosab;
01439   sincos(DEGTORAD(gamma), &sinab, &cosab);
01440 
01441   ua.x = a; ua.y = 0; ua.z = 0;
01442   ub.x = b * cosab;
01443   ub.y = b * sinab;
01444   ub.z = 0;
01445 
01446   
01447   
01448   if (sinab > 0) {
01449     uc.x = cosac;
01450     uc.y = (cosbc - cosac * cosab) / sinab;
01451     uc.z = sqrt(1.0 - uc.x*uc.x - uc.y*uc.y);
01452   }
01453   uc = c * uc;
01454   
01455   uo = uo - (0.5 * (ua + ub + uc));
01456    
01457   MolData* mol_data = MolData::readData(indices, coords, count,
01458                                         uo, ua, ub, uc,
01459                                         res,radius,select_dist,periodic);
01460   printf("Building grid\n");
01461   AtomGrid* atom_grid = new AtomGrid(mol_data);
01462   mol_data->wrapCoords(atom_grid);
01463   atom_grid->build(mol_data);
01464    
01465   
01466   
01467    
01468   printf("Searching grid\n");
01469   AtomList* atom_list = mol_data->findAtomsGrid(atom_grid);
01470   printf("Storing\n");
01471   atom_list->storeData(surf,n_surf);
01472    
01473   delete atom_list;
01474   delete atom_grid;
01475   delete mol_data;
01476      
01477   return;
01478 }
01479 
01480 
01481 int measure_surface(AtomSel *sel, MoleculeList *mlist,
01482                    const float *framepos,
01483                    const double gridsz, 
01484                    const double radius,
01485                    const double depth,
01486                    int **surface, int *n_surf ) {
01487   int i;
01488   
01489   if (!sel)                     return MEASURE_ERR_NOSEL;
01490   if (sel->num_atoms == 0)      return MEASURE_ERR_NOATOMS;
01491   
01492   
01493   int *sel_ind = new int[sel->selected];
01494   float *coords = new float[sel->selected*3];
01495   int j=0;
01496   int k=0;
01497   int ind=sel->firstsel*3;
01498   for(i=sel->firstsel; i<=sel->lastsel; i++) {
01499     if (sel->on[i]) {
01500       sel_ind[j++] = i;
01501       coords[k++] = framepos[ind];
01502       coords[k++] = framepos[ind+1];
01503       coords[k++] = framepos[ind+2];
01504     }
01505     ind += 3;
01506   }
01507   
01508   Timestep *ts = sel->timestep(mlist);
01509   double a = ts->a_length;
01510   double b = ts->b_length;
01511   double c = ts->c_length;
01512   double alpha = ts->alpha;
01513   double beta = ts->beta;
01514   double gamma = ts->gamma;
01515   bool periodic = true;
01516   if (a == 0 || b == 0 || c == 0 || alpha == 0 || beta == 0 || gamma == 0) {
01517     periodic = false;
01518     float min_coord[3];
01519     float max_coord[3];
01520     measure_minmax(sel->num_atoms, sel->on, framepos, NULL, min_coord, max_coord);
01521     a = max_coord[0] - min_coord[0];
01522     b = max_coord[1] - min_coord[1];
01523     c = max_coord[2] - min_coord[2];
01524     alpha = beta = gamma = 90;
01525   }
01526         
01527   printf("Periodic: %f %f %f %f %f %f\n",a,b,c,alpha,beta,gamma);
01528   
01529   measure_surface_int(gridsz, radius, depth, periodic,
01530                       a,b,c,alpha,beta,gamma,
01531                       sel_ind,coords,sel->selected,
01532                       surface, n_surf);
01533   
01534   printf("Done!\n");
01535   
01536   return MEASURE_NOERR;
01537 }