123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131 |
- /**********************************************************
-
- This software is part of J.-S. Caux's ABACUS library.
-
- Copyright (c) J.-S. Caux.
-
- -----------------------------------------------------------
-
- File: TBA_2CBG.cc
-
- Purpose: solves the TBA equations for the 2-component Bose gas
-
- ***********************************************************/
-
- #include "ABACUS.h"
-
- using namespace std;
- using namespace ABACUS;
-
- namespace ABACUS {
-
-
- /********************* 2CBG specific *******************/
-
-
- DP Asymptotic_2CBG_epsilon (int n, DP Omega, DP kBT)
- {
- return(2.0 * Omega * n + kBT * log(pow((1.0 - exp(-2.0 * (n + 1.0) * Omega/kBT))
- /(1.0 - exp(-2.0 * Omega/kBT)), 2.0) - exp(-2.0 * n * Omega/kBT)));
- }
-
- void Set_2CBG_Asymptotics (Root_Density_Set& TBA_Set, DP mu, DP Omega, DP kBT)
- {
- TBA_Set.epsilon[0].Set_Asymptotics (pow(TBA_Set.epsilon[0].lambdamax, 2.0) - mu - Omega);
- for (int n = 1; n < TBA_Set.ntypes; ++n) {
- TBA_Set.epsilon[n].Set_Asymptotics (Asymptotic_2CBG_epsilon(n, Omega, kBT));
- }
- }
-
- void Set_2CBG_deps_dchempot_Asymptotics (int option, const Root_Density_Set& Set, Root_Density_Set& DSet,
- DP mu, DP Omega, DP kBT)
- {
- // option == 0: deps/dmu
- // option == 1: deps/dOmega
-
- DP zeroasymptote = -1.0;
- DP em2OoT = exp(-2.0 * Omega/kBT);
- for (int n = 1; n < DSet.ntypes; ++n) {
- if (option == 0) DSet.epsilon[n].Set_Asymptotics (0.0);
- else if (option == 1)
- DSet.epsilon[n].Set_Asymptotics (2.0 * (1.0 - pow(em2OoT, n+1.0))
- * (n * (1.0 - pow(em2OoT, n+2.0)) - (n + 2.0) * em2OoT * (1.0 - pow(em2OoT, DP(n))))
- /((1.0 - em2OoT) * (1.0 - pow(em2OoT, DP(n))) * (1.0 - pow(em2OoT, n + 2.0))));
- zeroasymptote += DSet.epsilon[n].value_infty
- * exp(-Set.epsilon[n].value_infty/kBT)/(1.0 + exp(-Set.epsilon[n].value_infty/kBT));
- }
- // For n > nmax sum in RHS of BE for epsilon, assuming epsilon_n = epsilon_n^\infty in those cases:
- // Remember: nmax in notes is Set.ntypes - 1.
- zeroasymptote -= option == 0 ? 0.0
- : 2.0 * ((Set.ntypes + 1.0) * exp(-2.0 * (Set.ntypes + 1.0) * Omega/kBT)
- /(1.0 - exp(-2.0 * (Set.ntypes + 1.0) * Omega/kBT))
- - Set.ntypes * exp(-2.0 * Set.ntypes * Omega/kBT)/(1.0 - exp(-2.0 * Set.ntypes * Omega/kBT)));
-
- DSet.epsilon[0].Set_Asymptotics (zeroasymptote);
-
- return;
- }
-
- void Initiate_2CBG_TBA_Functions (Root_Density_Set& TBA_Set, DP mu, DP Omega)
- {
- for (int i = 0; i < TBA_Set.epsilon[0].Npts; ++i) {
- TBA_Set.epsilon[0].value[i] = TBA_Set.epsilon[0].lambda[i] * TBA_Set.epsilon[0].lambda[i] - mu - Omega;
- TBA_Set.epsilon[0].prev_value[i] = TBA_Set.epsilon[0].value[i];
- }
- for (int n = 1; n < TBA_Set.ntypes; ++n) {
- for (int i = 0; i < TBA_Set.epsilon[n].Npts; ++i)
- TBA_Set.epsilon[n].value[i] = TBA_Set.epsilon[n].value_infty;
- }
- }
-
- void Initiate_2CBG_deps_dchempot_Functions (Root_Density_Set& DSet)
- {
- for (int n = 0; n < DSet.ntypes; ++n) {
- for (int i = 0; i < DSet.epsilon[n].Npts; ++i)
- DSet.epsilon[n].value[i] = DSet.epsilon[n].value_infty;
- }
- }
-
- void Iterate_2CBG_TBAE (Root_Density_Set& Set, Vect<Vect<Vect_DP> >& a_n_dlambda, Vect<Vect<Vect_DP> >& fmin_dlambda,
- Vect<Vect<Vect_DP> >& fplus_dlambda, DP c_int, DP mu, DP Omega, DP kBT)
- {
- // Produces a new Root_Density_Set from a previous iteration.
- // Does NOT add types or change Npts, lambdamax values.
-
- // First define some useful functions:
- Vect<Vect_DP> Tln1plusemineps(Set.ntypes);
- Vect_DP Tln1pluseminepsinfty(Set.ntypes);
-
- for (int n = 0; n < Set.ntypes; ++n) {
-
- Tln1plusemineps[n] = Vect_DP (0.0, Set.epsilon[n].Npts);
-
- for (int i = 0; i < Set.epsilon[n].Npts; ++i) {
- Tln1plusemineps[n][i] = Set.epsilon[n].value[i] > 0.0 ?
- kBT * (Set.epsilon[n].value[i] < 24.0 * kBT ? log(1.0 + exp(-Set.epsilon[n].value[i]/kBT))
- : exp(-Set.epsilon[n].value[i]/kBT))
- :
- -Set.epsilon[n].value[i] + kBT * (-Set.epsilon[n].value[i] < 24.0 * kBT
- ? log (1.0 + exp(Set.epsilon[n].value[i]/kBT)) : exp(Set.epsilon[n].value[i]/kBT));
- // Keep previous rapidities:
- Set.epsilon[n].prev_value[i] = Set.epsilon[n].value[i];
- }
- Tln1pluseminepsinfty[n] = kBT * (Set.epsilon[n].value_infty < 24.0 * kBT
- ? log(1.0 + exp(-Set.epsilon[n].value_infty/kBT)) : exp(-Set.epsilon[n].value_infty/kBT));
- }
-
- // Now do the necessary convolutions for epsilon == epsilon[0].
- // For each value of lambda, do the convolutions:
- // Careful: the lambda's used for lambda (index i) are those of epsilon[0], the lambda' (index j) are for epsilon[n] !!
- Vect<Vect_DP> a_n_Tln_conv(Set.ntypes);
- for (int n = 0; n < Set.ntypes; ++n) {
- a_n_Tln_conv[n] = Vect_DP (0.0, Set.epsilon[0].Npts);
- Vect_DP f(0.0, Set.epsilon[n].Npts);
-
- for (int i = 0; i < Set.epsilon[0].Npts; ++i) {
- a_n_Tln_conv[n][i] = 0.0;
-
- for (int j = 0; j < Set.epsilon[n].Npts; ++j) a_n_Tln_conv[n][i] += Tln1plusemineps[n][j] * a_n_dlambda[i][n][j];
- // Add alpha curvature terms: VERY COSTLY, remove for now
- /*
- for (int j = 1; j < Set.epsilon[n].Npts - 1; ++j)
- a_n_Tln_conv[n][i] += (1.0/12.0) * pow(Set.epsilon[n].dlambda[j], 3.0)
- * ((Tln1plusemineps[n][j+1] * a_n_dlambda[i][n][j+1]
- - Tln1plusemineps[n][j] * a_n_dlambda[i][n][j])/(Set.epsilon[n].lambda[j+1] - Set.epsilon[n].lambda[j])
- - (Tln1plusemineps[n][j] * a_n_dlambda[i][n][j]
- - Tln1plusemineps[n][j-1] * a_n_dlambda[i][n][j-1])/(Set.epsilon[n].lambda[j] - Set.epsilon[n].lambda[j-1]))
- /(Set.epsilon[n].lambda[j+1] - Set.epsilon[n].lambda[j-1]);
- */
- } // for (int i ...
-
- } // for (int n... We now have all the a_n * Tln... at our disposal.
-
- // For n > nmax sum in RHS of BE for epsilon, assuming epsilon_n = epsilon_n^\infty in those cases:
- // Remember: nmax = Set.ntypes - 1
- DP Smaxsum = kBT * log((1.0 - exp(-2.0 * (Set.ntypes + 1.0) * Omega/kBT))/(1.0 - exp(-2.0 * Set.ntypes * Omega/kBT)));
-
- // Reconstruct the epsilon[0] function:
- for (int i = 0; i < Set.epsilon[0].Npts; ++i) {
- Set.epsilon[0].value[i] = pow(Set.epsilon[0].lambda[i], 2.0) - mu - Omega;
-
- // Add the convolutions:
- for (int n = 0; n < Set.ntypes; ++n)
- Set.epsilon[0].value[i] -= a_n_Tln_conv[n][i];
-
- // Add the asymptotic parts of convolutions:
- for (int n = 1; n < Set.ntypes; ++n)
- Set.epsilon[0].value[i] -= Tln1pluseminepsinfty[n]
- * (1.0 - (atan((Set.epsilon[n].lambdamax - Set.epsilon[0].lambda[i])/(0.5 * n * c_int))
- + atan((Set.epsilon[n].lambdamax + Set.epsilon[0].lambda[i])/(0.5 * n * c_int)))/PI);
-
- // Add the leftover summation for species n > nmax, assuming epsilon_n = epsilon_n^\infty in those cases:
- Set.epsilon[0].value[i] -= Smaxsum;
-
- // Include some damping:
- Set.epsilon[0].value[i] = 0.1 * Set.epsilon[0].prev_value[i] + 0.9 * Set.epsilon[0].value[i];
- // No need to force boundaries here, epsilon[0] is inherently stable.
- }
- // epsilon[0] is now fully iterated.
-
-
- // Now do the remaining epsilons:
-
- for (int n = 1; n < Set.ntypes; ++n) {
-
- Vect_DP f_Tln_conv_min (0.0, Set.epsilon[n].Npts); // 'down' convolution
- Vect_DP f_Tln_conv_plus (0.0, Set.epsilon[n].Npts); // 'up' convolution
-
- Vect_DP fmin(0.0, Set.epsilon[n-1].Npts);
- Vect_DP fplus(0.0, Set.epsilon[ABACUS::min(n+1, Set.ntypes - 1)].Npts);
-
- for (int i = 0; i < Set.epsilon[n].Npts; ++i) {
- f_Tln_conv_min[i] = 0.0;
- f_Tln_conv_plus[i] = 0.0;
-
- // 'down' convolutions
- if (n == 1)
- for (int j = 0; j < Set.epsilon[0].Npts; ++j)
- f_Tln_conv_min[i] += Tln1plusemineps[0][j] * fmin_dlambda[n][i][j];
-
- else for (int j = 0; j < Set.epsilon[n - 1].Npts; ++j)
- f_Tln_conv_min[i] += (Set.epsilon[n-1].prev_value[j] - Set.epsilon[n-1].value_infty
- + Tln1plusemineps[n-1][j] - Tln1pluseminepsinfty[n-1])
- * fmin_dlambda[n][i][j];
-
- // 'up' convolutions
- if (n < Set.ntypes - 1)
- for (int j = 0; j < Set.epsilon[n+1].Npts; ++j)
- f_Tln_conv_plus[i] += (Set.epsilon[n+1].prev_value[j] - Set.epsilon[n+1].value_infty
- + Tln1plusemineps[n+1][j] - Tln1pluseminepsinfty[n+1])
- * fplus_dlambda[n][i][j];
-
- else f_Tln_conv_plus[i] = 0.0;
-
- // Do some damping:
- Set.epsilon[n].value[i] = 0.1 * Set.epsilon[n].prev_value[i]
- + 0.9 * (Set.epsilon[n].value_infty + f_Tln_conv_min[i] + f_Tln_conv_plus[i]);
- // Force boundary values to asymptotes: force boundary 10 points on each side
- if (i < 10)
- Set.epsilon[n].value[i] = (1.0 - 0.1 * i) * Set.epsilon[n].value_infty + 0.1 * i * Set.epsilon[n].value[i];
- if (i > Set.epsilon[n].Npts - 11)
- Set.epsilon[n].value[i] = (1.0 - 0.1 * (Set.epsilon[n].Npts-1 - i)) * Set.epsilon[n].value_infty
- + 0.1 * (Set.epsilon[n].Npts-1 - i) * Set.epsilon[n].value[i];
-
- } // for (int i = 0...
-
- } // for (int n = 1...
-
- // All functions have now been iterated.
-
- // Now calculate diff:
-
- DP eps0i = 0.0;
- DP eps1i = 0.0;
-
- Set.diff = 0.0;
-
- for (int n = 0; n < Set.ntypes; ++n) {
- Set.epsilon[n].diff = 0.0;
- for (int i = 0; i < Set.epsilon[n].Npts; ++i) {
- // Measure based on delta f/delta epsilon:
- if (n == 0)
- Set.epsilon[n].diff += Set.epsilon[n].dlambda[i] *
- (Set.epsilon[0].value[i] > 0.0 ?
- exp(-Set.epsilon[0].value[i]/kBT)/(1.0 + exp(-Set.epsilon[0].value[i]/kBT)) : 1.0/(1.0 + exp(Set.epsilon[0].value[i]/kBT)))
- * fabs(Set.epsilon[n].value[i] - Set.epsilon[n].prev_value[i]);
- else {
- eps0i = Set.epsilon[0].Return_Value(Set.epsilon[n].lambda[i]);
- eps1i = Set.epsilon[1].Return_Value(Set.epsilon[n].lambda[i]);
-
- Set.epsilon[n].diff += Set.epsilon[n].dlambda[i] *
- // Logic: simple 1/2 cascade
- (eps0i > 0.0 ? exp(-eps0i/kBT)/(1.0 + exp(-eps0i/kBT)) : 1.0/(1.0 + exp(eps0i/kBT)))
- * pow(0.5, n) //* (exp(-eps1i/kBT)/(1.0 + exp(-eps1i/kBT)))
- * fabs(Set.epsilon[n].value[i] - Set.epsilon[n].prev_value[i]);
- }
- }
- Set.diff += Set.epsilon[n].diff;
- }
-
- return;
- }
-
- void Iterate_and_Extrapolate_2CBG_TBAE (Root_Density_Set& Set, Vect<Root_Density_Set>& IterSet,
- Vect<Vect<Vect_DP> >& a_n_dlambda, Vect<Vect<Vect_DP> >& fmin_dlambda,
- Vect<Vect<Vect_DP> >& fplus_dlambda, DP c_int, DP mu, DP Omega, DP kBT)
- {
- int nfit = IterSet.size();
-
- for (int ifit = 0; ifit < nfit; ++ifit) {
- Iterate_2CBG_TBAE (Set, a_n_dlambda, fmin_dlambda, fplus_dlambda, c_int, mu, Omega, kBT);
- IterSet[ifit] = Set;
- }
-
- // Now extrapolate each value to infinite nr of iterations:
- Vect_DP density(nfit);
- Vect_DP oneoverP(nfit);
- DP deltalambda = 0.0;
- for (int ifit = 0; ifit < nfit; ++ifit) oneoverP[ifit] = 1.0/(1.0 + ifit*ifit);
- for (int n = 0; n < Set.ntypes; ++n)
- for (int i = 0; i < Set.epsilon[n].Npts; ++i) {
- for (int ifit = 0; ifit < nfit; ++ifit) density[ifit] = IterSet[ifit].epsilon[n].value[i];
- polint (oneoverP, density, 0.0, Set.epsilon[n].value[i], deltalambda);
- }
-
- // Now iterate a few times to stabilize:
- for (int iint = 0; iint < 2; ++iint)
- Iterate_2CBG_TBAE(Set, a_n_dlambda, fmin_dlambda, fplus_dlambda, c_int, mu, Omega, kBT);
-
- return;
- }
-
- DP Refine_2CBG_Set (Root_Density_Set& Set, DP c_int, DP mu, DP Omega, DP kBT, DP refine_fraction)
- {
- // This function replaces Set by a new set with more points, where
- // Tln(...) needs to be evaluated more precisely.
-
- // The return value is the max of delta_tni found.
-
- // First, calculate the needed Tln...
- Vect<Vect_DP> Tln1plusemineps(Set.ntypes);
- Vect_DP Tln1pluseminepsinfty(Set.ntypes);
-
- for (int n = 0; n < Set.ntypes; ++n) {
-
- Tln1plusemineps[n] = Vect_DP (0.0, Set.epsilon[n].Npts);
-
- for (int i = 0; i < Set.epsilon[n].Npts; ++i) {
- Tln1plusemineps[n][i] = Set.epsilon[n].value[i] > 0.0 ?
- kBT * (Set.epsilon[n].value[i] < 24.0 * kBT
- ? log(1.0 + exp(-Set.epsilon[n].value[i]/kBT)) : exp(-Set.epsilon[n].value[i]/kBT))
- : -Set.epsilon[n].value[i] + kBT * log (1.0 + exp(Set.epsilon[n].value[i]/kBT));
- }
- Tln1pluseminepsinfty[n] = kBT * (Set.epsilon[n].value_infty < 24.0 * kBT ?
- log(1.0 + exp(-Set.epsilon[n].value_infty/kBT)) : exp(-Set.epsilon[n].value_infty/kBT));
- }
-
- // Now find the achieved delta_tni
- DP max_delta_tni_dlambda = 0.0;
- DP max_delta_tni_dlambda_toplevel = 0.0;
- DP sum_delta_tni_dlambda = 0.0;
-
- Vect<Vect_DP> tni(Set.ntypes);
- Vect<Vect_DP> tni_ex(Set.ntypes);
-
- DP measure_factor = 0.0;
- DP eps0i = 0.0;
- DP eps1i = 0.0;
-
- for (int n = 0; n < Set.ntypes; ++n) {
-
- tni[n] = Vect_DP (0.0, Set.epsilon[n].Npts);
- tni_ex[n] = Vect_DP (0.0, Set.epsilon[n].Npts); // extrapolation from adjacent points, to compare to obtained value
-
- for (int i = 1; i < Set.epsilon[n].Npts - 1; ++i) {
- if (n == 0) {
- // Measure based on delta f/delta epsilon:
- measure_factor = (Set.epsilon[0].value[i] > 0.0
- ? exp(-Set.epsilon[0].value[i]/kBT)/(1.0 + exp(-Set.epsilon[0].value[i]/kBT))
- : 1.0/(1.0 + exp(Set.epsilon[0].value[i]/kBT)));
- }
- else {
- // Measure based on delta f/delta epsilon:
- eps0i = Set.epsilon[0].Return_Value(Set.epsilon[n].lambda[i]);
- eps1i = Set.epsilon[1].Return_Value(Set.epsilon[n].lambda[i]);
-
- measure_factor = (eps0i > 0.0 ? exp(-eps0i/kBT)/(1.0 + exp(-eps0i/kBT)) : 1.0/(1.0 + exp(eps0i/kBT)))
- // Logic: simple 1/2 per level cascade down
- * pow(0.5, n);
-
- }
-
- tni[n][i] = measure_factor * Set.epsilon[n].value[i];
- tni_ex[n][i] = measure_factor * (Set.epsilon[n].value[i-1] * (Set.epsilon[n].lambda[i+1] - Set.epsilon[n].lambda[i])
- + Set.epsilon[n].value[i+1] * (Set.epsilon[n].lambda[i] - Set.epsilon[n].lambda[i-1]))
- /(Set.epsilon[n].lambda[i+1] - Set.epsilon[n].lambda[i-1]);
-
- max_delta_tni_dlambda = ABACUS::max(max_delta_tni_dlambda, fabs(tni[n][i] - tni_ex[n][i]) * Set.epsilon[n].dlambda[i]);
- if (n == Set.ntypes - 1)
- max_delta_tni_dlambda_toplevel = ABACUS::max(max_delta_tni_dlambda_toplevel, fabs(tni[n][i] - tni_ex[n][i]) * Set.epsilon[n].dlambda[i]);
- sum_delta_tni_dlambda += fabs(tni[n][i] - tni_ex[n][i]) * Set.epsilon[n].dlambda[i];
- }
- }
-
-
- // We now determine the locations where we need to add points
- Vect<Vect<bool> > need_new_point_around(Set.ntypes);
- Vect<bool> need_to_extend_limit(false, Set.ntypes);
-
- for (int n = 0; n < Set.ntypes; ++n) {
-
- need_new_point_around[n] = Vect<bool> (false, Set.epsilon[n].Npts);
-
- for (int i = 1; i < Set.epsilon[n].Npts - 1; ++i) {
- if (fabs(tni[n][i] - tni_ex[n][i]) * Set.epsilon[n].dlambda[i] > (1.0 - refine_fraction) * max_delta_tni_dlambda) {
- need_new_point_around[n][i] = true;
- // Do also the symmetric ones... Require need...[n][i] = need...[n][Npts - 1 - i]
- need_new_point_around[n][Set.epsilon[n].Npts - 1 - i] = true;
- }
- }
-
- // Check boundary values; if too different from value_infty, extend limits
- if (n == 0) {
- // Measure based on delta f/delta epsilon:
- if (exp(-Set.epsilon[0].value[0]/kBT) > 0.001 * max_delta_tni_dlambda)
- need_to_extend_limit[0] = true;
- }
- else
- // Measure deviation from asymptote for 10th element, since we smoothly put the i<10 ones to the asymptote when damping:
- if (fabs(Set.epsilon[n].value[10] - Set.epsilon[n].value_infty) * Set.epsilon[0].dlambda[10] > max_delta_tni_dlambda)
- need_to_extend_limit[n] = true;
- }
-
- // Check if we need to add a level
- bool need_new_epsilon_n_function = false;
-
- // We add new levels if the integral a_n * Tln1plusemineps at the highest level differs too much from
- // the asymptotic value. Since such integrals appear for each point of the epsilon[0] function, these
- // errors should be compared to the individual delta_tni factors.
- DP a_2_Tln_conv_0_integ = 0.0;
- DP oneoverpi = 1.0/PI;
- DP twoovernc = 2.0/((Set.ntypes - 1) * c_int);
- int i0 = Set.epsilon[0].Npts/2;
- for (int j = 0; j < Set.epsilon[Set.ntypes - 1].Npts; ++j)
- a_2_Tln_conv_0_integ += (Tln1plusemineps[Set.ntypes - 1][j] - Tln1pluseminepsinfty[Set.ntypes - 1])
- * oneoverpi * (atan(twoovernc * (Set.epsilon[0].lambda[i0] - Set.epsilon[Set.ntypes - 1].lambda[j]
- + 0.5 * Set.epsilon[Set.ntypes - 1].dlambda[j]))
- - atan(twoovernc * (Set.epsilon[0].lambda[i0] - Set.epsilon[Set.ntypes - 1].lambda[j]
- - 0.5 * Set.epsilon[Set.ntypes - 1].dlambda[j])));
-
- // Compare to prediction for this integral based on value_infty, which is simply 0.
- // Count this difference Set.ntypes times over, since it cascades down all levels
- if (fabs(a_2_Tln_conv_0_integ) * Set.ntypes > max_delta_tni_dlambda) need_new_epsilon_n_function = true;
-
- // Additionally, if the highest level needs updating, we automatically add new functions:
- for (int i = 0; i < Set.epsilon[Set.ntypes - 1].Npts; ++i)
- if (need_new_point_around[Set.ntypes - 1][i] || need_to_extend_limit[Set.ntypes - 1]) need_new_epsilon_n_function = true;
-
-
- // Now insert the new points between existing points:
- Set.Insert_new_points (need_new_point_around);
-
- // Now extend the integration limits if needed:
- Set.Extend_limits (need_to_extend_limit);
-
- // If we add a level, we do it here:
- if (need_new_epsilon_n_function) {
- // Insert more than one function per cycle...
- Set.Insert_new_function(Asymptotic_2CBG_epsilon(Set.ntypes, Omega, kBT));
- Set.Insert_new_function(Asymptotic_2CBG_epsilon(Set.ntypes, Omega, kBT)); // CAREFUL !! ntypes is already updated
- Set.Insert_new_function(Asymptotic_2CBG_epsilon(Set.ntypes, Omega, kBT)); // CAREFUL !! ntypes is already updated
- Set.Insert_new_function(Asymptotic_2CBG_epsilon(Set.ntypes, Omega, kBT)); // CAREFUL !! ntypes is already updated;
- Set.Insert_new_function(Asymptotic_2CBG_epsilon(Set.ntypes, Omega, kBT)); // CAREFUL !! ntypes is already updated
- }
-
- //return(max_delta_tni_dlambda);
- return(sum_delta_tni_dlambda);
- }
-
- DP Calculate_Gibbs_Free_Energy (const Root_Density_Set& Set, DP c_int, DP mu, DP Omega, DP kBT)
- {
- // Computes the Gibbs free energy, assuming that epsilon[0] is symmetric.
-
- // WORKING VERSION
- DP sum_f = 0.0;
- Vect_DP f(0.0, Set.epsilon[0].Npts);
- DP sum_f_check = 0.0;
- Vect_DP fcheck(0.0, Set.epsilon[0].Npts);
- DP sum_g_check = 0.0;
- Vect_DP gcheck(0.0, Set.epsilon[0].Npts);
- for (int i = 0; i < Set.epsilon[0].Npts; ++i) {
- f[i] = (Set.epsilon[0].value[i] > 0.0 ? kBT* log(1.0 + exp(-Set.epsilon[0].value[i]/kBT))
- : -Set.epsilon[0].value[i] + kBT * log(1.0 + exp(Set.epsilon[0].value[i]/kBT)));
- sum_f += Set.epsilon[0].dlambda[i] * f[i];
- fcheck[i] = kBT * log(1.0 + exp(-(Set.epsilon[0].lambda[i] * Set.epsilon[0].lambda[i] - mu - Omega)/kBT));
- sum_f_check += Set.epsilon[0].dlambda[i] * fcheck[i];
- gcheck[i] = exp(-(Set.epsilon[0].lambda[i] * Set.epsilon[0].lambda[i])/kBT);
- sum_g_check += Set.epsilon[0].dlambda[i] * gcheck[i];
- }
-
- // Now add alpha curvature terms:
- for (int i = 1; i < Set.epsilon[0].Npts - 1; ++i)
- sum_f += pow(Set.epsilon[0].dlambda[i], 3.0) * ((f[i+1] - f[i])/(Set.epsilon[0].lambda[i+1] - Set.epsilon[0].lambda[i])
- - (f[i] - f[i-1])/(Set.epsilon[0].lambda[i] - Set.epsilon[0].lambda[i-1]))
- /(12.0 * (Set.epsilon[0].lambda[i+1] - Set.epsilon[0].lambda[i-1]));
-
- // Now add alpha curvature terms:
- DP sum_gcorralphacheck = 0.0;
- Vect_DP gcorr_alpha_check(0.0, Set.epsilon[0].Npts);
- for (int i = 1; i < Set.epsilon[0].Npts - 1; ++i) {
- gcorr_alpha_check[i] = (1.0/12.0) * pow(Set.epsilon[0].dlambda[i], 3.0)
- * ((gcheck[i+1] - gcheck[i]) * (Set.epsilon[0].lambda[i] - Set.epsilon[0].lambda[i-1])
- - (gcheck[i] - gcheck[i-1]) * (Set.epsilon[0].lambda[i+1] - Set.epsilon[0].lambda[i]))
- /((Set.epsilon[0].lambda[i+1] - Set.epsilon[0].lambda[i-1]) * (Set.epsilon[0].lambda[i+1] - Set.epsilon[0].lambda[i])
- * (Set.epsilon[0].lambda[i] - Set.epsilon[0].lambda[i-1]));
- sum_gcorralphacheck += gcorr_alpha_check[i];
- }
-
- // Testing:
- int Npts_test = Set.epsilon[0].Npts;
- DP lambdamax_test = Set.epsilon[0].lambdamax;
- DP testsum = 0.0;
- DP testgauss = 0.0;
- DP lambda;
- DP dlambda;
- for (int i = 0; i < Npts_test; ++i) {
- lambda = lambdamax_test * (-Npts_test + 1.0 + 2*i)/Npts_test;
- dlambda = lambdamax_test * 2.0/Npts_test;
- testsum += kBT * log(1.0 + exp(-(lambda*lambda - mu - Omega)/kBT)) * dlambda;
- testgauss += exp(-lambda*lambda/kBT) * dlambda;
- }
-
- return(-sum_f/twoPI);
- }
-
- DP Calculate_dGibbs_dchempot (const Root_Density_Set& DSet, const Root_Density_Set& Set, DP c_int, DP mu, DP Omega, DP kBT)
- {
- // This calculates the derivative of the Gibbs free energy with respect to either of the two chemical potential,
- // given the fundametal set Set for eps and DSet for either deps_du or deps_dOmega.
-
- DP sum_f = 0.0;
- Vect_DP f(0.0, Set.epsilon[0].Npts);
-
- for (int i = 0; i < Set.epsilon[0].Npts; ++i) {
- f[i] = DSet.epsilon[0].value[i] * (Set.epsilon[0].value[i] > 0.0
- ? exp(-Set.epsilon[0].value[i]/kBT)/(1.0 + exp(-Set.epsilon[0].value[i]/kBT))
- : 1.0/(1.0 + exp(Set.epsilon[0].value[i]/kBT)));
- sum_f += DSet.epsilon[0].dlambda[i] * f[i];
- }
-
- // Now add alpha curvature terms:
- for (int i = 1; i < DSet.epsilon[0].Npts - 1; ++i)
- sum_f += pow(DSet.epsilon[0].dlambda[i], 3.0)
- * ((f[i+1] - f[i])/(DSet.epsilon[0].lambda[i+1] - DSet.epsilon[0].lambda[i])
- - (f[i] - f[i-1])/(DSet.epsilon[0].lambda[i] - DSet.epsilon[0].lambda[i-1]))
- /(12.0 * (DSet.epsilon[0].lambda[i+1] - DSet.epsilon[0].lambda[i-1]));
-
- return(sum_f/twoPI);
- }
-
- Vect<Vect<Vect_DP> > Build_a_n_dlambda (const Root_Density_Set& Set, DP c_int, DP mu, DP Omega, DP kBT)
- {
- DP oneoverpi = 1.0/PI;
- DP oneoverc = 1.0/c_int;
- DP twoovernc = 2.0/c_int;
-
- Vect<Vect<Vect_DP> > a_n_dlambda(Set.epsilon[0].Npts);
- for (int i = 0; i < Set.epsilon[0].Npts; ++i) {
- a_n_dlambda[i] = Vect<Vect_DP>(Set.ntypes);
- for (int n = 0; n < Set.ntypes; ++n) {
- a_n_dlambda[i][n] = Vect_DP(0.0, Set.epsilon[n].Npts);
- }
- }
-
- for (int i = 0; i < Set.epsilon[0].Npts; ++i) {
-
- // Do n == 0 separately:
- for (int j = 0; j < Set.epsilon[0].Npts; ++j)
- a_n_dlambda[i][0][j] = oneoverpi
- * (atan(oneoverc * (Set.epsilon[0].lambda[i] - Set.epsilon[0].lambda[j] + 0.5 * Set.epsilon[0].dlambda[j]))
- - atan(oneoverc * (Set.epsilon[0].lambda[i] - Set.epsilon[0].lambda[j] - 0.5 * Set.epsilon[0].dlambda[j])));
-
- // Now do n > 0:
- for (int n = 1; n < Set.ntypes; ++n) {
- twoovernc = 2.0/(n * c_int);
- for (int j = 0; j < Set.epsilon[n].Npts; ++j) {
- a_n_dlambda[i][n][j] = oneoverpi
- * (atan(twoovernc * (Set.epsilon[0].lambda[i] - Set.epsilon[n].lambda[j] + 0.5 * Set.epsilon[n].dlambda[j]))
- - atan(twoovernc * (Set.epsilon[0].lambda[i] - Set.epsilon[n].lambda[j] - 0.5 * Set.epsilon[n].dlambda[j])));
- }
- } // for (int n
- } // for (int i
-
- return(a_n_dlambda);
- }
-
- Vect<Vect<Vect_DP> > Build_fmin_dlambda (const Root_Density_Set& Set, DP c_int, DP mu, DP Omega, DP kBT)
- {
- DP oneoverpi = 1.0/PI;
- DP pioverc = PI/c_int;
- DP twopioverc = 2.0*PI/c_int;
- DP piovertwoc = 0.5 * pioverc;
-
- Vect<Vect<Vect_DP> > fmin_dlambda(Set.ntypes);
- for (int n = 0; n < Set.ntypes; ++n) {
- fmin_dlambda[n] = Vect<Vect_DP> (Set.epsilon[n].Npts);
- for (int i = 0; i < Set.epsilon[n].Npts; ++i)
- fmin_dlambda[n][i] = Vect_DP (0.0, Set.epsilon[ABACUS::max(n-1, 0)].Npts);
- }
-
- for (int n = 1; n < Set.ntypes; ++n) {
- for (int i = 0; i < Set.epsilon[n].Npts; ++i) {
-
- for (int j = 0; j < Set.epsilon[n-1].Npts; ++j)
- fmin_dlambda[n][i][j] = oneoverpi
- * atan(exp(-pioverc * fabs(Set.epsilon[n].lambda[i] - Set.epsilon[n-1].lambda[j]))
- * 2.0 * sinh(piovertwoc * Set.epsilon[n-1].dlambda[j])
- /(1.0 + exp(-twopioverc * fabs(Set.epsilon[n].lambda[i] - Set.epsilon[n-1].lambda[j]))));
- } // for i
- } // for n
-
- return(fmin_dlambda);
- }
-
- Vect<Vect<Vect_DP> > Build_fplus_dlambda (const Root_Density_Set& Set, DP c_int, DP mu, DP Omega, DP kBT)
- {
- DP oneoverpi = 1.0/PI;
- DP pioverc = PI/c_int;
- DP twopioverc = 2.0*PI/c_int;
- DP piovertwoc = 0.5 * pioverc;
-
- Vect<Vect<Vect_DP> > fplus_dlambda(Set.ntypes);
- for (int n = 0; n < Set.ntypes; ++n) {
- fplus_dlambda[n] = Vect<Vect_DP> (Set.epsilon[n].Npts);
- for (int i = 0; i < Set.epsilon[n].Npts; ++i)
- fplus_dlambda[n][i] = Vect_DP (0.0, Set.epsilon[ABACUS::min(n+1, Set.ntypes - 1)].Npts);
- }
-
- for (int n = 0; n < Set.ntypes - 1; ++n) {
- for (int i = 0; i < Set.epsilon[n].Npts; ++i) {
- for (int j = 0; j < Set.epsilon[n+1].Npts; ++j)
- fplus_dlambda[n][i][j] = oneoverpi
- * atan(exp(-pioverc * fabs(Set.epsilon[n].lambda[i] - Set.epsilon[n+1].lambda[j]))
- * 2.0 * sinh(piovertwoc * Set.epsilon[n+1].dlambda[j])
- /(1.0 + exp(-twopioverc * fabs(Set.epsilon[n].lambda[i] - Set.epsilon[n+1].lambda[j]))));
- }
- }
-
- return(fplus_dlambda);
- }
-
-
- Root_Density_Set Solve_2CBG_TBAE_via_refinements (DP c_int, DP mu, DP Omega, DP kBT, int Max_Secs,
- ofstream& LOG_outfile, bool Save_data)
- {
- // This solves the 2CBG TBAE as best as possible given the time constraint.
-
- clock_t StartTime = clock();
-
- int Max_CPU_ticks = 98 * (Max_Secs - 0) * CLOCKS_PER_SEC/100; // give 30 seconds to wrap up, assume we time to 2% accuracy.
-
- // Set basic precision needed:
- DP running_prec = 1.0;
-
- DP refine_fraction = 0.5; // value fraction of points to be refined
-
- // Set basic number of types needed:
- int ntypes_needed = int(kBT * log(kBT/1.0e-14)/Omega);
- int ntypes = ABACUS::max(ntypes_needed, 1);
- ntypes = ABACUS::min(ntypes, 10);
-
- if (Save_data)
- if (ntypes >= 10) LOG_outfile << "WARNING: ntypes needs to be quite high for c_int = " << c_int
- << " mu = " << mu << " Omega = " << Omega
- << " kBT = " << kBT << ". Set to " << ntypes << ", ideally needed: "
- << ntypes_needed << ". Accuracy might be incorrectly evaluated." << endl;
-
- DP lambdamax = 10.0 + sqrt(ABACUS::max(1.0, kBT * 36.0 + mu + Omega));
- // such that exp(-(lambdamax^2 - mu - Omega)/T) <~ machine_eps
- int Npts = 50;
- Vect_INT Npts_init(Npts, ntypes);
- if (Save_data) LOG_outfile << "Npts (basic) set to " << Npts_init << endl;
-
- Vect_DP lambdamax_init(lambdamax, ntypes); // such that exp(-pi *lambdamax/c) <~ machine_eps
- Npts_init[0] = 1 * Npts; // give more precision to lowest level
- lambdamax_init[0] = 10.0 + sqrt(ABACUS::max(1.0, kBT * 36.0 + mu + Omega));
- // such that exp(-(lambdamax^2 - mu - Omega)/T) <~ machine_eps
- Root_Density_Set TBA_Set (ntypes, Npts_init, lambdamax_init);
-
- // Set the asymptotics of the TBA_fns:
- Set_2CBG_Asymptotics (TBA_Set, mu, Omega, kBT);
-
- // Initiate the functions:
- Initiate_2CBG_TBA_Functions (TBA_Set, mu, Omega);
-
- clock_t StopTime = clock();
- clock_t Cycle_StartTime, Cycle_StopTime;
-
- int CPU_ticks = StopTime - StartTime;
-
- int ncycles = 0;
- int niter_tot = 0;
-
- do {
-
- StartTime = clock();
-
- Cycle_StartTime = clock();
-
- // The running precision is an estimate of the accuracy of the free energy integral.
- // Refine... returns sum_delta_tni_dlambda, so running prec is estimated as...
- running_prec = Refine_2CBG_Set (TBA_Set, c_int, mu, Omega, kBT, refine_fraction);
-
- Vect<Vect<Vect_DP> > a_n_dlambda = Build_a_n_dlambda (TBA_Set, c_int, mu, Omega, kBT);
- Vect<Vect<Vect_DP> > fmin_dlambda = Build_fmin_dlambda (TBA_Set, c_int, mu, Omega, kBT);
- Vect<Vect<Vect_DP> > fplus_dlambda = Build_fplus_dlambda (TBA_Set, c_int, mu, Omega, kBT);
-
- StopTime = clock();
-
- CPU_ticks += StopTime - StartTime;
-
- int niter = 0;
- int niter_max = ncycles == 0 ? 300 : 300;
-
- // For extrapolations:
- Vect<Root_Density_Set> IterSet(4);
-
- do {
-
- StartTime = clock();
-
- if (niter <= 10 || niter > 100) {
- Iterate_2CBG_TBAE (TBA_Set, a_n_dlambda, fmin_dlambda, fplus_dlambda, c_int, mu, Omega, kBT);
- niter++;
- }
- else {
- Iterate_and_Extrapolate_2CBG_TBAE (TBA_Set, IterSet, a_n_dlambda, fmin_dlambda, fplus_dlambda, c_int, mu, Omega, kBT);
- niter += 6;
- }
-
- StopTime = clock();
- CPU_ticks += StopTime - StartTime;
-
- } while (niter < 5 || niter < niter_max && TBA_Set.diff > 0.1 * running_prec && CPU_ticks < Max_CPU_ticks);
-
- if (Save_data) {
- LOG_outfile << "ncycles = " << ncycles << "\trunning_prec = " << running_prec << "\t niter = " << niter
- << "\tntypes = " << TBA_Set.ntypes << "\tNpts ";
- for (int n = 0; n < TBA_Set.ntypes; ++n) LOG_outfile << TBA_Set.epsilon[n].Npts << " ";
- LOG_outfile << "\tNpts_total = " << TBA_Set.Npts_total << endl
- << "\tdiff = " << TBA_Set.diff
- << "\tGSE = " << Calculate_Gibbs_Free_Energy (TBA_Set, c_int, mu, Omega, kBT) << endl;
- }
-
- ncycles++;
- niter_tot += niter;
-
- if (niter == niter_max) {
- if (Save_data) LOG_outfile << "Not able to improve functions enough after " << niter_max << " iterations." << endl;
- }
-
- Cycle_StopTime = clock();
-
- } while (CPU_ticks < Max_CPU_ticks - 2.0*(Cycle_StopTime - Cycle_StartTime));
- // Allow a new cycle only if there is time, assuming new cycle time < 2* last one
-
- if (Save_data) {
- LOG_outfile << "c_int " << c_int << "\tmu " << mu << "\tOmega " << Omega << "\tkBT " << kBT
- << "\tncycles = " << ncycles << "\trunning_prec = " << running_prec << "\t niter_tot = " << niter_tot
- << "\tntypes = " << TBA_Set.ntypes << "\tdiff = " << TBA_Set.diff << endl << "\tNpts ";
- for (int n = 0; n < TBA_Set.ntypes; ++n) LOG_outfile << TBA_Set.epsilon[n].Npts << " ";
- LOG_outfile << "\tNpts_total = " << TBA_Set.Npts_total << endl;
- }
-
- return(TBA_Set);
- //return;
- }
-
-
- // Iterative procedures for deps/dmu or /dOmega:
- void Iterate_2CBG_deps_dchempot (int option, Root_Density_Set& DSet, const Root_Density_Set& Set,
- Vect<Vect<Vect_DP> >& a_n_dlambda, Vect<Vect<Vect_DP> >& fmin_dlambda,
- Vect<Vect<Vect_DP> >& fplus_dlambda, DP c_int, DP mu, DP Omega, DP kBT)
- {
- // Produces a new Root_Density_Set for depsilon/dmu (option == 0) or depsilon/dOmega (option == 1) from a previous iteration.
- // Does NOT add types or change Npts, lambdamax values.
-
- // First define some useful functions:
- Vect<Vect_DP> depsover1plusemineps(Set.ntypes);
- Vect<Vect_DP> depsover1plusepluseps(Set.ntypes);
- Vect_DP depsover1pluseminepsinfty(Set.ntypes);
- Vect_DP depsover1pluseplusepsinfty(Set.ntypes);
-
- for (int n = 0; n < Set.ntypes; ++n) {
-
- depsover1plusemineps[n] = Vect_DP (0.0, Set.epsilon[n].Npts);
- depsover1plusepluseps[n] = Vect_DP (0.0, Set.epsilon[n].Npts);
-
- for (int i = 0; i < Set.epsilon[n].Npts; ++i) {
- depsover1plusemineps[n][i] = Set.epsilon[n].value[i] > 0.0 ?
- DSet.epsilon[n].value[i]/(1.0 + exp(-Set.epsilon[n].value[i]/kBT)) :
- DSet.epsilon[n].value[i] * exp(Set.epsilon[n].value[i]/kBT)/(1.0 + exp(Set.epsilon[n].value[i]/kBT));
- depsover1plusepluseps[n][i] = Set.epsilon[n].value[i] > 0.0 ?
- DSet.epsilon[n].value[i] * exp(-Set.epsilon[n].value[i]/kBT)/(1.0 + exp(-Set.epsilon[n].value[i]/kBT)) :
- DSet.epsilon[n].value[i]/(1.0 + exp(Set.epsilon[n].value[i]/kBT));
-
- // Keep previous rapidities:
- DSet.epsilon[n].prev_value[i] = DSet.epsilon[n].value[i];
-
- }
- depsover1pluseminepsinfty[n] = DSet.epsilon[n].value_infty/(1.0 + exp(-Set.epsilon[n].value_infty/kBT));
- depsover1pluseplusepsinfty[n] = DSet.epsilon[n].value_infty * exp(-Set.epsilon[n].value_infty/kBT)
- /(1.0 + exp(-Set.epsilon[n].value_infty/kBT));
- }
-
-
- // Now do the necessary convolutions for epsilon == epsilon[0].
- // For each value of lambda, do the convolutions:
- // Careful: the lambda's used for lambda (index i) are those of epsilon[0], the lambda' (index j) are for epsilon[n] !!
- Vect<Vect_DP> a_n_depsover_conv(Set.ntypes);
- for (int n = 0; n < Set.ntypes; ++n) {
- a_n_depsover_conv[n] = Vect_DP (0.0, Set.epsilon[0].Npts);
- Vect_DP f(0.0, Set.epsilon[n].Npts);
-
- for (int i = 0; i < Set.epsilon[0].Npts; ++i) {
- a_n_depsover_conv[n][i] = 0.0;
-
- for (int j = 0; j < Set.epsilon[n].Npts; ++j) {
- f[j] = depsover1plusepluseps[n][j] * a_n_dlambda[i][n][j];
- a_n_depsover_conv[n][i] += f[j];
- }
- }
- } // for (int n... We now have all the a_n * deps... at our disposal.
-
- // For n > nmax sum in RHS of BE for epsilon, assuming epsilon_n = epsilon_n^\infty in those cases:
- // Remember: nmax = Set.ntypes - 1
- DP Smaxsum = option == 0 ? 0.0 : 2.0 * ((Set.ntypes + 1.0) * exp(-2.0 * (Set.ntypes + 1.0) * Omega/kBT)
- /(1.0 - exp(-2.0 * (Set.ntypes + 1.0) * Omega/kBT))
- - Set.ntypes * exp(-2.0 * Set.ntypes * Omega/kBT)
- /(1.0 - exp(-2.0 * Set.ntypes * Omega/kBT)));
-
- // Reconstruct the epsilon[0] function:
- for (int i = 0; i < DSet.epsilon[0].Npts; ++i) {
- DSet.epsilon[0].value[i] = -1.0;
-
- // Add the convolutions:
- for (int n = 0; n < Set.ntypes; ++n)
- DSet.epsilon[0].value[i] += a_n_depsover_conv[n][i];
- // Add the asymptotic parts of convolutions: n == 0 part is zero because of 1 + exp[epsilon[0] ] in denominator
- for (int n = 1; n < Set.ntypes; ++n)
- DSet.epsilon[0].value[i] += depsover1pluseplusepsinfty[n]
- * (1.0 - (atan((DSet.epsilon[n].lambdamax - DSet.epsilon[0].lambda[i])/(0.5 * n * c_int))
- + atan((DSet.epsilon[n].lambdamax + DSet.epsilon[0].lambda[i])/(0.5 * n * c_int)))/PI);
-
- // Add the leftover summation for species n > nmax, assuming epsilon_n = epsilon_n^\infty in those cases:
- DSet.epsilon[0].value[i] -= Smaxsum;
- // Include some damping:
- DSet.epsilon[0].value[i] = 0.1 * DSet.epsilon[0].prev_value[i] + 0.9 * DSet.epsilon[0].value[i];
- // Force boundary values to asymptotes: force boundary 10 points on each side
- if (i < 10)
- DSet.epsilon[0].value[i] = (1.0 - 0.1 * i) * DSet.epsilon[0].value_infty + 0.1 * i * DSet.epsilon[0].value[i];
- if (i > DSet.epsilon[0].Npts - 11)
- DSet.epsilon[0].value[i] = (1.0 - 0.1 * (DSet.epsilon[0].Npts-1 - i)) * DSet.epsilon[0].value_infty
- + 0.1 * (DSet.epsilon[0].Npts-1 - i) * DSet.epsilon[0].value[i];
-
- }
- // epsilon[0] is now fully iterated.
-
- // Now do the remaining epsilons:
-
- for (int n = 1; n < Set.ntypes; ++n) {
-
- Vect_DP f_depsover_conv_min (0.0, Set.epsilon[n].Npts); // 'down' convolution
- Vect_DP f_depsover_conv_plus (0.0, Set.epsilon[n].Npts); // 'up' convolution
-
- Vect_DP fmin(0.0, Set.epsilon[n-1].Npts);
- Vect_DP fplus(0.0, Set.epsilon[ABACUS::min(n+1, Set.ntypes - 1)].Npts);
-
- for (int i = 0; i < Set.epsilon[n].Npts; ++i) {
- f_depsover_conv_min[i] = 0.0;
- f_depsover_conv_plus[i] = 0.0;
-
- // 'down' convolutions
- if (n == 1) {
-
- for (int j = 0; j < Set.epsilon[0].Npts; ++j) {
- fmin[j] = depsover1plusepluseps[0][j]
- * fmin_dlambda[n][i][j];
- f_depsover_conv_min[i] -= fmin[j]; // Careful ! - sign here
- }
- } // if (n == 1)
-
- else { // if (n != 1)
-
- for (int j = 0; j < Set.epsilon[n - 1].Npts; ++j) {
- fmin[j] = (depsover1plusemineps[n-1][j] - depsover1pluseminepsinfty[n-1])
- * fmin_dlambda[n][i][j];
- f_depsover_conv_min[i] += fmin[j];
- }
- } // if (n != 1)
-
-
- // 'up' convolutions
- if (n < Set.ntypes - 1) {
-
- for (int j = 0; j < Set.epsilon[n+1].Npts; ++j) {
- fplus[j] = (depsover1plusemineps[n+1][j] - depsover1pluseminepsinfty[n+1])
- * fplus_dlambda[n][i][j];
- f_depsover_conv_plus[i] += fplus[j];
- }
-
- } // if (n < Set.ntypes - 1...
-
- // otherwise, we put the function to 1/2 times depsover... of epsilon[n+1] at infinity, minus the same:
- else f_depsover_conv_plus[i] = 0.0;
-
- // Do some damping:
- DSet.epsilon[n].value[i] = 0.1 * DSet.epsilon[n].prev_value[i]
- + 0.9 * (DSet.epsilon[n].value_infty + f_depsover_conv_min[i] + f_depsover_conv_plus[i]);
- // Force boundary values to asymptotes: force boundary 10 points on each side
- if (i < 10)
- DSet.epsilon[n].value[i] = (1.0 - 0.1 * i) * DSet.epsilon[n].value_infty + 0.1 * i * DSet.epsilon[n].value[i];
- if (i > DSet.epsilon[n].Npts - 11)
- DSet.epsilon[n].value[i] = (1.0 - 0.1 * (DSet.epsilon[n].Npts-1 - i)) * DSet.epsilon[n].value_infty
- + 0.1 * (DSet.epsilon[n].Npts-1 - i) * DSet.epsilon[n].value[i];
-
- } // for (int i = 0...
-
- } // for (int n = 1...
-
- // All functions have now been iterated.
-
- // Now calculate diff:
-
- DSet.diff = 0.0;
-
- for (int n = 0; n < DSet.ntypes; ++n) {
- DSet.epsilon[n].diff = 0.0;
- for (int i = 0; i < DSet.epsilon[n].Npts; ++i) {
- DSet.epsilon[n].diff += DSet.epsilon[n].dlambda[i] *
- fabs((DSet.epsilon[n].value[i] - DSet.epsilon[n].prev_value[i]) * depsover1plusepluseps[n][i]);
- }
- DSet.diff += DSet.epsilon[n].diff;
- }
-
- return;
- }
-
- Root_Density_Set Solve_2CBG_deps_dchempot (int option, Root_Density_Set& TBA_Set, DP c_int, DP mu, DP Omega, DP kBT,
- int Max_Secs, ofstream& LOG_outfile, bool Save_data)
- {
- // This solves the 2CBG deps/dmu (option == 0) or deps/dOmega (option == 1).
-
- clock_t StartTime, StopTime;
-
- int Max_CPU_ticks = 98 * (Max_Secs - 10) * CLOCKS_PER_SEC/100; // give 30 seconds to wrap up, assume we time to 2% accuracy.
-
- // Set basic precision needed:
- DP running_prec = TBA_Set.diff;
-
- // We start by converging simplified sets, with fewer points:
-
- Root_Density_Set TBA_Set_comp = TBA_Set.Return_Compressed_and_Matched_Set(1.0);
-
- Root_Density_Set DSet = TBA_Set; // this will be the final function return
- Root_Density_Set DSet_comp = TBA_Set_comp;
-
- // Set the asymptotics of the TBA_fns:
- Set_2CBG_deps_dchempot_Asymptotics (option, TBA_Set_comp, DSet_comp, mu, Omega, kBT);
- Set_2CBG_deps_dchempot_Asymptotics (option, TBA_Set, DSet, mu, Omega, kBT);
-
- // Now, start by 'converging' the comp set:
-
- // Initiate the functions:
- Initiate_2CBG_deps_dchempot_Functions (DSet_comp);
-
- Vect<Vect<Vect_DP> > a_n_dlambda_comp = Build_a_n_dlambda (TBA_Set_comp, c_int, mu, Omega, kBT);
- Vect<Vect<Vect_DP> > fmin_dlambda_comp = Build_fmin_dlambda (TBA_Set_comp, c_int, mu, Omega, kBT);
- Vect<Vect<Vect_DP> > fplus_dlambda_comp = Build_fplus_dlambda (TBA_Set_comp, c_int, mu, Omega, kBT);
-
- int CPU_ticks = 0;
-
- int niter_comp = 0;
-
- do {
-
- StartTime = clock();
- Iterate_2CBG_deps_dchempot (option, DSet_comp, TBA_Set_comp,
- a_n_dlambda_comp, fmin_dlambda_comp, fplus_dlambda_comp, c_int, mu, Omega, kBT);
- niter_comp++;
- StopTime = clock();
- CPU_ticks += StopTime - StartTime;
-
- } while (CPU_ticks < Max_CPU_ticks/2 && (niter_comp < 100 || DSet_comp.diff > running_prec));
- // use at most half the time, keep rest for later.
-
- DSet.Match_Densities(DSet_comp);
-
- Vect<Vect<Vect_DP> > a_n_dlambda = Build_a_n_dlambda (TBA_Set, c_int, mu, Omega, kBT);
- Vect<Vect<Vect_DP> > fmin_dlambda = Build_fmin_dlambda (TBA_Set, c_int, mu, Omega, kBT);
- Vect<Vect<Vect_DP> > fplus_dlambda = Build_fplus_dlambda (TBA_Set, c_int, mu, Omega, kBT);
-
- int niter = 0;
-
- do {
- StartTime = clock();
- Iterate_2CBG_deps_dchempot (option, DSet, TBA_Set, a_n_dlambda, fmin_dlambda, fplus_dlambda, c_int, mu, Omega, kBT);
- niter++;
- StopTime = clock();
- CPU_ticks += StopTime - StartTime;
- } while (CPU_ticks < Max_CPU_ticks && DSet_comp.diff > 1.0e-4 * running_prec);
-
-
- // We're done !!
-
- if (Save_data) {
- LOG_outfile << "deps_dchempot, option == " << option << endl;
- LOG_outfile << "c_int " << c_int << "\tmu " << mu << "\tOmega " << Omega << "\tkBT " << kBT
- << "\trunning_prec " << running_prec << " niter_comp " << niter_comp << " niter_full " << niter
- << "\tntypes " << DSet.ntypes << "\tdiff " << DSet.diff << endl;
- }
-
- return(DSet);
- }
-
-
- TBA_Data_2CBG Solve_2CBG_TBAE_via_refinements (DP c_int, DP mu, DP Omega, DP kBT, int Max_Secs, bool Save_data)
- {
- // This solves the 2CBG TBAE as best as possible given the time constraint.
-
- stringstream TBA_stringstream;
- string TBA_string;
- stringstream Dmu_stringstream;
- string Dmu_string;
- stringstream DOmega_stringstream;
- string DOmega_string;
- stringstream LOG_stringstream;
- string LOG_string;
- stringstream GFE_stringstream;
- string GFE_string;
-
- TBA_stringstream << "EPS_2CBG_c_" << c_int << "_mu_" << mu << "_Omega_" << Omega
- << "_kBT_" << kBT << "_Secs_" << Max_Secs << ".dat";
- Dmu_stringstream << "EPS_2CBG_c_" << c_int << "_mu_" << mu << "_Omega_" << Omega
- << "_kBT_" << kBT << "_Secs_" << Max_Secs << ".dmu";
- DOmega_stringstream << "EPS_2CBG_c_" << c_int << "_mu_" << mu << "_Omega_" << Omega
- << "_kBT_" << kBT << "_Secs_" << Max_Secs << ".dOm";
- LOG_stringstream << "EPS_2CBG_c_" << c_int << "_mu_" << mu << "_Omega_" << Omega
- << "_kBT_" << kBT << "_Secs_" << Max_Secs << ".log";
- GFE_stringstream << "GFE_2CBG_c_" << c_int << "_mu_" << mu << "_Omega_" << Omega
- << "_kBT_" << kBT << "_Secs_" << Max_Secs << ".dat";
-
- TBA_string = TBA_stringstream.str();
- const char* TBA_Cstr = TBA_string.c_str();
-
- Dmu_string = Dmu_stringstream.str();
- const char* Dmu_Cstr = Dmu_string.c_str();
-
- DOmega_string = DOmega_stringstream.str();
- const char* DOmega_Cstr = DOmega_string.c_str();
-
- LOG_string = LOG_stringstream.str();
- const char* LOG_Cstr = LOG_string.c_str();
-
- GFE_string = GFE_stringstream.str();
- const char* GFE_Cstr = GFE_string.c_str();
-
- ofstream LOG_outfile;
- ofstream GFE_outfile;
-
- if (Save_data) {
- LOG_outfile.open(LOG_Cstr);
- LOG_outfile.precision(6);
-
- GFE_outfile.open(GFE_Cstr);
- GFE_outfile.precision(16);
- }
-
- Root_Density_Set TBA_Set = Solve_2CBG_TBAE_via_refinements (c_int, mu, Omega, kBT, Max_Secs/3, LOG_outfile, Save_data);
-
- if (Save_data) {
- // Output the functions:
- TBA_Set.Save(TBA_Cstr);
- }
-
- Root_Density_Set DSet_dmu =
- Solve_2CBG_deps_dchempot (0, TBA_Set, c_int, mu, Omega, kBT, Max_Secs/3, LOG_outfile, Save_data);
- if (Save_data) DSet_dmu.Save(Dmu_Cstr);
-
- Root_Density_Set DSet_dOmega =
- Solve_2CBG_deps_dchempot (1, TBA_Set, c_int, mu, Omega, kBT, Max_Secs/3, LOG_outfile, Save_data);
- if (Save_data) DSet_dOmega.Save(DOmega_Cstr);
-
- DP f = Calculate_Gibbs_Free_Energy (TBA_Set, c_int, mu, Omega, kBT);
- DP dfdmu = Calculate_dGibbs_dchempot (DSet_dmu, TBA_Set, c_int, mu, Omega, kBT);
- DP dfdOm = Calculate_dGibbs_dchempot (DSet_dOmega, TBA_Set, c_int, mu, Omega, kBT);
-
- if (Save_data)
- GFE_outfile << f << "\t" << TBA_Set.diff
- << "\t" << dfdmu << "\t" << dfdOm << "\t" << 0.5 * (-dfdmu - dfdOm) << "\t" << 0.5 * (-dfdmu + dfdOm)
- << endl;
-
- else cout << setprecision(16) << f << "\t" << 0.5 * (-dfdmu - dfdOm) << "\t" << 0.5 * (-dfdmu + dfdOm);
-
- if (Save_data) {
- LOG_outfile.close();
- GFE_outfile.close();
- }
-
- TBA_Data_2CBG answer;
- answer.c_int = c_int;
- answer.mu = mu;
- answer.Omega = Omega;
- answer.kBT = kBT;
- answer.f = f;
- answer.n1 = 0.5 * (-dfdmu - dfdOm);
- answer.n2 = 0.5 * (-dfdmu + dfdOm);
-
- return(answer);
- }
-
- void GFE_muscan_2CBG (DP c_int, DP mu_min, DP mu_max, DP Omega, DP kBT, int Npts_mu, int Max_Secs, bool Save_data)
- {
- DP dmu = (mu_max - mu_min)/(Npts_mu - 1);
-
- stringstream LOG_stringstream;
- string LOG_string;
- stringstream GFE_stringstream;
- string GFE_string;
-
- LOG_stringstream << "GFE_2CBG_c_" << c_int << "_mu_min_" << mu_min << "_mu_max_" << mu_max
- << "_Npts_mu_" << Npts_mu << "_Omega_" << Omega << "_kBT_" << kBT << "_Secs_" << Max_Secs << ".log";
- GFE_stringstream << "GFE_2CBG_c_" << c_int << "_mu_min_" << mu_min << "_mu_max_" << mu_max
- << "_Npts_mu_" << Npts_mu << "_Omega_" << Omega << "_kBT_" << kBT << "_Secs_" << Max_Secs << ".dat";
-
- LOG_string = LOG_stringstream.str();
- const char* LOG_Cstr = LOG_string.c_str();
-
- GFE_string = GFE_stringstream.str();
- const char* GFE_Cstr = GFE_string.c_str();
-
- ofstream LOG_outfile;
- ofstream GFE_outfile;
-
- LOG_outfile.open(LOG_Cstr);
- LOG_outfile.precision(6);
-
- GFE_outfile.open(GFE_Cstr);
- GFE_outfile.precision(16);
-
-
- Root_Density_Set Scan_Set (10, 10, 10.0);;
- Root_Density_Set Scan_dSet_dmu (10, 10, 10.0);;
- Root_Density_Set Scan_dSet_dOmega (10, 10, 10.0);;
- DP mu;
- int Max_Secs_per_mu_pt = Max_Secs/Npts_mu;
-
- for (int imu = 0; imu < Npts_mu; ++imu) {
- mu = mu_min + imu * dmu;
- Scan_Set = Solve_2CBG_TBAE_via_refinements (c_int, mu, Omega, kBT, Max_Secs_per_mu_pt/3, LOG_outfile, Save_data);
-
- Scan_dSet_dmu = Solve_2CBG_deps_dchempot (0, Scan_Set, c_int, mu, Omega, kBT, Max_Secs_per_mu_pt/3,
- LOG_outfile, Save_data);
-
- Scan_dSet_dOmega = Solve_2CBG_deps_dchempot (1, Scan_Set, c_int, mu, Omega, kBT, Max_Secs_per_mu_pt/3,
- LOG_outfile, Save_data);
-
- DP dfdmu = Calculate_dGibbs_dchempot (Scan_dSet_dmu, Scan_Set, c_int, mu, Omega, kBT);
- DP dfdOm = Calculate_dGibbs_dchempot (Scan_dSet_dOmega, Scan_Set, c_int, mu, Omega, kBT);
-
- GFE_outfile << mu << "\t" << Calculate_Gibbs_Free_Energy (Scan_Set, c_int, mu, Omega, kBT) << "\t" << Scan_Set.diff
- << "\t" << dfdmu << "\t" << dfdOm << "\t" << 0.5 * (-dfdmu - dfdOm) << "\t" << 0.5 * (-dfdmu + dfdOm)
- << endl;
- } // for imu
-
- LOG_outfile.close();
- GFE_outfile.close();
-
- return;
- }
-
- } // namespace ABACUS
|