ESPResSo 3.2.0-11-g9950804-git
Extensible Simulation Package for Soft Matter Research
p3m_tcl.c
Go to the documentation of this file.
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 #include "parser.h"
00022 
00023 #ifdef P3M
00024 #include "p3m_tcl.h"
00025 #include "p3m.h"
00026 
00027 int tclcommand_inter_coulomb_parse_p3m_tune(Tcl_Interp * interp, int argc, char ** argv, int adaptive)
00028 {
00029   int mesh = -1, cao = -1, n_interpol = -1;
00030   double r_cut = -1, accuracy = -1;
00031 
00032   while(argc > 0) {
00033     if(ARG0_IS_S("r_cut")) {
00034       if (! (argc > 1 && ARG1_IS_D(r_cut) && r_cut >= -1)) {
00035         Tcl_AppendResult(interp, "r_cut expects a positive double",
00036                          (char *) NULL);
00037         return TCL_ERROR;
00038       }
00039       
00040     } else if(ARG0_IS_S("mesh")) {
00041       if(! (argc > 1 && ARG1_IS_I(mesh) && mesh >= -1)) {
00042         Tcl_AppendResult(interp, "mesh expects an integer >= -1",
00043                          (char *) NULL);
00044         return TCL_ERROR;
00045       }
00046       
00047     } else if(ARG0_IS_S("cao")) {
00048       if(! (argc > 1 && ARG1_IS_I(cao) && cao >= -1 && cao <= 7)) {
00049         Tcl_AppendResult(interp, "cao expects an integer between -1 and 7",
00050                          (char *) NULL);
00051         return TCL_ERROR;
00052       } 
00053 
00054     } else if(ARG0_IS_S("accuracy")) {
00055       if(! (argc > 1 && ARG1_IS_D(accuracy) && accuracy > 0)) {
00056         Tcl_AppendResult(interp, "accuracy expects a positive double",
00057                          (char *) NULL);
00058         return TCL_ERROR;
00059       }
00060 
00061     } else if (ARG0_IS_S("n_interpol")) {
00062       if (! (argc > 1 && ARG1_IS_I(n_interpol) && n_interpol >= 0)) {
00063         Tcl_AppendResult(interp, "n_interpol expects an nonnegative integer", (char *) NULL);
00064         return TCL_ERROR;
00065       }
00066     }
00067     /* unknown parameter. Probably one of the optionals */
00068     else break;
00069     
00070     argc -= 2;
00071     argv += 2;
00072   }
00073   p3m_set_tune_params(r_cut, mesh, cao, -1.0, accuracy, n_interpol);
00074 
00075   /* check for optional parameters */
00076   if (argc > 0) {
00077     if (tclcommand_inter_coulomb_parse_p3m_opt_params(interp, argc, argv) == TCL_ERROR)
00078       return TCL_ERROR;
00079   }
00080 
00081   /* do the tuning */
00082   char *log = NULL;
00083   if (p3m_adaptive_tune(&log) == ES_ERROR) {  
00084     Tcl_AppendResult(interp, log, "\nfailed to tune P3M parameters to required accuracy", (char *) NULL);
00085     if (log)
00086       free(log);
00087     return TCL_ERROR;
00088   }
00089   
00090   /* Tell the user about the tuning outcome */
00091   Tcl_AppendResult(interp, log, (char *) NULL);
00092 
00093   if (log)
00094     free(log);
00095 
00096   return TCL_OK;
00097 }
00098 
00099 int tclcommand_inter_coulomb_parse_p3m(Tcl_Interp * interp, int argc, char ** argv)
00100 {
00101   double r_cut, alpha, accuracy = -1.0;
00102   int mesh[3], cao, i;
00103   IntList il;
00104   init_intlist(&il);
00105 
00106   if (argc < 1) {
00107     Tcl_AppendResult(interp, "expected: inter coulomb <bjerrum> p3m tune | <r_cut> { <mesh> | \\{ <mesh_x> <mesh_y> <mesh_z> \\} } <cao> [<alpha> [<accuracy>]]",
00108                      (char *) NULL);
00109     return TCL_ERROR;  
00110   }
00111 
00112   if (ARG0_IS_S("tune"))
00113     return tclcommand_inter_coulomb_parse_p3m_tune(interp, argc-1, argv+1, 0);
00114 
00115   if (ARG0_IS_S("tunev2"))
00116     return tclcommand_inter_coulomb_parse_p3m_tune(interp, argc-1, argv+1, 1);
00117       
00118   if(! ARG0_IS_D(r_cut))
00119     return TCL_ERROR;  
00120 
00121   if(argc < 3 || argc > 5) {
00122     Tcl_AppendResult(interp, "wrong # arguments: inter coulomb <bjerrum> p3m <r_cut> { <mesh> | \\{ <mesh_x> <mesh_y> <mesh_z> \\} } <cao> [<alpha> [<accuracy>]]",
00123                      (char *) NULL);
00124     return TCL_ERROR;  
00125   }
00126 
00127   if(! ARG_IS_I(1, mesh[0])) {
00128     if( ! ARG_IS_INTLIST(1, il) || !(il.n == 3) ) {
00129       Tcl_AppendResult(interp, "integer or interger list of length 3 expected", (char *) NULL);
00130       return TCL_ERROR;
00131     } else {
00132       mesh[0] = il.e[0];
00133       mesh[1] = il.e[1];
00134       mesh[2] = il.e[2];
00135     }
00136   } else {
00137     mesh[1] = mesh[2] = mesh[0];
00138   }
00139 
00140   if(! ARG_IS_I(2, cao)) {
00141     Tcl_AppendResult(interp, "integer expected", (char *) NULL);
00142     return TCL_ERROR;
00143   }
00144         
00145   if(argc > 3) {
00146     if(! ARG_IS_D(3, alpha))
00147       return TCL_ERROR;
00148   }
00149   else {
00150     Tcl_AppendResult(interp, "Automatic p3m tuning not implemented.",
00151                      (char *) NULL);
00152     return TCL_ERROR;  
00153   }
00154 
00155   if(argc > 4) {
00156     if(! ARG_IS_D(4, accuracy)) {
00157       Tcl_AppendResult(interp, "double expected", (char *) NULL);
00158       return TCL_ERROR;
00159     }
00160   }
00161 
00162   if ((i = p3m_set_params(r_cut, mesh, cao, alpha, accuracy)) < 0) {
00163     switch (i) {
00164     case -1:
00165       Tcl_AppendResult(interp, "r_cut must be positive", (char *) NULL);
00166       break;
00167     case -2:
00168       Tcl_AppendResult(interp, "mesh must be positive", (char *) NULL);
00169       break;
00170     case -3:
00171       Tcl_AppendResult(interp, "cao must be between 1 and 7 and less than mesh",
00172                        (char *) NULL);
00173       break;
00174     case -4:
00175       Tcl_AppendResult(interp, "alpha must be positive", (char *) NULL);
00176       break;
00177     case -5:
00178       Tcl_AppendResult(interp, "accuracy must be positive", (char *) NULL);
00179       break;
00180     default:;
00181       Tcl_AppendResult(interp, "unspecified error", (char *) NULL);
00182     }
00183 
00184     return TCL_ERROR;
00185   }
00186 
00187   return TCL_OK;
00188 }
00189 
00190 
00191 int tclcommand_inter_coulomb_parse_p3m_opt_params(Tcl_Interp * interp, int argc, char ** argv)
00192 {
00193   int i; double d1, d2, d3;
00194 
00195   Tcl_ResetResult(interp);
00196 
00197   while (argc > 0) {
00198     /* p3m parameter: inter */
00199     if (ARG0_IS_S("n_interpol")) {
00200       
00201       if(argc < 2) {
00202         Tcl_AppendResult(interp, argv[0], " needs 1 parameter",
00203                          (char *) NULL);
00204         return TCL_ERROR;
00205       }
00206       
00207       if (! ARG1_IS_I(i)) {
00208         Tcl_AppendResult(interp, argv[0], " needs 1 INTEGER parameter",
00209                          (char *) NULL);
00210         return TCL_ERROR;
00211       }
00212       
00213       if (p3m_set_ninterpol(i) == TCL_ERROR) {
00214         Tcl_AppendResult(interp, argv[0], " argument must be positive",
00215                          (char *) NULL);
00216         return TCL_ERROR;
00217       }
00218 
00219       argc -= 2;
00220       argv += 2;
00221     }
00222     
00223     /* p3m parameter: mesh_off */
00224     else if (ARG0_IS_S("mesh_off")) {
00225       
00226       if(argc < 4) {
00227         Tcl_AppendResult(interp, argv[0], " needs 3 parameters",
00228                          (char *) NULL);
00229         return TCL_ERROR;
00230       }
00231         
00232       if ((! ARG_IS_D(1, d1)) ||
00233           (! ARG_IS_D(2, d2)) ||
00234           (! ARG_IS_D(3, d3)))
00235         {
00236           Tcl_AppendResult(interp, argv[0], " needs 3 DOUBLE parameters",
00237                            (char *) NULL);
00238           return TCL_ERROR;
00239         }
00240 
00241       if (p3m_set_mesh_offset(d1, d2 ,d3) == TCL_ERROR)
00242         {
00243           Tcl_AppendResult(interp, argv[0], " parameters have to be between 0.0 an 1.0",
00244                            (char *) NULL);
00245           return TCL_ERROR;
00246         }
00247 
00248       argc -= 4;
00249       argv += 4;
00250     }
00251     
00252     /* p3m parameter: epsilon */
00253     else if(ARG0_IS_S( "epsilon")) {
00254 
00255       if(argc < 2) {
00256         Tcl_AppendResult(interp, argv[0], " needs 1 parameter",
00257                          (char *) NULL);
00258         return TCL_ERROR;
00259       }
00260 
00261       if (ARG1_IS_S("metallic")) {
00262         d1 = P3M_EPSILON_METALLIC;
00263       }
00264       else if (! ARG1_IS_D(d1)) {
00265         Tcl_AppendResult(interp, argv[0], " needs 1 DOUBLE parameter or \"metallic\"",
00266                          (char *) NULL);
00267         return TCL_ERROR;
00268       }
00269         
00270       if (p3m_set_eps(d1) == TCL_ERROR) {
00271         Tcl_AppendResult(interp, argv[0], " There is no error msg yet!",
00272                          (char *) NULL);
00273         return TCL_ERROR;
00274       }
00275 
00276       argc -= 2;
00277       argv += 2;            
00278     }
00279     else {
00280       Tcl_AppendResult(interp, "Unknown coulomb p3m parameter: \"",argv[0],"\"",(char *) NULL);
00281       return TCL_ERROR;
00282     }
00283   }
00284 
00285   return TCL_OK;
00286 }
00287 
00288 /*********************** miscelanea of functions *************************************/
00289 
00290 int tclprint_to_result_p3m(Tcl_Interp *interp)
00291 {
00292   char buffer[TCL_DOUBLE_SPACE];
00293 
00294   Tcl_PrintDouble(interp, p3m.params.r_cut, buffer);
00295   Tcl_AppendResult(interp, "p3m ", buffer, " ", (char *) NULL);
00296   sprintf(buffer,"%d",p3m.params.mesh[0]);
00297   Tcl_AppendResult(interp, buffer, " ", (char *) NULL);
00298   sprintf(buffer,"%d",p3m.params.cao);
00299   Tcl_AppendResult(interp, buffer, " ", (char *) NULL);
00300   Tcl_PrintDouble(interp, p3m.params.alpha, buffer);
00301   Tcl_AppendResult(interp, buffer, " ", (char *) NULL);
00302   Tcl_PrintDouble(interp, p3m.params.accuracy, buffer);
00303   Tcl_AppendResult(interp, buffer, (char *) NULL);
00304 
00305   Tcl_AppendResult(interp, "} {coulomb epsilon ", (char *) NULL);
00306   if (p3m.params.epsilon == P3M_EPSILON_METALLIC)
00307     Tcl_AppendResult(interp, " metallic ", (char *) NULL);
00308   else {
00309     Tcl_PrintDouble(interp, p3m.params.epsilon, buffer);
00310     Tcl_AppendResult(interp, buffer, " ", (char *) NULL);
00311   }
00312   sprintf(buffer,"%d",p3m.params.inter);
00313   Tcl_AppendResult(interp, "n_interpol ", buffer, " ", (char *) NULL);
00314   Tcl_PrintDouble(interp, p3m.params.mesh_off[0], buffer);
00315   Tcl_AppendResult(interp, "mesh_off ", buffer, " ", (char *) NULL);
00316   Tcl_PrintDouble(interp, p3m.params.mesh_off[1], buffer);
00317   Tcl_AppendResult(interp, buffer, " ", (char *) NULL);
00318   Tcl_PrintDouble(interp, p3m.params.mesh_off[2], buffer);
00319   Tcl_AppendResult(interp, buffer, (char *) NULL);
00320 
00321   return TCL_OK;
00322 }
00323 
00324 /************************************************
00325  * Debug functions printing p3m structures 
00326  ************************************************/
00327 
00328 #endif /* of P3M */
00329