MDStressLab++
MethodSphere.cpp
Go to the documentation of this file.
1 /*
2  * MethodSphere.cpp
3  *
4  * Created on: Nov 5, 2019
5  * Author: Nikhil
6  */
7 
8 #include <math.h>
9 #include <MethodSphere.h>
10 #include <iostream>
11 #include <limits>
12 #include "typedef.h"
13 
14 
15 MethodSphere::MethodSphere(double averagingDomainSize, std::string type="virial") : Method<MethodSphere>(averagingDomainSize)
16 {
17  double normalizer;
18  if (type =="hardy")
19  {
20  // weighting function:
21 
22  //w(r)= c if r<= R/2,
23  // = 2c(1-r/R) if R/2<=r<=R
24  //where c= 8/(5\pi R^3)
25 
26  normalizer= 8/(5*M_PI*pow(averagingDomainSize,3));
27  // constant polynomial
28  std::deque<double> constant{normalizer};
29  Polynomial constantPolynomial{constant};
30  //linear polynomial
31  std::deque<double> linear{2*normalizer,-2*normalizer/averagingDomainSize};
32  Polynomial linearPolynomial{linear};
33 
34 
35  // construct piecewise polynomial
36  std::pair<double,double> interval;
37  interval.first= 0;
38  interval.second= averagingDomainSize/2;
39  piecewisePolynomial[interval]= constantPolynomial;
40 
41  interval.first= averagingDomainSize/2;
42  interval.second= averagingDomainSize;
43  piecewisePolynomial[interval]= linearPolynomial;
44  return;
45  }
46  else if (type == "virial")
47  {
48  normalizer= 1/(M_PI*pow(averagingDomainSize,3));
49  std::deque<double> constant{normalizer};
50  // constant polynomial
51  Polynomial constantPolynomial{constant};
52 
53  std::pair<double,double> interval;
54  interval.first= 0;
55  interval.second= averagingDomainSize;
56  piecewisePolynomial[interval]= constantPolynomial;
57  return;
58  }
59  assert(0);
60 }
61 
62 MethodSphere::MethodSphere(double averagingDomainSize, std::map<double,double> map) : Method<MethodSphere>(averagingDomainSize)
63 {
64  // ensure the domain of map lies in between 0 and 1, and its range is non-negative
65  assert( (map.cbegin())->first >= 0 &&
66  (map.cend())->first <= 1 &&
67  (map.cbegin())->second >= 0 &&
68  (map.cend())->second >= 0 );
69 
70  for (auto iter = map.cbegin(); iter != map.cend(); iter++)
71  {
72  // (y-y1)/(y2-y1) = (x-x1)/(x2-x1)
73  // y = (y2-y1)/(x2-x1) * (x-x1) + y1
74  // = y1-x1*(y2-y1)/(x2-x1) + (y2-y1)/(x2-x1) * x
75  auto nextiter= std::next(iter);
76  if (nextiter != map.cend())
77  {
78  double x1= iter->first; double x2= nextiter->first;
80  std::pair<double,double> interval{x1,x2};
81 
82  double y1= iter->second; double y2= nextiter->second;
83  std::deque<double> linear{ y1-x1*(y2-y1)/(x2-x1), (y2-y1)/(x2-x1) };
84  Polynomial linearPolynomial{linear};
85  piecewisePolynomial[interval]= linearPolynomial;
86  }
87  else
88  {
89  if (abs(iter->first-1.0)>epsilon)
90  MY_ERROR("Weight function is not defined entirely on the averaging domain.");
91  break;
92  }
93  }
94  // now compute the normalizer
95  double integral= 0;
96  for(auto iter=piecewisePolynomial.cbegin(); iter!=piecewisePolynomial.cend(); iter++)
97  {
98  Polynomial temp(iter->second);
99  temp.coefficients.push_front(0); temp.coefficients.push_front(0); // Multiplying the polynomial by r^2
100  Polynomial integratedPolynomial= temp.integrate();
101  integral= integral+integratedPolynomial(iter->first.second) - integratedPolynomial(iter->first.first);
102  }
103  double normalizer = 1/(4*M_PI*integral);
104  for(auto iter=piecewisePolynomial.begin(); iter!=piecewisePolynomial.end(); iter++)
105  {
106  for(auto& coeff : iter->second.coefficients)
107  {
108  coeff= normalizer*coeff;
109  }
110  }
111 }
112 
113 
115 {
116  *this= _hardy;
117 }
118 
120  // TODO Auto-generated destructor stub
121 }
122 
123 double MethodSphere::integratePolynomial(const int& degree,
124  const double& a,
125  const double& b,
126  const double& r1,
127  const double& r2) const
128 {
129  assert(r1<=r2);
130  switch(degree)
131  {
132  case 0:
133  {
134  assert (a*pow(r2,2)+b+epsilon>0 && a*pow(r1,2)+b+epsilon>0);
135  return (std::sqrt(a*pow(r2,2)+b+epsilon) - std::sqrt(a*pow(r1,2)+b+epsilon))/a;
136  }
137 
138  case 1:
139  {
140  assert(a*r1*r1+b+epsilon>0 && a*r2*r2+b+epsilon>0 && a>0);
141  double temp1= std::sqrt(a)*std::sqrt(a*r1*r1 + b + epsilon);
142  double temp2= std::sqrt(a)*std::sqrt(a*r2*r2 + b + epsilon);
143 
144  return ((r2*temp2-b*log(temp2+a*r2))-
145  (r1*temp1-b*log(temp1+a*r1)))/(2*pow(a,1.5));
146  }
147  default:
148  MY_ERROR("Attempt to integrate polynomial of degree not equal to 0 or 1.");
149  }
150 
151 }
152 
153 double MethodSphere::operator()(const Vector3d& vec) const
154 {
155  double r= vec.norm();
156 
157  auto iter = std::find_if(piecewisePolynomial.cbegin(), piecewisePolynomial.cend(),
158  [=](const std::pair< std::pair<double,double>, Polynomial>& polynomial)
159  {
160  return r>=polynomial.first.first && r<polynomial.first.second;
161  });
162 
163  if (iter == piecewisePolynomial.end()) MY_ERROR("Argument out of range for the piecewise-defined weight function");
164  return (iter->second)(r);
165 }
166 
167 double MethodSphere::bondFunction(const Vector3d& vec1, const Vector3d& vec2) const
168 {
169  double r1= vec1.norm();
170  double r2= vec2.norm();
171 
172  double a= 4*(vec1-vec2).squaredNorm();
173  double b= 4*pow(vec2.dot(vec1)-vec1.dot(vec1),2)-a*r1*r1;
174 
175  double sPerp= (vec1.dot(vec1)-vec2.dot(vec1))/(vec1-vec2).squaredNorm();
176 
177  Vector3d vecPerp;
178  vecPerp= (1-sPerp)*vec1+sPerp*vec2;
179  double rPerp= vecPerp.norm();
180  assert(rPerp<std::min(r1,r2)+epsilon);
181 
183  if (rPerp>=averagingDomainSize) return 0;
184 
185  r1= std::min(r1,averagingDomainSize);
186  r2= std::min(r2,averagingDomainSize);
187 
188  double rmin;
189  double rmax;
190  double result= 0;
191  if (sPerp<0 || sPerp>1)
192  {
193  rmin= std::min(r1,r2);
194  rmax= std::max(r1,r2);
195 
196  if (abs(rmax-rmin)>epsilon) return integrate(a,b,rmin,rmax);
197  else return 0;
198  }
199  else
200  {
201  rmin= rPerp;
202  if (abs(r1-rmin)>epsilon) result= integrate(a,b,rmin,r1);
203  if (abs(r2-rmin)>epsilon) result= result+integrate(a,b,rmin,r2);
204 
205  return result;
206  }
207  assert(0);
208 }
209 
210 double MethodSphere::integrate(const double& a,
211  const double& b,
212  const double& rmin,
213  const double& rmax) const
214 {
216  assert(rmin<=rmax && rmax<=averagingDomainSize);
217  double result= 0;
218  auto iterMin = std::find_if(piecewisePolynomial.cbegin(), piecewisePolynomial.cend(),
219  [=](const std::pair< std::pair<double,double>, Polynomial>& polynomial)
220  {
221  return rmin>=polynomial.first.first && rmin<polynomial.first.second;
222  });
223  if (iterMin == piecewisePolynomial.cend()) MY_ERROR("Lower integral limit out of range for the piecewise-defined weight function");
224  auto iterMax = std::find_if(iterMin, piecewisePolynomial.cend(),
225  [=](const std::pair< std::pair<double,double>, Polynomial>& polynomial)
226  {
227  return rmax>=polynomial.first.first && rmax<polynomial.first.second;
228  });
229 
230  for(auto it=iterMin; it!=piecewisePolynomial.cend(); it++)
231  {
232  double lb,ub;
233  if (it == iterMin) lb= rmin;
234  else lb= it->first.first;
235  if (it == iterMax) ub= rmax;
236  else ub= it->first.second;
237 
238  int degree= 0;
239  for(const auto& coefficient : it->second.coefficients)
240  {
241  result= result + 2*coefficient*integratePolynomial(degree,a,b,lb,ub);
242  degree++;
243  }
244 
245  if (it == iterMax) break;
246  }
247  return result;
248 }
249 
double bondFunction(const Vector3d &vec1, const Vector3d &vec2) const
double operator()(const Vector3d &vec) const
const double epsilon
Definition: typedef.h:73
Polynomial integrate() const
Definition: Polynomial.h:35
double averagingDomainSize
Definition: Method.h:24
double getAveragingDomainSize() const
virtual ~MethodSphere()
MethodSphere(double, std::string)
Definition: Method.h:14
#define MY_ERROR(message)
Definition: typedef.h:17
Eigen::Matrix< double, 1, DIM, Eigen::RowMajor > Vector3d
Definition: typedef.h:60
std::deque< double > coefficients
Definition: Polynomial.h:20