/* Copyright 2016 Ian Jauslin Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ #include #include // define MPFR_USE_VA_LIST to enable the use of mpfr_inits and mpfr_clears #define MPFR_USE_VA_LIST #include #include #include #include "types.h" #include "hh_integral.h" #include "hh_root.h" #include "hh_integral_double.h" #include "hh_root_double.h" #include "ss_integral_double.h" #include "zz_integral.h" #include "zz_integral_double.h" #include "parser.h" #include "definitions.h" // usage message int print_usage(); // read arguments int read_args(int argc, char* argv[], hh_params* params, mpfr_t tolerance, unsigned int* maxiter, unsigned int* order, unsigned int* computation_nr, unsigned int* threads, unsigned int* use_double); // compute the first loop correction to the topological phase diagram int compute_hh(hh_params params, mpfr_t tolerance, unsigned int maxiter, unsigned int order); // using doubles instead of mpfr int compute_hh_double(hh_params params, mpfr_t tolerance, unsigned int maxiter, unsigned int order); // compute the sunrise diagram int compute_ss(TYPE_I, hh_params params, mpfr_t tolerance, unsigned int maxiter, unsigned int order, unsigned int threads); // using doubles instead of mpfr int compute_ss_double(TYPE_I_DOUBLE, hh_params params, mpfr_t tolerance, unsigned int maxiter, unsigned int order, unsigned int threads); // codes for possible computations #define COMPUTATION_PHASE 1 #define COMPUTATION_ZZ 2 #define COMPUTATION_ZZZZ 3 int main(int argc, char* argv[]){ hh_params params; mpfr_t tolerance; unsigned int maxiter; unsigned int order; int ret; unsigned int computation_nr; unsigned int threads; unsigned int use_double; // default computation: phase diagram computation_nr=COMPUTATION_PHASE; mpfr_inits(params.W, params.sinphi, params.phi, params.t1, params.t2, params.lambda, tolerance, NULL); // read command line arguments ret=read_args(argc, argv, ¶ms, tolerance, &maxiter, &order, &computation_nr, &threads, &use_double); if(ret<0){ mpfr_clears(params.W, params.sinphi, params.phi, params.t1, params.t2, params.lambda, tolerance, NULL); return(-1); } if(ret>0){ mpfr_clears(params.W, params.sinphi, params.phi, params.t1, params.t2, params.lambda, tolerance, NULL); return(0); } // phase diagram if(computation_nr==COMPUTATION_PHASE){ // compute the first-loop correction to the phase diagram if(use_double==0){ compute_hh(params, tolerance, maxiter, order); } else{ compute_hh_double(params, tolerance, maxiter, order); } } else if(computation_nr==COMPUTATION_ZZ){ // compute second-order correction to z1-z2 if(use_double==0){ compute_ss(&zz_I, params, tolerance, maxiter, order, threads); } else{ compute_ss_double(&zz_I_double, params, tolerance, maxiter, order, threads); } } else if(computation_nr==COMPUTATION_ZZZZ){ // compute second-order correction to z1+z2 if(use_double==0){ compute_ss(&ZZ_I, params, tolerance, maxiter, order, threads); } else{ compute_ss_double(&ZZ_I_double, params, tolerance, maxiter, order, threads); } } mpfr_clears(params.W, params.sinphi, params.phi, params.t1, params.t2, params.lambda, tolerance, NULL); return(0); } // usage message int print_usage(){ fprintf(stderr, "usage:\n hhtop phase [-p params] [-v] [-O order] [-t tolerance] [-N maxiter] [-P precision] [-E emax]\n hhtop z1-z2 [-p params] [-v] [-O order] [-t tolerance] [-N maxiter] [-P precision] [-E emax] [-C threads]\n hhtop z1+z2 [-p params] [-v] [-O order] [-t tolerance] [-N maxiter] [-P precision] [-E emax] [-C threads]\n\n hhtop -D phase [-p params] [-v] [-O order] [-t tolerance] [-N maxiter]\n hhtop -D z1-z2 [-p params] [-v] [-O order] [-t tolerance] [-N maxiter] [-C threads]\n\n hhtop -V [-v]\n\n"); return(0); } // read command line arguments #define CP_FLAG_PARAMS 1 #define CP_FLAG_ORDER 2 #define CP_FLAG_TOLERANCE 3 #define CP_FLAG_MAXITER 4 #define CP_FLAG_MPFR_PREC 5 #define CP_FLAG_MPFR_EXP 6 #define CP_FLAG_THREADS 7 int read_args(int argc, char* argv[], hh_params* params, mpfr_t tolerance, unsigned int* maxiter, unsigned int* order, unsigned int* computation_nr, unsigned int* threads, unsigned int* use_double){ int i; int ret; // temporary long int long int tmp_lint; // temporary unsigned int unsigned int tmp_uint; // pointers char* ptr; // flag that indicates what argument is being read int flag=0; // pointer to various arguments char* tolerance_str=NULL; char* params_str=NULL; // whether to print the variables after they are read int print_vars=0; // keep track of which flags were used (to check for incompatibilities) unsigned char pflag=0; unsigned char Oflag=0; unsigned char tflag=0; unsigned char Nflag=0; unsigned char Pflag=0; unsigned char Eflag=0; unsigned char vflag=0; unsigned char Cflag=0; unsigned char Dflag=0; unsigned char Vflag=0; // defaults mpfr_set_d(params->t1, 1., MPFR_RNDN); mpfr_set_d(params->t2, .1, MPFR_RNDN); mpfr_set_d(params->lambda, .01, MPFR_RNDN); mpfr_set_d(params->sinphi, 1., MPFR_RNDN); mpfr_set_d(tolerance, 1e-11, MPFR_RNDN); *maxiter=1000000; *order=10; params->omega=+1; *threads=1; *use_double=0; mpfr_const_pi(params->phi, MPFR_RNDN); mpfr_div_ui(params->phi, params->phi, 2, MPFR_RNDN); // default W=-3*sqrt(3)*t2*sin(phi) mpfr_sqrt_ui(params->W, 3, MPFR_RNDN); mpfr_mul_si(params->W, params->W, -3, MPFR_RNDN); mpfr_mul(params->W, params->W, params->sinphi, MPFR_RNDN); mpfr_mul(params->W, params->W, params->t2, MPFR_RNDN); // loop over arguments for(i=1;iomega); fprintf(stderr, "\ntolerance="); fprint_mpfr(stderr,tolerance); fprintf(stderr, "\n"); fprintf(stderr, "order of integration=%d\n", *order); fprintf(stderr, "\nMPFR precision=%ld\n", mpfr_get_default_prec()); fprintf(stderr, "MPFR emax=%ld\n", mpfr_get_emax()); fprintf(stderr, "\n"); } return(0); } // compute the first loop correcion to the topological phase diagram int compute_hh(hh_params params, mpfr_t tolerance, unsigned int maxiter, unsigned int order){ mpfr_t val; int ret; args_integration args_int; // compute weights ret=gauss_legendre_weights_mpfr(order, tolerance, maxiter, &(args_int.abcissa), &(args_int.weights)); // return codes if(ret==LIBINUM_ERROR_MAXITER){ fprintf(stderr, "error: maximum number of iterations reached when computing the integration abcissa\n try increasing the precision or the tolerance\n"); return(ret); } else if(ret==LIBINUM_ERROR_NAN){ fprintf(stderr, "error: infinity encountered when computing the integration abcissa\n"); return(ret); } // set args args_int.params=params; mpfr_init(args_int.params.W); mpfr_init(val); // initial value mpfr_sqrt_ui(val, 3, MPFR_RNDN); mpfr_mul_ui(val, val, 3, MPFR_RNDN); mpfr_mul(val, val, params.sinphi, MPFR_RNDN); mpfr_mul(val, val, params.t2, MPFR_RNDN); if(params.omega==1){ mpfr_neg(val, val, MPFR_RNDN); } // compute root ret=root_newton_inplace_mpfr(&val, &integration_wrapper, &d_integration_wrapper, tolerance, maxiter, &args_int); // return codes if(ret==LIBINUM_ERROR_MAXITER){ fprintf(stderr, "error: maximum number of iterations reached when computing the solution to m=0\n try increasing the precision or the tolerance\n"); mpfr_clear(val); mpfr_clear(args_int.params.W); array_mpfr_free(args_int.abcissa); array_mpfr_free(args_int.weights); return(ret); } else if(ret==LIBINUM_ERROR_NAN){ fprintf(stderr, "error: infinity encountered: either the integrand is singular or the derivative of the integral vanishes at a point of the Newton iteration\n"); mpfr_clear(val); mpfr_clear(args_int.params.W); array_mpfr_free(args_int.abcissa); array_mpfr_free(args_int.weights); return(ret); } fprint_mpfr(stdout, val); printf("\n"); mpfr_clear(val); mpfr_clear(args_int.params.W); array_mpfr_free(args_int.abcissa); array_mpfr_free(args_int.weights); return(0); } // using double instead of mpfr int compute_hh_double(hh_params params, mpfr_t tolerance, unsigned int maxiter, unsigned int order){ long double tolerance_d; hh_args_integration_double args_int; long double val; int ret; // convert mpfr to double tolerance_d=mpfr_get_ld(tolerance, MPFR_RNDN); hh_params_todouble(&(args_int.params), params); // compute weights ret=gauss_legendre_weights_ldouble(order, tolerance_d, maxiter, &(args_int.abcissa), &(args_int.weights)); // return codes if(ret==LIBINUM_ERROR_MAXITER){ fprintf(stderr, "error: maximum number of iterations reached when computing the integration abcissa\n"); return(ret); } else if(ret==LIBINUM_ERROR_NAN){ fprintf(stderr, "error: infinity encountered when computing the integration abcissa\n"); return(ret); } // initial value val=-args_int.params.omega*3*sqrtl(3)*args_int.params.t2*args_int.params.sinphi; ret=root_newton_inplace_ldouble(&val, &hh_integration_wrapper_double, &hh_d_integration_wrapper_double, tolerance_d, maxiter, &args_int); // return codes if(ret==LIBINUM_ERROR_MAXITER){ fprintf(stderr, "error: maximum number of iterations reached when computing the solution to m=0\n"); array_ldouble_free(args_int.abcissa); array_ldouble_free(args_int.weights); return(ret); } else if(ret==LIBINUM_ERROR_NAN){ fprintf(stderr, "error: infinity encountered: either the integrand is singular or the derivative of the integral vanishes at a point of the Newton iteration\n"); array_ldouble_free(args_int.abcissa); array_ldouble_free(args_int.weights); return(ret); } printf("% .19Le\n",val); array_ldouble_free(args_int.abcissa); array_ldouble_free(args_int.weights); return(0); } // compute the sunrise diagram int compute_ss(TYPE_I, hh_params params, mpfr_t tolerance, unsigned int maxiter, unsigned int order, unsigned int threads){ mpfr_t val; int ret; array_mpfr abcissa; array_mpfr weights; // compute weights ret=gauss_legendre_weights_mpfr(order, tolerance, maxiter, &abcissa, &weights); // return codes if(ret==LIBINUM_ERROR_MAXITER){ fprintf(stderr, "error: maximum number of iterations reached when computing the integration abcissa\n try increasing the precision, the tolerance, or the maximal number of Newton steps\n"); return(ret); } else if(ret==LIBINUM_ERROR_NAN){ fprintf(stderr, "error: infinity encountered when computing the integration abcissa\n"); return(ret); } mpfr_init(val); // compute integral ret=ss_integrate(&val, I, params, abcissa, weights, threads); // return codes if(ret==LIBINUM_ERROR_NAN){ fprintf(stderr, "error: infinity encountered: the integrand is singular\n"); mpfr_clear(val); array_mpfr_free(abcissa); array_mpfr_free(weights); return(ret); } fprint_mpfr(stdout, val); printf("\n"); mpfr_clear(val); array_mpfr_free(abcissa); array_mpfr_free(weights); return(0); } // using doubles instead of mpfr int compute_ss_double(TYPE_I_DOUBLE, hh_params params, mpfr_t tolerance, unsigned int maxiter, unsigned int order, unsigned int threads){ long double tolerance_d; hh_params_double params_d; long double val; int ret; array_ldouble abcissa; array_ldouble weights; // convert mpfr to double tolerance_d=mpfr_get_ld(tolerance, MPFR_RNDN); hh_params_todouble(¶ms_d, params); // compute weights ret=gauss_legendre_weights_ldouble(order, tolerance_d, maxiter, &abcissa, &weights); // return codes if(ret==LIBINUM_ERROR_MAXITER){ fprintf(stderr, "error: maximum number of iterations reached when computing the integration abcissa\n try increasing the tolerance, or the maximal number of Newton steps\n"); return(ret); } else if(ret==LIBINUM_ERROR_NAN){ fprintf(stderr, "error: infinity encountered when computing the integration abcissa\n"); return(ret); } // compute integral ret=ss_integrate_double(&val, I, params_d, abcissa, weights, threads); // return codes if(ret==LIBINUM_ERROR_NAN){ fprintf(stderr, "error: infinity encountered: the integrand is singular\n"); array_ldouble_free(abcissa); array_ldouble_free(weights); return(ret); } printf("% .19Le\n",val); array_ldouble_free(abcissa); array_ldouble_free(weights); return(0); }