lammps/lib/atc/Function.cpp

572 lines
19 KiB
C++

#if !defined(_WIN32)
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__)
#include <cstdlib>
#else
#include <alloca.h>
#endif
#endif
#include "Function.h"
#include "ATC_Error.h"
#include "LammpsInterface.h"
#include <sstream>
using std::stringstream;
using std::string;
using std::set;
using std::fstream;
namespace ATC {
//====================================================================
// UXT_Function
//===================================================================
UXT_Function::UXT_Function(int /* narg */, double* /* args */) { }
//====================================================================
// UXT_Function_Mgr
//====================================================================
UXT_Function_Mgr * UXT_Function_Mgr::myInstance_ = NULL;
// -----------------------------------------------------------------
// instance()
// -----------------------------------------------------------------
UXT_Function_Mgr * UXT_Function_Mgr::instance()
{
if (myInstance_ == NULL) {
myInstance_ = new UXT_Function_Mgr();
}
return myInstance_;
}
// Destructor
UXT_Function_Mgr::~UXT_Function_Mgr()
{
// Delete all functions created using "new"
set<UXT_Function * >::iterator it;
for (it = pointerSet_.begin(); it != pointerSet_.end(); it++)
if (*it) delete *it;
}
// add user function into the if statement and assign returnFunction to it
UXT_Function* UXT_Function_Mgr::function(string & type, int nargs, double * args)
{
UXT_Function * returnFunction;
if (type=="linear") {
returnFunction = new ScalarLinearFunction(nargs,args);
}
else
throw ATC_Error("Bad user function name");
pointerSet_.insert(returnFunction);
return returnFunction;
}
// add user function into the if statement and assign returnFunction to it
UXT_Function* UXT_Function_Mgr::function(char ** args, int nargs)
{
string type = args[0];
int narg = nargs -1;
#ifdef _WIN32
double *dargs = (double *) _alloca(sizeof(double) * narg);
#else
double *dargs = (double *) alloca(sizeof(double) * narg);
#endif
for (int i = 0; i < narg; ++i) dargs[i] = atof(args[i+1]);
return function(type, narg, dargs);
}
// add constant function
UXT_Function* UXT_Function_Mgr::linear_function(double c0, double c1)
{
double args[2] = {c0,c1};
UXT_Function * returnFunction = new ScalarLinearFunction(2,args);
pointerSet_.insert(returnFunction);
return (returnFunction);
}
UXT_Function* UXT_Function_Mgr::copy_UXT_function(UXT_Function* other)
{
string tag = other->tag();
UXT_Function * returnFunction = NULL;
if (tag=="linear") {
ScalarLinearFunction * other_cast = (ScalarLinearFunction*) other;
returnFunction = new ScalarLinearFunction(*other_cast);
}
pointerSet_.insert(returnFunction);
return returnFunction;
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// ScalarLinearFunction
//--------------------------------------------------------------------
//--------------------------------------------------------------------
ScalarLinearFunction::ScalarLinearFunction(int narg, double* args)
: UXT_Function(narg,args)
{
tag_ = "linear";
c0_ = args[0];
c1_ = args[1];
stringstream ss;
ss << "created function : " << c0_ << " + " << c1_ << "*u";
ATC::LammpsInterface::instance()->print_msg_once(ss.str());
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// XT_Function
//--------------------------------------------------------------------
//--------------------------------------------------------------------
XT_Function::XT_Function(int narg, double* args)
{
if (narg > 5 ) {
x0[0] = args[0];
x0[1] = args[1];
x0[2] = args[2];
mask[0] = args[3];
mask[1] = args[4];
mask[2] = args[5];
}
else {
x0[0] = 0.0;
x0[1] = 0.0;
x0[2] = 0.0;
mask[0] = 0.0;
mask[1] = 0.0;
mask[2] = 0.0;
}
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// XT_Function_Mgr
//--------------------------------------------------------------------
//--------------------------------------------------------------------
XT_Function_Mgr * XT_Function_Mgr::myInstance_ = NULL;
// -----------------------------------------------------------------
// instance()
// -----------------------------------------------------------------
XT_Function_Mgr * XT_Function_Mgr::instance()
{
if (myInstance_ == NULL) {
myInstance_ = new XT_Function_Mgr();
}
return myInstance_;
}
// Destructor
XT_Function_Mgr::~XT_Function_Mgr()
{
// Delete all functions created using "new"
set<XT_Function * >::iterator it;
for (it = pointerSet_.begin(); it != pointerSet_.end(); it++)
if (*it) delete *it;
}
// add user function into the if statement and assign returnFunction to it
XT_Function* XT_Function_Mgr::function(string & type, int nargs, double * args)
{
XT_Function * returnFunction;
if (type=="constant") {
returnFunction = new ConstantFunction(nargs,args);
}
else if (type=="temporal_ramp") {
returnFunction = new TemporalRamp(nargs,args);
}
else if (type=="linear")
returnFunction = new LinearFunction(nargs,args);
else if (type=="piecewise_linear")
returnFunction = new PiecewiseLinearFunction(nargs,args);
else if (type=="linear_temporal_ramp")
returnFunction = new LinearTemporalRamp(nargs,args);
else if (type=="quadratic")
returnFunction = new QuadraticFunction(nargs,args);
else if (type=="sine")
returnFunction = new SineFunction(nargs,args);
else if (type=="gaussian")
returnFunction = new GaussianFunction(nargs,args);
else if (type=="gaussian_temporal_ramp")
returnFunction = new GaussianTemporalRamp(nargs,args);
else if (type=="radial_power")
returnFunction = new RadialPower(nargs,args);
else
throw ATC_Error("Bad user function name");
pointerSet_.insert(returnFunction);
return returnFunction;
}
// add user function into the if statement and assign returnFunction to it
XT_Function* XT_Function_Mgr::function(char ** args, int nargs)
{
string type = args[0];
int narg = nargs -1;
#ifdef _WIN32
double *dargs = (double *) _alloca(sizeof(double) * narg);
#else
double *dargs = (double *) alloca(sizeof(double) * narg);
#endif
for (int i = 0; i < narg; ++i) dargs[i] = atof(args[i+1]);
return function(type, narg, dargs);
}
// add constant function
XT_Function* XT_Function_Mgr::constant_function(double c)
{
XT_Function * returnFunction = new ConstantFunction(c);
pointerSet_.insert(returnFunction);
return (returnFunction);
}
XT_Function* XT_Function_Mgr::copy_XT_function(XT_Function* other)
{
string tag = other->tag();
XT_Function * returnFunction = NULL;
if (tag=="linear") {
LinearFunction * other_cast = (LinearFunction*) other;
returnFunction = new LinearFunction(*other_cast);
}
else if (tag=="piecewise_linear") {
PiecewiseLinearFunction * other_cast = (PiecewiseLinearFunction*) other;
returnFunction = new PiecewiseLinearFunction(*other_cast);
}
else if (tag=="quadratic") {
QuadraticFunction * other_cast = (QuadraticFunction*) other;
returnFunction = new QuadraticFunction(*other_cast);
}
else if (tag=="sine") {
SineFunction * other_cast = (SineFunction*) other;
returnFunction = new SineFunction(*other_cast);
}
else if (tag=="gaussian") {
GaussianFunction * other_cast = (GaussianFunction*) other;
returnFunction = new GaussianFunction(*other_cast);
}
else if (tag=="gaussian_temporal_ramp") {
GaussianTemporalRamp * other_cast = (GaussianTemporalRamp*) other;
returnFunction = new GaussianTemporalRamp(*other_cast);
}
else if (tag=="temporal_ramp") {
TemporalRamp * other_cast = (TemporalRamp*) other;
returnFunction = new TemporalRamp(*other_cast);
}
else if (tag=="radial_power") {
RadialPower * other_cast = (RadialPower*) other;
returnFunction = new RadialPower(*other_cast);
}
pointerSet_.insert(returnFunction);
return returnFunction;
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// ConstantFunction
//--------------------------------------------------------------------
//--------------------------------------------------------------------
ConstantFunction::ConstantFunction(int narg, double* args)
: XT_Function(narg,args),
C0(args[0])
{
tag_ = "constant";
}
//--------------------------------------------------------------------
ConstantFunction::ConstantFunction(double arg)
: XT_Function(1,&arg),
C0(arg)
{
tag_ = "constant";
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// LinearFunction
//--------------------------------------------------------------------
//--------------------------------------------------------------------
LinearFunction::LinearFunction(int narg, double* args)
: XT_Function(narg,args)
{
C0 = args[6];
tag_ = "linear";
stringstream ss;
ss << "created function : " << C0 << " + " << mask[0] << "(x-"<< x0[0] << ")+"<< mask[1] << "(y-"<<x0[1]<<")+"<<mask[2]<<"(z-"<<x0[2] << ")";
ATC::LammpsInterface::instance()->print_msg_once(ss.str());
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// PiecewiseLinearFunction
//--------------------------------------------------------------------
//--------------------------------------------------------------------
PiecewiseLinearFunction::PiecewiseLinearFunction(int narg, double* args)
: XT_Function(narg,args)
{
int i=0, idx = 6, n = (narg-idx)/2;
xi.reset(n);
fi.reset(n);
while (idx < narg) {
xi(i) = args[idx++];
fi(i++) = args[idx++];
}
tag_ = "piecewise_linear";
stringstream ss;
ss << "created piecewise function : " << n << " \n";
for (i = 0; i < n; i++) {
ss << xi(i) << " " << fi(i) << "\n";
}
ATC::LammpsInterface::instance()->print_msg_once(ss.str());
}
double PiecewiseLinearFunction::f(double * x, double /* t */)
{
double s = mask[0]*(x[0]-x0[0])+mask[1]*(x[1]-x0[1])+mask[2]*(x[2]-x0[2]);
int index = xi.index(s);
if (index < 0) return fi(0);
else if (index >= xi.size()-1 ) return fi(xi.size()-1);
else {
double f = fi(index)
+ (fi(index+1)-fi(index))*(s-xi(index))/(xi(index+1)-xi(index));
return f;
}
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// LinearTemporalRamp
//--------------------------------------------------------------------
//--------------------------------------------------------------------
LinearTemporalRamp::LinearTemporalRamp(int narg, double* args)
: XT_Function(narg,args)
{
double mask_final[3];
mask_final[0] = args[6];
mask_final[1] = args[7];
mask_final[2] = args[8];
C0_initial = args[9];
double C0_final = args[10];
double delta_t = args[11];
for (int i = 0; i < 3; i++)
mask_slope[i] = (mask_final[i] - mask[i])/delta_t;
C0_slope = (C0_initial - C0_final)/delta_t;
}
double LinearTemporalRamp::f(double* x, double t) {
double slope[3];
for (int i = 0; i < 3; i++)
slope[i] = mask[i] + mask_slope[i]*t;
double C0 = C0_initial + C0_slope*t;
return slope[0]*(x[0]-x0[0])+slope[1]*(x[1]-x0[1])+slope[2]*(x[2]-x0[2]) + C0;
}
double LinearTemporalRamp::dfdt(double* x, double /* t */) {
return mask_slope[0]*(x[0]-x0[0])+mask_slope[1]*(x[1]-x0[1])+mask_slope[2]*(x[2]-x0[2]) + C0_slope;
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// QuadraticFunction
//--------------------------------------------------------------------
//--------------------------------------------------------------------
QuadraticFunction::QuadraticFunction(int narg, double* args)
: XT_Function(narg,args)
{
C0 = args[6];
C2[0] = args[7];
C2[1] = args[8];
C2[2] = args[9];
C2[3] = args[10];
C2[4] = args[11];
C2[5] = args[12];
tag_ = "quadratic";
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// SineFunction
//--------------------------------------------------------------------
//--------------------------------------------------------------------
SineFunction::SineFunction(int narg, double* args)
: XT_Function(narg,args)
{
C = args[6];
w = args[7];
C0 = args[8];
tag_ = "sine";
stringstream ss;
ss << "created function : " << C << " sin( " << mask[0] << "(x-"<< x0[0] << ")+"<< mask[1] << "(y-"<<x0[1]<<")+"<<mask[2]<<"(z-"<<x0[2] << ") - " << w << "t ) + " << C0;
ATC::LammpsInterface::instance()->print_msg_once(ss.str());
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// GaussianFunction
//--------------------------------------------------------------------
//--------------------------------------------------------------------
GaussianFunction::GaussianFunction(int narg, double* args)
: XT_Function(narg,args)
{
tau = args[6];
C = args[7];
C0 = args[8];
tag_ = "gaussian";
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// GaussianTemporalRamp
//--------------------------------------------------------------------
//--------------------------------------------------------------------
GaussianTemporalRamp::GaussianTemporalRamp(int narg, double* args)
: GaussianFunction(narg,args)
{
tau_initial = args[9];
C_initial = args[10];
C0_initial = args[11];
double delta_t = args[12];
tau_slope = (tau - tau_initial)/delta_t;
C_slope = (C - C_initial)/delta_t;
C0_slope = (C0 - C0_initial)/delta_t;
tag_ = "gaussian_temporal_ramp";
}
double GaussianTemporalRamp::f(double* x, double t) {
tau = tau_initial + tau_slope*t;
C = C_initial + C_slope*t;
C0 = C0_initial + C0_slope*t;
return GaussianFunction::f(x,t);
}
double GaussianTemporalRamp::dfdt(double* x, double t) {
tau = tau_initial + tau_slope*t;
C = C_initial + C_slope*t;
C0 = C0_initial + C0_slope*t;
double dfdt = 0.;
dfdt += C_slope*exp(-(mask[0]*(x[0]-x0[0])*(x[0]-x0[0])
+mask[1]*(x[1]-x0[1])*(x[1]-x0[1])
+mask[2]*(x[2]-x0[2])*(x[2]-x0[2]))
/tau/tau);
dfdt += C*exp(2.*tau_slope*(mask[0]*(x[0]-x0[0])*(x[0]-x0[0])
+mask[1]*(x[1]-x0[1])*(x[1]-x0[1])
+mask[2]*(x[2]-x0[2])*(x[2]-x0[2]))
/tau/tau/tau);
dfdt += C0_slope;
return dfdt;
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// TemporalRamp
//--------------------------------------------------------------------
//--------------------------------------------------------------------
TemporalRamp::TemporalRamp(int narg, double* args)
: XT_Function(narg,args)
{
f_initial = args[0];
double f_final = args[1];
double delta_t = args[2];
slope = (f_final - f_initial)/delta_t;
tag_ = "temporal_ramp";
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// RadialPower
//--------------------------------------------------------------------
//--------------------------------------------------------------------
RadialPower::RadialPower(int narg, double* args)
: XT_Function(narg,args)
{
C0 = args[6];
n = args[7];
tag_ = "radial_power";
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// InterpolationFunction
//--------------------------------------------------------------------
//--------------------------------------------------------------------
void InterpolationFunction::initialize(int npts, fstream &fileId, double coef)
{ // read data
npts_ = npts;
xs_.reset(npts);
fs_.reset(npts);
fps_.reset(npts);
double x,f,fp;
int i = 0;
while(fileId.good() && i < npts) {
fileId >> x >> f >> fp;
xs_(i)=x;
fs_(i)=coef*f;
fps_(i)=coef*fp;
i++;
}
// scale tangents
double dx, dx0 = xs_(1)-xs_(0);
for (int i = 0; i < npts_ ; i++) {
if (i == 0) { dx = xs_(1)-xs_(0); }
else if (i+1 == npts_) { dx = xs_(npts_-1)-xs_(npts_-2); }
else { dx= 0.5*(xs_(i+1)-xs_(i-1)); }
if (fabs(dx-dx0) > 1.e-8) throw ATC_Error("InterpolationFunction::initialize non-uniform data spacing not handled currently");
fps_(i) *= dx;
}
// options: calculate / adjust tangents for monotonicity
}
double InterpolationFunction::coordinate(double x,
double & f0, double & fp0, double & f1, double & fp1, double & inv_dx ) const
{
int i0 = xs_.index(x);
int i1 = i0+1;
if (i0 < 0) {
double x0 = xs_(0), x1 = xs_(1);
inv_dx = 1./(x1-x0);
fp0 = fp1 = fps_(0);
f1 = fs_(0);
f0 = fp0*(x-xs_(0))+f1;
return 0;
}
else if (i1 >= npts_) {
double x0 = xs_(npts_-2), x1 = xs_(npts_-1);
inv_dx = 1./(x1-x0);
fp0 = fp1 = fps_(i0);
f0 = fs_(i0);
f1 = fp0*(x-xs_(i0))+f0;
return 1;
}
else {
double x0 = xs_(i0), x1 = xs_(i1);
inv_dx = 1./(x1-x0);
f0 = fs_ (i0); f1 = fs_ (i1);
fp0 = fps_(i0); fp1 = fps_(i1);
double t = (x-x0)*inv_dx;
return t;
}
}
double InterpolationFunction::f(const double x) const
{
double f0,fp0,f1,fp1,inv_dx;
double t = coordinate(x,f0,fp0,f1,fp1,inv_dx);
double t2 = t*t;
double t3 = t*t2;
double h00 = 2*t3 - 3*t2 + 1;
double h10 = t3 - 2*t2 + t;
double h01 =-2*t3 + 3*t2;
double h11 = t3 - t2;
double f = h00 * f0 + h10 * fp0 + h01 * f1 + h11 * fp1;
return f;
}
double InterpolationFunction::dfdt(const double x) const
{
double f0,fp0,f1,fp1,inv_dx;
double t = coordinate(x,f0,fp0,f1,fp1,inv_dx);
double t2 = t*t;
double d00 = 6*t2 - 6*t;
double d10 = 3*t2 - 4*t + 1;
double d01 =-6*t2 + 6*t;
double d11 = 3*t2 - 2*t;
double fp = d00 * f0 + d10 * fp0 + d01 * f1 + d11 * fp1;
fp *= inv_dx;
return fp;
}
}