![]() |
ESPResSo 3.2.0-11-g9950804-git
Extensible Simulation Package for Soft Matter Research
|
00001 /* 00002 Copyright (C) 2010,2011,2012,2013 The ESPResSo project 00003 Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 00004 Max-Planck-Institute for Polymer Research, Theory Group 00005 00006 This file is part of ESPResSo. 00007 00008 ESPResSo is free software: you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation, either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 ESPResSo is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program. If not, see <http://www.gnu.org/licenses/>. 00020 */ 00021 #ifndef _UTILS_H 00022 #define _UTILS_H 00023 /** \file utils.h 00024 * Small functions that are useful not only for one modul. 00025 00026 * just some nice utilities... 00027 * and some constants... 00028 * 00029 */ 00030 #include <math.h> 00031 #include <stdio.h> 00032 #include <stdlib.h> 00033 #include <string.h> 00034 #include "config.h" 00035 #include "debug.h" 00036 #include "errorhandling.h" 00037 00038 /*************************************************************/ 00039 /** \name Mathematical, physical and chemical constants. */ 00040 /*************************************************************/ 00041 /*@{*/ 00042 /** Pi. */ 00043 #define PI 3.14159265358979323846264338328 00044 /** Square root of Pi */ 00045 #define wupi 1.77245385090551602729816748334 00046 /** One over square root of Pi. */ 00047 #define wupii 0.56418958354775627928034964498 00048 /** Pi to the power 1/3. */ 00049 #define driwu2 1.25992104989487316476721060728 00050 00051 /// error code if no error occured 00052 #define ES_OK 0 00053 /// error code if an error occured 00054 #define ES_ERROR 1 00055 00056 /** space necessary for an (64-bit) integer with sprintf. 00057 Analog to Tcl 00058 */ 00059 #define ES_INTEGER_SPACE 24 00060 /** space necessary for an double with sprintf. Precision 00061 is 17 digits, plus sign, dot, e, sign of exponent and 00062 3 digits exponent etc. Analog to Tcl 00063 */ 00064 #define ES_DOUBLE_SPACE 27 00065 00066 /*@}*/ 00067 00068 /************************************************ 00069 * data types 00070 ************************************************/ 00071 00072 /** Integer list. 00073 Use the functions specified in list operations. */ 00074 typedef struct { 00075 /** Dynamically allocated integer field. */ 00076 int *e; 00077 /** number of used elements in the integer field. */ 00078 int n; 00079 /** allocated size of the integer field. This value is ONLY changed 00080 in the routines specified in list operations ! */ 00081 int max; 00082 } IntList; 00083 00084 /** Double list. 00085 Use the functions specified in list operations. */ 00086 typedef struct { 00087 /** Dynamically allocated double field. */ 00088 double *e; 00089 /** number of used elements in the double field. */ 00090 int n; 00091 /** allocated size of the double field. This value is ONLY changed 00092 in the routines specified in list operations ! */ 00093 int max; 00094 } DoubleList; 00095 00096 /*************************************************************/ 00097 /** \name Dynamic memory allocation. */ 00098 /*************************************************************/ 00099 /*@{*/ 00100 00101 /* to enable us to make sure that freed pointers are invalidated, we normally try to use realloc. 00102 Unfortunately allocating zero bytes (which should be avoided) actually allocates 16 bytes, and 00103 reallocating to 0 also. To avoid this, we use our own malloc and realloc procedures. */ 00104 #ifndef MEM_DEBUG 00105 00106 #ifdef realloc 00107 #undef realloc 00108 #endif 00109 00110 #ifdef malloc 00111 #undef malloc 00112 #endif 00113 00114 /** used instead of realloc. 00115 Makes sure that resizing to zero FREEs pointer */ 00116 MDINLINE void *prealloc(void *old, int size) 00117 { 00118 void *p; 00119 if (size <= 0) { 00120 free(old); 00121 return NULL; 00122 } 00123 p = (void *)realloc(old, size); 00124 if(p == NULL) { 00125 fprintf(stderr, "Could not allocate memory.\n"); 00126 errexit(); 00127 } 00128 return p; 00129 } 00130 00131 /** used instead of malloc. 00132 Makes sure that a zero size allocation returns a NULL pointer */ 00133 MDINLINE void *pmalloc(int size) 00134 { 00135 void *p; 00136 if (size <= 0) { 00137 return NULL; 00138 } 00139 p = (void *)malloc(size); 00140 if(p == NULL) { 00141 fprintf(stderr, "Could not allocate memory.\n"); 00142 errexit(); 00143 } 00144 return p; 00145 } 00146 00147 /** use our own realloc which makes sure that realloc(0) is actually a free. */ 00148 #define realloc prealloc 00149 00150 /** use our own malloc which makes sure that malloc(0) returns NULL. */ 00151 #define malloc pmalloc 00152 00153 #endif 00154 /*@}*/ 00155 00156 /*************************************************************/ 00157 /* mass helper macro */ 00158 /*************************************************************/ 00159 00160 #ifdef MASS 00161 /** macro for easy use of mass. If masses are not switched on, the particle mass is defined to 1, 00162 so it should be compiled out in most cases. */ 00163 #define PMASS(pt) (pt).p.mass 00164 #else 00165 #define PMASS(pt) 1 00166 #endif 00167 00168 /*************************************************************/ 00169 /** \name List operations . */ 00170 /*************************************************************/ 00171 /*@{*/ 00172 00173 /** Initialize an \ref IntList. */ 00174 MDINLINE void init_intlist(IntList *il) 00175 { 00176 il->n = 0; 00177 il->max = 0; 00178 il->e = NULL; 00179 } 00180 extern int this_node; 00181 00182 /** Allocate an \ref IntList of size size. If you need an \ref IntList 00183 with variable size better use \ref realloc_intlist */ 00184 MDINLINE void alloc_intlist(IntList *il, int size) 00185 { 00186 il->max = size; 00187 il->e = (int *) malloc(sizeof(int)*il->max); 00188 } 00189 00190 /** Reallocate an \ref IntList */ 00191 MDINLINE void realloc_intlist(IntList *il, int size) 00192 { 00193 if(size != il->max) { 00194 il->max = size; 00195 il->e = (int *) realloc(il->e, sizeof(int)*il->max); 00196 } 00197 } 00198 00199 /** Allocate an \ref IntList, but only to multiples of grain. */ 00200 MDINLINE void alloc_grained_intlist(IntList *il, int size, int grain) 00201 { 00202 il->max = grain*((size + grain - 1)/grain); 00203 il->e = (int *) malloc(sizeof(int)*il->max); 00204 } 00205 00206 /** Reallocate an \ref IntList, but only to multiples of grain. */ 00207 MDINLINE void realloc_grained_intlist(IntList *il, int size, int grain) 00208 { 00209 if(size >= il->max) 00210 il->max = grain*((size + grain - 1)/grain); 00211 else 00212 /* shrink not as fast, just lose half, rounded up */ 00213 il->max = grain*(((il->max + size + 1)/2 + 00214 grain - 1)/grain); 00215 00216 il->e = (int *) realloc(il->e, sizeof(int)*il->max); 00217 } 00218 00219 /** Check wether an \ref IntList contains the value c */ 00220 MDINLINE int intlist_contains(IntList *il, int c) 00221 { 00222 int i; 00223 for (i = 0; i < il->n; i++) 00224 if (c == il->e[i]) return 1; 00225 return 0; 00226 } 00227 00228 /** Initialize an \ref DoubleList. */ 00229 MDINLINE void init_doublelist(DoubleList *il) 00230 { 00231 il->n = 0; 00232 il->max = 0; 00233 il->e = NULL; 00234 } 00235 00236 /** Allocate an \ref DoubleList of size size. If you need an \ref DoubleList 00237 with variable size better use \ref realloc_doublelist */ 00238 MDINLINE void alloc_doublelist(DoubleList *dl, int size) 00239 { 00240 dl->max = size; 00241 dl->e = (double *) malloc(sizeof(double)*dl->max); 00242 } 00243 00244 /** Reallocate an \ref DoubleList */ 00245 MDINLINE void realloc_doublelist(DoubleList *dl, int size) 00246 { 00247 if(size != dl->max) { 00248 dl->max = size; 00249 dl->e = (double *) realloc(dl->e, sizeof(double)*dl->max); 00250 } 00251 } 00252 00253 /** Allocate an \ref DoubleList, but only to multiples of grain. */ 00254 MDINLINE void alloc_grained_doublelist(DoubleList *dl, int size, int grain) 00255 { 00256 dl->max = grain*((size + grain - 1)/grain); 00257 dl->e = (double *) malloc(sizeof(double)*dl->max); 00258 } 00259 00260 /** Reallocate an \ref DoubleList, but only to multiples of grain. */ 00261 MDINLINE void realloc_grained_doublelist(DoubleList *dl, int size, int grain) 00262 { 00263 if(size >= dl->max) 00264 dl->max = grain*((size + grain - 1)/grain); 00265 else 00266 /* shrink not as fast, just lose half, rounded up */ 00267 dl->max = grain*(((dl->max + size + 1)/2 + 00268 grain - 1)/grain); 00269 00270 dl->e = (double *) realloc(dl->e, sizeof(double)*dl->max); 00271 } 00272 /*@}*/ 00273 00274 00275 /*************************************************************/ 00276 /** \name Mathematical functions. */ 00277 /*************************************************************/ 00278 /*@{*/ 00279 00280 /** Calculates the maximum of 'double'-typed a and b, returning 'double'. */ 00281 MDINLINE double dmax(double a, double b) { return (a>b) ? a : b; } 00282 00283 /** Calculates the minimum of 'double'-typed a and b, returning 'double'. */ 00284 MDINLINE double dmin(double a, double b) { return (a<b) ? a : b; } 00285 00286 /** Calculates the maximum of 'int'-typed a and b, returning 'int'. */ 00287 MDINLINE int imax(int a, int b) { return (a>b) ? a : b; } 00288 00289 /** Calculates the minimum of 'int'-typed a and b, returning 'int'. */ 00290 MDINLINE int imin(int a, int b) { return (a<b) ? a : b; } 00291 00292 /** Calculates the remainder of a division */ 00293 MDINLINE double drem_down(double a, double b) { return a - floor(a/b)*b; } 00294 00295 /** vector difference */ 00296 MDINLINE void vector_subt(double res[3], double a[3], double b[3]) 00297 { 00298 int i; 00299 for (i=0;i<3;i++) 00300 res[i]=a[i]-b[i]; 00301 } 00302 00303 /** Very slow sort routine for small integer arrays. Sorts the values 00304 in decending order. 00305 \param data the integer array 00306 \param size size of the array 00307 */ 00308 MDINLINE void sort_int_array(int *data, int size) 00309 { 00310 int i,j,tmp; 00311 for(i=0;i<size-1;i++) 00312 for(j=i+1;j<size;j++) { 00313 if(data[i]<data[j]) { 00314 tmp=data[i]; data[i]=data[j]; data[j]=tmp; 00315 } 00316 } 00317 } 00318 00319 /** permute an interger array field of size size about permute positions. */ 00320 MDINLINE void permute_ifield(int *field, int size, int permute) 00321 { 00322 int i,tmp; 00323 00324 if(permute==0) return; 00325 if(permute<0) permute = (size + permute); 00326 while(permute>0) { 00327 tmp=field[0]; 00328 for(i=1;i<size;i++) field[i-1] = field[i]; 00329 field[size-1]=tmp; 00330 permute--; 00331 } 00332 } 00333 00334 /** Mathematically rounds 'double'-typed x, returning 'double'. */ 00335 MDINLINE double dround(double x) { return floor(x+0.5); } 00336 00337 /** Calculates the SQuaRe of 'double' x, returning 'double'. */ 00338 MDINLINE double SQR(double x) { return x*x; } 00339 00340 /** approximates \f$ \exp(d^2) \mathrm{erfc}(d)\f$ by applying a formula from: 00341 Abramowitz/Stegun: Handbook of Mathematical Functions, Dover 00342 (9. ed.), chapter 7 */ 00343 MDINLINE double AS_erfc_part(double d) 00344 { 00345 #define AS_a1 0.254829592 00346 #define AS_a2 -0.284496736 00347 #define AS_a3 1.421413741 00348 #define AS_a4 -1.453152027 00349 #define AS_a5 1.061405429 00350 #define AS_p 0.3275911 00351 double t; 00352 00353 t = 1.0 / (1.0 + AS_p * d); 00354 00355 return t * (AS_a1 + t * (AS_a2 + t * (AS_a3 + t * (AS_a4 + t * AS_a5) ) ) ); 00356 } 00357 00358 /** Calculates the sinc-function as sin(PI*x)/(PI*x). 00359 * 00360 * (same convention as in Hockney/Eastwood). In order to avoid 00361 * divisions by 0, arguments, whose modulus is smaller than epsi, will 00362 * be evaluated by an 8th order Taylor expansion of the sinc 00363 * function. Note that the difference between sinc(x) and this 00364 * expansion is smaller than 0.235e-12, if x is smaller than 0.1. (The 00365 * next term in the expansion is the 10th order contribution 00366 * PI^10/39916800 * x^10 = 0.2346...*x^12). This expansion should 00367 * also save time, since it reduces the number of function calls to 00368 * sin(). 00369 */ 00370 MDINLINE double sinc(double d) 00371 { 00372 #define epsi 0.1 00373 00374 #define c2 -0.1666666666667e-0 00375 #define c4 0.8333333333333e-2 00376 #define c6 -0.1984126984127e-3 00377 #define c8 0.2755731922399e-5 00378 00379 double PId = PI*d, PId2; 00380 00381 if (fabs(d)>epsi) 00382 return sin(PId)/PId; 00383 else { 00384 PId2 = SQR(PId); 00385 return 1.0 + PId2*(c2+PId2*(c4+PId2*(c6+PId2*c8))); 00386 } 00387 } 00388 00389 /** factorizes small numbers up to a maximum of max factors. */ 00390 MDINLINE int calc_factors(int n, int *factors, int max) 00391 { 00392 int f=2,i=0; 00393 while(n>1) { 00394 while(f<=n) { 00395 if(n%f==0) { 00396 if(i>=max) return 0; 00397 n /= f; 00398 factors[i]=f; 00399 i++; 00400 f=n; 00401 } 00402 f++; 00403 } 00404 f=2; 00405 } 00406 return i; 00407 } 00408 /*@}*/ 00409 00410 00411 /*************************************************************/ 00412 /** \name Vector and matrix operations for three dimensons. */ 00413 /*************************************************************/ 00414 /*@{*/ 00415 00416 /** Subtracts vector v2 from vector v1 and stores resuld in vector dv */ 00417 MDINLINE void vecsub(double v1[3], double v2[3], double dv[3]) 00418 { 00419 dv[0] = v1[0] - v2[0]; 00420 dv[1] = v1[1] - v2[1]; 00421 dv[2] = v1[2] - v2[2]; 00422 } 00423 00424 00425 /** calculates the length of a vector */ 00426 MDINLINE double normr(double v[3]) { 00427 double d2 = 0.0; 00428 int i; 00429 for(i=0;i<3;i++) 00430 d2 += SQR(v[i]); 00431 d2 = sqrtf(d2); 00432 return d2; 00433 } 00434 00435 /** calculates the squared length of a vector */ 00436 MDINLINE double sqrlen(double v[3]) { 00437 double d2 = 0.0; 00438 int i; 00439 for(i=0;i<3;i++) 00440 d2 += SQR(v[i]); 00441 return d2; 00442 } 00443 00444 /** calculates unit vector */ 00445 MDINLINE void unit_vector(double v[3],double y[3]) { 00446 double d = 0.0; 00447 int i; 00448 d=sqrt( sqrlen(v) ); 00449 00450 for(i=0;i<3;i++) 00451 y[i] = v[i]/d; 00452 00453 return; 00454 } 00455 00456 /** calculates the scalar product of two vectors a nd b */ 00457 MDINLINE double scalar(double a[3], double b[3]) { 00458 double d2 = 0.0; 00459 int i; 00460 for(i=0;i<3;i++) 00461 d2 += a[i]*b[i]; 00462 return d2; 00463 } 00464 00465 /** calculates the vector product c of two vectors a and b */ 00466 MDINLINE void vector_product(double a[3], double b[3], double c[3]) { 00467 c[0]=a[1]*b[2]-a[2]*b[1]; 00468 c[1]=a[2]*b[0]-a[0]*b[2]; 00469 c[2]=a[0]*b[1]-a[1]*b[0]; 00470 return ; 00471 } 00472 00473 /** rotates vector around axis by alpha */ 00474 MDINLINE void vec_rotate(double *axis, double alpha, double *vector, double *result){ 00475 double sina,cosa,absa,a[3]; 00476 sina=sin(alpha); 00477 cosa=cos(alpha); 00478 absa=sqrt(scalar(axis,axis)); 00479 00480 a[0]=axis[0]/absa; 00481 a[1]=axis[1]/absa; 00482 a[2]=axis[2]/absa; 00483 00484 result[0]=(cosa+SQR(a[0])*(1-cosa))*vector[0]+(a[0]*a[1]*(1-cosa)-a[2]*sina)*vector[1]+(a[0]*a[2]*(1-cosa)+a[1]*sina)*vector[2]; 00485 result[1]=(a[0]*a[1]*(1-cosa)+a[2]*sina)*vector[0]+(cosa+SQR(a[1])*(1-cosa))*vector[1]+(a[1]*a[2]*(1-cosa)-a[0]*sina)*vector[2]; 00486 result[2]=(a[0]*a[2]*(1-cosa)-a[1]*sina)*vector[0]+(a[1]*a[2]*(1-cosa)+a[0]*sina)*vector[1]+(cosa+SQR(a[2])*(1-cosa))*vector[2]; 00487 00488 return; 00489 } 00490 00491 /** Calc eigevalues of a 3x3 matrix stored in q as a 9x1 array*/ 00492 MDINLINE int calc_eigenvalues_3x3(double *q, double *eva) { 00493 double q11,q22,q33,q12,q13,q23; 00494 double a,b,c; 00495 double QQ,R,R2,QQ3; 00496 double theta,root1,root2,x1,x2,x3,help; 00497 int anzdiff=3; 00498 00499 /* copy tensor to local variables (This is really a fuc off code!) */ 00500 q11 = *q++; q12 = *q++; q13 = *q; 00501 q22 = *(q+=2); q23 = *(++q); q33 = *(q+=3); 00502 00503 /* solve the cubic equation of the eigenvalue problem */ 00504 a = -(q11 + q22 + q33); 00505 b = q11*q22 + q11*q33 + q22*q33 - q12*q12 - q13*q13 - q23*q23; 00506 c = -(q11*q22*q33 + 2*q12*q23*q13 - q12*q12*q33 - q13*q13*q22 - q23*q23*q11); 00507 QQ = (a*a-3*b)/9.0; 00508 R = (2*a*a*a - 9*a*b + 27*c)/54; 00509 QQ3 = QQ*QQ*QQ; 00510 R2 = R*R; 00511 00512 if (R2 < QQ3) { 00513 theta = acos(R/sqrt(QQ3)); 00514 root1 = sqrt(QQ)*cos(theta/3.0); 00515 root2 = sqrt(QQ*3.0)*sin(theta/3.0); 00516 x1 = - 2*root1 - a/3.0; 00517 x2 = root1 - root2 - a/3.0; 00518 x3 = root1 + root2 - a/3.0; 00519 } 00520 else { 00521 double AA,BB,signum = 1.0; 00522 00523 if (R < 0) { signum = -1.0; R = -R; } 00524 AA = - signum*exp( log(R + sqrt(R2-QQ3))/3.0); 00525 if (AA==0.0) BB = 0.0; 00526 else BB = QQ/AA; 00527 00528 /* compute the second way of the diagonalization 00529 * remark : a diagonal matrix has to have real eigenvalues (=>x2=x3) 00530 * but (!), the general solution of this case can have in general 00531 * imaginary solutions for x2,x3 (see numerical recipies p. 185) */ 00532 x1 = (AA+BB) - a/3.0; 00533 x2 = 0.5*(AA+BB) - a/3.0; 00534 x3 = x2; 00535 } 00536 00537 /* order the eigenvalues in decreasing order */ 00538 if (x1<x2) { help = x1; x1 = x2; x2 = help; } 00539 if (x1<x3) { help = x1; x1 = x3; x3 = help; } 00540 if (x2<x3) { help = x2; x2 = x3; x3 = help; } 00541 eva[0] = x1; eva[1] = x2; eva[2] = x3; 00542 00543 /* calculate number of different eigenvalues */ 00544 if(x1==x2) anzdiff--; 00545 if(x2==x3) anzdiff--; 00546 00547 return anzdiff; 00548 } 00549 00550 /** Calc eigevectors of a 3x3 matrix stored in a as a 9x1 array*/ 00551 /** Given an eigenvalue (eva) returns the corresponding eigenvector (eve)*/ 00552 MDINLINE int calc_eigenvector_3x3(double *a,double eva,double *eve) { 00553 int i,j,ind1,ind2,ind3,row1,row2; 00554 double A_x1[3][3],coeff1,coeff2,norm; 00555 00556 /* build (matrix - eva*unity) */ 00557 for(i=0;i<3;i++) { 00558 for(j=0;j<3;j++) A_x1[i][j]=a[3*i+j]; 00559 A_x1[i][i]-=eva; 00560 } 00561 00562 /* solve the linear equation system */ 00563 for(ind1=0;ind1<3;ind1++) { 00564 ind2=(ind1+1) % 3; ind3=(ind1+2) % 3; 00565 row1=0; 00566 do { 00567 row1++; 00568 } while ((row1<3) && (A_x1[ind3][row1]==0)); 00569 00570 /* okay, if one whole column is empty then we can take this 00571 direction as the eigenvector 00572 remember : {eigenvectors} = kernel(A_x1) */ 00573 if (row1 == 3) { 00574 eve[ind3]=1.0; 00575 eve[(ind3+1) % 3]=0.0; 00576 eve[(ind3+2) % 3]=0.0; 00577 return 1; 00578 } 00579 00580 for(i=1;i<3;i++) { 00581 row2=(row1+i) % 3; 00582 coeff1=A_x1[ind1][row1]*A_x1[ind3][row2]- 00583 A_x1[ind1][row2]*A_x1[ind3][row1]; 00584 coeff2=A_x1[ind2][row1]*A_x1[ind3][row2]- 00585 A_x1[ind2][row2]*A_x1[ind3][row1]; 00586 if (coeff1!=0.0) { 00587 eve[ind2]=1.0; 00588 eve[ind1]=-coeff2/coeff1; 00589 eve[ind3]=-( A_x1[ind2][row1]+eve[ind1]* A_x1[ind1][row1]) 00590 /A_x1[ind3][row1]; 00591 norm = sqrt(eve[0]*eve[0] + eve[1]*eve[1] + eve[2]*eve[2]); 00592 eve[0]/=norm; eve[1]/=norm; eve[2]/=norm; 00593 return 1; 00594 } 00595 else { 00596 if (coeff2!=0.0) { 00597 eve[ind1]=1.0; 00598 eve[ind2]=-coeff1/coeff2; 00599 eve[ind3]=-( A_x1[ind1][row1]+eve[ind2]* A_x1[ind2][row1]) 00600 /A_x1[ind3][row1]; 00601 norm = sqrt(eve[0]*eve[0] + eve[1]*eve[1] + eve[2]*eve[2]); 00602 eve[0]/=norm; eve[1]/=norm; eve[2]/=norm; 00603 return(1); 00604 } 00605 } 00606 } /* loop over the different rows */ 00607 } /* loop over the different columns */ 00608 00609 /* the try failed => not a singular matrix: only solution is (0,0,0) */ 00610 return 0; 00611 } 00612 /*@}*/ 00613 00614 /*************************************************************/ 00615 /** \name Linear algebra functions */ 00616 /*************************************************************/ 00617 /*@{*/ 00618 00619 /** Calculate the LU decomposition of a matrix A. Uses Crout's method 00620 * with partial implicit pivoting. The original matrix A is replaced 00621 * by its LU decomposition. Due to the partial pivoting the result 00622 * may contain row permutations which are recorded in perms. 00623 * @return 0 for success, -1 otherwise (i.e. matrix is singular) 00624 * @param A Matrix to be decomposed (Input/Output) 00625 * @param n Dimension of the matrix (Input) 00626 * @param perms Records row permutations effected by pivoting (Output) 00627 */ 00628 MDINLINE int lu_decompose_matrix(double **A, int n, int *perms) { 00629 int i, j, k, ip; 00630 double max, sum, tmp; 00631 00632 double *scal = (double *)malloc(n*sizeof(double)); 00633 00634 /* loop over rows and store implicit scaling factors */ 00635 for (i=0; i<n; i++) { 00636 max = 0.0; 00637 for (j=0; j<n; j++) { 00638 if ( (tmp=fabs(A[i][j])) > max) max=tmp; 00639 } 00640 if (max == 0.0) { 00641 /* matrix has a zero row and is singular */ 00642 return -1; 00643 } 00644 scal[i] = 1.0/max; 00645 } 00646 00647 /** Crout's algorithm: Calculate L and U columnwise from top to 00648 * bottom. The diagonal elements of L are chosen to be 1. Only 00649 * previously determined entries are used in the calculation. The 00650 * original matrix elements are used only once and can be 00651 * overwritten with the elements of L and U, the diagonal of L not 00652 * being stored. Rows may be permuted according to the largest 00653 * element (pivot) in the lower part, where rows are normalized to 00654 * have the largest element scaled to unity. 00655 */ 00656 00657 /* loop over columns */ 00658 for (j=0; j<n; j++) { 00659 00660 /* calculate upper triangle part (without diagonal) */ 00661 for (i=0; i<j; i++) { 00662 sum = A[i][j]; 00663 for (k=0;k<=i-1;k++) sum -= A[i][k]*A[k][j]; 00664 A[i][j] = sum; 00665 } 00666 00667 /* calculate diagonal and lower triangle part */ 00668 /* pivot is determined on the fly, but not yet divided by */ 00669 ip = j; 00670 max = 0.0; 00671 for (i=j; i<n; i++) { 00672 sum = A[i][j]; 00673 for (k=0; k<=j-1; k++) sum -= A[i][k]*A[k][j]; 00674 A[i][j] = sum; 00675 if ((tmp=scal[i]*fabs(sum)) > max) { 00676 max = tmp; 00677 ip = i; 00678 } 00679 } 00680 00681 /* swap rows according to pivot index */ 00682 if (j != ip) { 00683 for (k=0; k<n; k++) { 00684 tmp = A[j][k]; 00685 A[j][k] = A[ip][k]; 00686 A[ip][k] = tmp; 00687 } 00688 scal[ip] = scal[j]; 00689 } 00690 perms[j] = ip; 00691 00692 if (A[j][j] == 0.0) { 00693 /* zero pivot indicates singular matrix */ 00694 return -1; 00695 } 00696 00697 /* now divide by pivot element */ 00698 if (j != n) { 00699 tmp = 1.0/A[j][j]; 00700 for (i=j+1; i<n; i++) 00701 A[i][j] *= tmp; 00702 } 00703 00704 } 00705 00706 free(scal); 00707 00708 return 0; 00709 } 00710 00711 /** Solve the linear equation system for a LU decomposed matrix A. 00712 * Uses forward substitution for the lower triangle part and 00713 * backsubstitution for the upper triangle part. Row permutations as 00714 * indicated in perms are applied to b accordingly. The solution is 00715 * written to b in place. 00716 * @param A Matrix in LU decomposed form (Input) 00717 * @param n Dimension of the matrix (Input) 00718 * @param perms Indicates row permutations due to pivoting (Input) 00719 * @param b Right-hand side of equation system (Input). 00720 * Is destroyed and contains the solution x afterwards (Output). 00721 */ 00722 MDINLINE void lu_solve_system(double **A, int n, int *perms, double *b) { 00723 int i, j; 00724 double sum; 00725 00726 /* Step 1: Solve Ly=b */ 00727 00728 /* forward substitution for lower triangle part */ 00729 for (i=0; i<n; i++) { 00730 /* take care of the correct permutations */ 00731 sum=b[perms[i]]; 00732 b[perms[i]]=b[i]; 00733 for (j=0; j<=i-1; j++) sum -= A[i][j]*b[j]; 00734 b[i] = sum; 00735 } 00736 00737 /* Step 2: Solve Ux=y */ 00738 00739 /* backsubstitution for upper triangle part */ 00740 for (i=n-1; i>=0; i--) { 00741 sum = b[i]; 00742 for (j=i+1; j<n; j++) sum -= A[i][j]*b[j]; 00743 b[i]=sum/A[i][i]; 00744 } 00745 00746 } 00747 /*@}*/ 00748 00749 /*************************************************************/ 00750 /** \name Three dimensional grid operations */ 00751 /*************************************************************/ 00752 /*@{*/ 00753 00754 /** get the linear index from the position (a,b,c) in a 3D grid 00755 * of dimensions adim[]. returns linear index. 00756 * 00757 * @return the linear index 00758 * @param a x position 00759 * @param b y position 00760 * @param c z position 00761 * @param adim dimensions of the underlying grid 00762 */ 00763 MDINLINE int get_linear_index(int a, int b, int c, int adim[3]) 00764 { 00765 return (a + adim[0]*(b + adim[1]*c)); 00766 } 00767 00768 /** get the position a[] from the linear index in a 3D grid 00769 * of dimensions adim[]. 00770 * 00771 * @param i linear index 00772 * @param a x position (return value) 00773 * @param b y position (return value) 00774 * @param c z position (return value) 00775 * @param adim dimensions of the underlying grid 00776 */ 00777 MDINLINE void get_grid_pos(int i, int *a, int *b, int *c, int adim[3]) 00778 { 00779 *a = i % adim[0]; 00780 i /= adim[0]; 00781 *b = i % adim[1]; 00782 i /= adim[1]; 00783 *c = i; 00784 } 00785 00786 /** Malloc a 3d grid for doubles with dimension dim[3] . 00787 * @param grid pointer to grid. 00788 * @param dim dimension of the grid. 00789 */ 00790 MDINLINE int malloc_3d_grid(double ****grid, int dim[3]) 00791 { 00792 int i,j; 00793 *grid = (double***)malloc(sizeof(double **)*dim[0]); 00794 if(*grid==NULL) return 0; 00795 for(i=0;i<dim[0];i++) { 00796 (*grid)[i] = (double**)malloc(sizeof(double *)*dim[1]); 00797 if((*grid)[i]==NULL) return 0; 00798 for(j=0;j<dim[1];j++) { 00799 (*grid)[i][j] = (double*)malloc(sizeof(double)*dim[2]); 00800 if((*grid)[i][j]==NULL) return 0; 00801 } 00802 } 00803 return 1; 00804 } 00805 00806 /** print a block of a 3D array. 00807 * @param data 3D array. 00808 * @param start start coordinate for the block. 00809 * @param size size of the block. 00810 * @param dim dimension of the array. 00811 * @param element size of the elements in the array. 00812 * @param num number of element to print. 00813 00814 */ 00815 MDINLINE void print_block(double *data, int start[3], int size[3], int dim[3], int element, int num) 00816 { 00817 int i0,i1,i2,b=1; 00818 int divide=0,block1=0,start1; 00819 double tmp; 00820 00821 while(divide==0) { 00822 if(b*size[2] > 7) { 00823 block1=b; 00824 divide = (int)ceil(size[1]/(double)block1); 00825 } 00826 b++; 00827 } 00828 fprintf(stderr,"?: print_block (%d of %d): (%d,%d,%d)+(%d,%d,%d) from grid (%d,%d,%d)\n", 00829 num+1,element, 00830 start[0],start[1],start[2],size[0],size[1],size[2],dim[0],dim[1],dim[2]); 00831 for(b=0;b<divide;b++) { 00832 start1 = b*block1+start[1]; 00833 for(i0=start[0]+size[0]-1; i0>=start[0]; i0--) { 00834 for(i1=start1; i1<imin(start1+block1,start[1]+size[1]);i1++) { 00835 for(i2=start[2]; i2<start[2]+size[2];i2++) { 00836 tmp=data[num+(element*(i2+dim[2]*(i1+dim[1]*i0)))]; 00837 if(tmp<0) fprintf(stderr,"%1.2e",tmp); 00838 else fprintf(stderr," %1.2e",tmp); 00839 } 00840 fprintf(stderr," | "); 00841 } 00842 fprintf(stderr,"\n"); 00843 } 00844 fprintf(stderr,"\n"); 00845 } 00846 } 00847 /*@}*/ 00848 00849 00850 /*************************************************************/ 00851 /** \name Distance calculations. */ 00852 /*************************************************************/ 00853 /*@{*/ 00854 00855 /** returns the distance between two position. 00856 * \param pos1 Position one. 00857 * \param pos2 Position two. 00858 */ 00859 MDINLINE double distance(double pos1[3], double pos2[3]) 00860 { 00861 return sqrt( SQR(pos1[0]-pos2[0]) + SQR(pos1[1]-pos2[1]) + SQR(pos1[2]-pos2[2]) ); 00862 } 00863 00864 /** returns the distance between two positions squared. 00865 * \param pos1 Position one. 00866 * \param pos2 Position two. 00867 */ 00868 MDINLINE double distance2(double pos1[3], double pos2[3]) 00869 { 00870 return SQR(pos1[0]-pos2[0]) + SQR(pos1[1]-pos2[1]) + SQR(pos1[2]-pos2[2]); 00871 } 00872 00873 /** Returns the distance between two positions squared and stores the 00874 distance vector pos1-pos2 in vec. 00875 * \param pos1 Position one. 00876 * \param pos2 Position two. 00877 * \param vec vecotr pos1-pos2. 00878 * \return distance squared 00879 */ 00880 MDINLINE double distance2vec(double pos1[3], double pos2[3], double vec[3]) 00881 { 00882 vec[0] = pos1[0]-pos2[0]; 00883 vec[1] = pos1[1]-pos2[1]; 00884 vec[2] = pos1[2]-pos2[2]; 00885 return SQR(vec[0]) + SQR(vec[1]) + SQR(vec[2]); 00886 } 00887 00888 /** returns the distance between the unfolded coordintes of two particles. 00889 * \param pos1 Position of particle one. 00890 * \param image_box1 simulation box index of particle one . 00891 * \param pos2 Position of particle two. 00892 * \param image_box2 simulation box index of particle two . 00893 * \param box_l size of simulation box. 00894 */ 00895 MDINLINE double unfolded_distance(double pos1[3], int image_box1[3], 00896 double pos2[3], int image_box2[3], double box_l[3]) 00897 { 00898 int i; 00899 double dist = 0; 00900 double lpos1[3],lpos2[3]; 00901 for(i=0;i<3;i++){ 00902 lpos1[i] = pos1[i]; 00903 lpos2[i] = pos2[i]; 00904 lpos1[i] += image_box1[i]*box_l[i]; 00905 lpos2[i] += image_box2[i]*box_l[i]; 00906 dist += SQR(lpos1[i]-lpos2[i]); 00907 } 00908 return sqrt(dist); 00909 } 00910 /*@}*/ 00911 00912 /*************************************************************/ 00913 /** \name String helper functions */ 00914 /*************************************************************/ 00915 /*@{*/ 00916 00917 /** extend a string with another one. Like strcat, just automatically 00918 increases the string space */ 00919 MDINLINE char *strcat_alloc(char *left, char *right) 00920 { 00921 if (!left) { 00922 char *res = (char *)malloc(strlen(right) + 1); 00923 strcpy(res, right); 00924 return res; 00925 } 00926 else { 00927 char *res = (char *)realloc(left, strlen(left) + strlen(right) + 1); 00928 strcat(res, right); 00929 return res; 00930 } 00931 } 00932 00933 /*@}*/ 00934 00935 /*************************************************************/ 00936 /** \name Object-in-fluid functions */ 00937 /*************************************************************/ 00938 /*@{*/ 00939 00940 /** Computes the area of triangle between vectors P1 and P2, 00941 * by computing the crossproduct P1 x P2 and taking the half of its norm */ 00942 MDINLINE double area_triangle_new(double *P1, double *P2) { 00943 double area; 00944 double normal[3], n; //auxiliary variables 00945 vector_product(P1,P2,normal); 00946 n=normr(normal); 00947 area = 0.5*n; 00948 return area; 00949 } 00950 00951 /** Computes the area of triangle between vectors P1,P2,P3, 00952 * by computing the crossproduct P1P2 x P1P3 and taking the half of its norm */ 00953 MDINLINE double area_triangle(double *P1, double *P2, double *P3) { 00954 double area; 00955 double u[3],v[3],normal[3], n; //auxiliary variables 00956 u[0] = P2[0] - P1[0]; // u = P1P2 00957 u[1] = P2[1] - P1[1]; 00958 u[2] = P2[2] - P1[2]; 00959 v[0] = P3[0] - P1[0]; // v = P1P3 00960 v[1] = P3[1] - P1[1]; 00961 v[2] = P3[2] - P1[2]; 00962 vector_product(u,v,normal); 00963 n=normr(normal); 00964 area = 0.5*n; 00965 return area; 00966 } 00967 00968 /** Computes the normal vector to the plane given by points P1P2P3 */ 00969 MDINLINE void get_n_triangle(double* p1, double* p2, double* p3, double* n){ 00970 n[0]=(p2[1]-p1[1])*(p3[2]-p1[2])-(p2[2]-p1[2])*(p3[1]-p1[1]); 00971 n[1]=(p2[2]-p1[2])*(p3[0]-p1[0])-(p2[0]-p1[0])*(p3[2]-p1[2]); 00972 n[2]=(p2[0]-p1[0])*(p3[1]-p1[1])-(p2[1]-p1[1])*(p3[0]-p1[0]); 00973 } 00974 00975 /** This function returns the angle btw the triangle p1,p2,p3 and p2,p3,p4. 00976 * Be careful, the angle depends on the orientation of the trianlges! 00977 * You need to be sure that the orientation (direction of normal vector) 00978 * of p1p2p3 is given by the cross product p2p1 x p2p3. 00979 * The orientation of p2p3p4 must be given by p2p3 x p2p4. 00980 * 00981 * Example: p1 = (0,0,1), p2 = (0,0,0), p3=(1,0,0), p4=(0,1,0). 00982 * The orientation of p1p2p3 should be in the direction (0,1,0) 00983 * and indeed: p2p1 x p2p3 = (0,0,1)x(1,0,0) = (0,1,0) 00984 * This function is called in the beginning of the simulation when creating 00985 * bonds depending on the angle btw the triangles, the bending_force. 00986 * Here, we determine the orientations by looping over the triangles 00987 * and checking the correct orientation. So when defining the bonds by tcl command 00988 * "part p2 bond xxxx p1 p3 p4", we correctly input the particle id's. 00989 * So if you have the access to the order of particles, you are safe to call this 00990 * function with exactly this order. Otherwise you need to check the orientations. */ 00991 MDINLINE double angle_btw_triangles(double *P1, double *P2, double *P3, double *P4) { 00992 double phi; 00993 double u[3],v[3],normal1[3],normal2[3]; //auxiliary variables 00994 u[0] = P1[0] - P2[0]; // u = P2P1 00995 u[1] = P1[1] - P2[1]; 00996 u[2] = P1[2] - P2[2]; 00997 v[0] = P3[0] - P2[0]; // v = P2P3 00998 v[1] = P3[1] - P2[1]; 00999 v[2] = P3[2] - P2[2]; 01000 vector_product(u,v,normal1); 01001 u[0] = P3[0] - P2[0]; // u = P2P3 01002 u[1] = P3[1] - P2[1]; 01003 u[2] = P3[2] - P2[2]; 01004 v[0] = P4[0] - P2[0]; // v = P2P4 01005 v[1] = P4[1] - P2[1]; 01006 v[2] = P4[2] - P2[2]; 01007 vector_product(u,v,normal2); 01008 01009 double tmp11,tmp22,tmp33; 01010 // Now we compute the scalar product of n1 and n2 divided by the norms of n1 and n2 01011 //tmp11 = dot(3,normal1,normal2); // tmp11 = n1.n2 01012 tmp11 = scalar(normal1,normal2); // tmp11 = n1.n2 01013 01014 /* 01015 tmp22 = normr(normal1); 01016 tmp33 = normr(normal2); 01017 tmp11 /= (tmp22*tmp33); // tmp11 = n1.n2/(|n1||n2|) 01018 */ 01019 tmp11 *= fabs(tmp11); // tmp11 = (n1.n2)^2 01020 tmp22 = sqrlen(normal1); //tmp22 = |n1|^2 01021 tmp33 = sqrlen(normal2); //tmp33 = |n1|^2 01022 tmp11 /= (tmp22*tmp33); // tmp11 = (n1.n2/(|n1||n2|))^2 01023 if (tmp11 > 0 ) { 01024 tmp11 = sqrt(tmp11); 01025 } else { 01026 tmp11 = - sqrt(- tmp11); 01027 } 01028 01029 if(tmp11>=1.) { tmp11=0.0;} 01030 else if(tmp11<=-1.) { tmp11=M_PI;} 01031 phi = M_PI - acos(tmp11); // The angle between the faces (not considering the orientation, always less or equal to Pi) is 01032 // equal to Pi minus angle between the normals 01033 01034 // Now we need to determine, if the angle btw two triangles is less than Pi or more than Pi. To do this we check, 01035 // if the point P4 lies in the halfspace given by trianlge P1P2P3 and the normal to this triangle. If yes, we have 01036 // angle less than Pi, if not, we have angle more than Pi. 01037 // General equation of the plane is n_x*x + n_y*y + n_z*z + d = 0 where (n_x,n_y,n_z) is the normal to the plane. 01038 // Point P1 lies in the plane, therefore d = -(n_x*P1_x + n_y*P1_y + n_z*P1_z) 01039 // Point P4 lies in the halfspace given by normal iff n_x*P4_x + n_y*P4_y + n_z*P4_z + d >= 0 01040 tmp11 = - (normal1[0]*P1[0] + normal1[1]*P1[1] + normal1[2]*P1[2]); 01041 if (normal1[0]*P4[0] + normal1[1]*P4[1] + normal1[2]*P4[2] + tmp11 < 0) phi = 2*M_PI - phi; 01042 return phi; 01043 } 01044 01045 /*@}*/ 01046 01047 #endif
1.7.5.1