I need to solve an ODE that has stiff behaviour. Said ODE would be given by
int odefunc (double x, const double y[], double f[], void *params)
{
double k=1e12; //At k=1e7 it works (doesn't show stiffness)
double y_eq=-1.931+1.5*log(x)-x;
f[0] = k*(exp(2*y_eq-y[0])-exp(y[0]));
return GSL_SUCCESS;
}
I'm not so used to C (I am to C++, though) and the documentation in the GSL page for Differential Equations doesn't have that many comments for me to understand it. I've used this post to understand it (also because I only have 1 ode, not a system of them), and to some extent it has been useful, but it's still a bit confusing to me. For my tests I've used my function instead of the one given, and I've gone with it although I don't understand the code. But now it was key for me to understand, because...
I would need to modify the examples they give me, I need to use an algorithm that solves stiff equations, preferably gsl_odeiv2_step_msbdf with an adaptative step-size or something equivalent to that (the BDF method seems to be used profusely in the academia). That needs the jacobian, and that part is really intricate if you're not used to GSL or C.
To manually implement an algorithmic differentiation it helps to include explicit intermediary steps
int odefunc (double x, const double y[], double f[], void *params)
{
double k=1e12; //At k=1e7 it works (doesn't show stiffness)
double y_eq=-1.931+1.5*log(x)-x;
double v1 = exp(2*y_eq-y[0]);
double v2 = exp(y[0]);
double z = k*(v1-v2);
f[0] = z;
return GSL_SUCCESS;
}
Then you can enhance each step with its derivative propagation
int jac (double x, const double y[], double *dfdy,
double dfdx[], void *params)
{
double k=1e12; //At k=1e7 it works (doesn't show stiffness)
// Dx_dx=Dy_dy=1, Dx_dy=Dy_dx=0 are used without naming them
double y_eq = -1.931+1.5*log(x)-x,
Dy_eq_dx=1.5/x-1,
Dy_eq_dy=0;
double v1 = exp(2*y_eq-y[0]),
Dv1_dx=v1*(2*Dy_eq_dx-0),
Dv1_dy=v1*(2*Dy_eq_dy-1);
double v2 = exp(y[0]),
Dv2_dx=v2*(0),
Dv2_dy=v2*(1);
double z = k*(v1-v2),
Dz_dx=k*(Dv1_dx-Dv2_dx),
Dz_dy=k*(Dv1_dy-Dv2_dy);
dfdx[0] = Dz_dx;
dfdy[0] = Dz_dy;
return GSL_SUCCESS;
}
For larger code use a code-rewriting tool that does these steps automatically. auto-diff.org should have a list of appropriate ones.
Related
The title summarizes the goal that is more exactly to dynamically retrieve the number of dimensions of MATLAB arrays passed to armadillo matrices.
I would like to change the second and third arguments of mY() and mD() to parametric ones below.
// mat(ptr_aux_mem, n_rows, n_cols, copy_aux_mem = true, strict = false)
arma::mat mY(&dY[0], 2, 168, false);
arma::mat mD(&dD[0], 2, 168, false);
This must be definitely a common use case, but I still could not find a nice way of achieving it for the general case when the number of dimensions of the arrays feeding from MATLAB could be arbitrary (n > 2).
For the matrix (two dimensional) case, I could possibly hack my way around but I feel like that is not elegant enough (probably not efficient either).
IMHO, the way to go must be:
matlab::data::TypedArray<double> has getDimensions() member function which retrieves matlab::data::ArrayDimensions that is fundamentally a std::vector<size_t>.
Indexing the first and second element of the vector retrieved by getDimensions() one can retrieve the number of rows and columns, for instance like below.
unsigned int mYrows = matrixY.getDimensions()[0];
unsigned int mYcols = matrixY.getDimensions()[1];
However, with my current setup, I cannot get to call getDimensions() through pointers/references in the foo() function of sub.cpp. If it is feasible, I would neither like to create additional temporary objects nor passing other arguments to foo(). How it possible that way?
Intuition keeps telling me that there must be an elegant solution that way too. Maybe using multiple indirection?
I would highly appreciate any help, hints or constructive comments from more knowledgeable SO members. Thank you in advance.
Setup:
Two C++ source files and a header file:
main.cpp
contains the general IO interface between MATLAB and C++
feeds two double arrays and two double const doubles into C++
it does some Armadillo based looping (this part is not that important therefore omitted) by calling foo()
returns outp which is a “just a plain” scalar double
Nothing fancy or complicated.
sub.cpp
This is only for the foo() looping part.
sub.hpp
Just a simple header file.
// main.cpp
// MATLAB API Header Files
#include "mex.hpp"
#include "mexAdapter.hpp"
// Custom header
#include "sub.hpp"
// Overloading the function call operator, thus class acts as a functor
class MexFunction : public matlab::mex::Function {
public:
void operator()(matlab::mex::ArgumentList outputs,
matlab::mex::ArgumentList inputs){
matlab::data::ArrayFactory factory;
// Validate arguments
checkArguments(outputs, inputs);
matlab::data::TypedArray<double> matrixY = std::move(inputs[0]);
matlab::data::TypedArray<double> matrixD = std::move(inputs[1]);
const double csT = inputs[2][0];
const double csKy = inputs[3][0];
buffer_ptr_t<double> mY = matrixY.release();
buffer_ptr_t<double> mD = matrixD.release();
double* darrY = mY.get();
double* darrD = mD.get();
// data type of outp is "just" a plain double, NOT a double array
double outp = foo(darrY, darrD, csT, csKy);
outputs[0] = factory.createScalar(outp);
void checkArguments(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs){
// Create pointer to MATLAB engine
std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
// Create array factory, allows us to create MATLAB arrays in C++
matlab::data::ArrayFactory factory;
// Check input size and types
if (inputs[0].getType() != ArrayType::DOUBLE ||
inputs[0].getType() == ArrayType::COMPLEX_DOUBLE)
{
// Throw error directly into MATLAB if type does not match
matlabPtr->feval(u"error", 0,
std::vector<Array>({ factory.createScalar("Input must be double array.") }));
}
// Check output size
if (outputs.size() > 1) {
matlabPtr->feval(u"error", 0,
std::vector<Array>({ factory.createScalar("Only one output is returned.") }));
}
}
};
// sub.cpp
#include "sub.hpp"
#include "armadillo"
double foo(double* dY, double* dD, const double T, const double Ky) {
double sum = 0;
// Conversion of input parameters to Armadillo types
// mat(ptr_aux_mem, n_rows, n_cols, copy_aux_mem = true, strict = false)
arma::mat mY(&dY[0], 2, 168, false);
arma::mat mD(&dD[0], 2, 168, false);
// Armadillo calculations
for(int t=0; t<int(T); t++){
// some armadillo based calculation
// each for cycle increments sum by its return value
}
return sum;
}
// sub.hpp
#ifndef SUB_H_INCLUDED
#define SUB_H_INCLUDED
double foo(double* dY, double* dD, const double T, const double Ky);
#endif // SUB_H_INCLUDED
One way is to convert it to arma matrix using a function
template<class T>
arma::Mat<T> getMat( matlab::data::TypedArray<T> A)
{
matlab::data::TypedIterator<T> it = A.begin();
matlab::data::ArrayDimensions nDim = A.getDimensions();
return arma::Mat<T>(it.operator->(), nDim[0], nDim[1]);
}
and call it by
arma::mat Y = getMat<double>(inputs[0]);
arma::mat D = getMat<double>(inputs[1]);
...
double outp = foo(Y,D, csT, csKy);
and change foo() to
double foo( arma::mat& dY, arma::mat& dD, const double T, const double Ky)
I recently started using C++ and I just created a class that allows the integration of a user-defined system of ode's. It uses two different integrators in order to compare its performance. Here is the general layout of the code:
class integrators {
private:
double ti; // initial time
double *xi; // initial solution
double tf; // end time
double dt; // time step
int n; // number of ode's
public:
// Function prototypes
double f(double, double *, double *); // function to integrate
double rk4(int, double, double, double, double *, double *);
double dp8(int, double, double, double, double *, double *);
};
// 4th Order Runge-Kutta function
double integrators::rk4(int n, double ti, double tf, double dt, double *xi, double *xf) {
// Function statements
}
// 8th Order Dormand-Prince function
double integrators::dp8(int n, double ti, double tf, double dt, double *xi, double *xf) {
// Function statements
}
// System of first order differential equations
double integrators::f(double t, double *x, double *dx) {
// Function statements
}
int main() {
// Initial conditions and time related parameters
const int n = 4;
double t0, tmax, dt;
double x0[n], xf[n];
x0[0] = 0.0;
x0[1] = 0.0;
x0[2] = 1.0;
x0[3] = 2.0;
// Calling class integrators
integrators example01;
integrators example02;
// First integrator
example02.dp8(n, t0, tmax, dt, x0, xf);
// Second integrator
example01.rk4(n, t0, tmax, dt, x0, xf);
}
The problem is that the array containing the initial conditions x0 in main, changes after executing the first integrator and I cannot use the same initial conditions for the second integrator, unless I define another array with the same initial conditions (x0_rk4 and x0_dp8). Is there a more professional way to keep this array constant in order to use it in both integrators?
The easiest way is to make a local copy of array inside integrating functions.
Change the way you are passing 'n' to function to 'const int n', so you can make something like double currentSolution[n]; inside and copy elements from initial array to new one. This approach will save your initial array intact, unless you will "accidently" modify it somewhere.
To prevent this probability of accident modification we need to go deeper and use one of stl containers. I think you will be fine with std::valarray<T>.
Change the way you are passing it to const std::valarray<double>& and again make non-const local copy.
No, not really. But there exist a more elegant solution:
std::array<double, n> x0_rk4 = { 0.0, 0.0, 1.0, 2.0 };
auto x0_dp8 = x0_rk4; // copy!
You will have to use x0_rk4.data() to access the underlying array. Note that it would be better if you used std::array and other modern C++ features instead of raw pointers and the like.
From a speed and efficiency standpoint: which is considered best-practice, create a temporary object or decompose a (possibly temporary) argument object?
In this example the implementations of the functions are mutually exclusive for DRY purposes. Both WILL NOT be implemented as shown, but one will be implemented in terms of the other which will delegate the actual work.
void SetPoints(double xA, double yA, double xB, double yB, double xC, double yC);
void SetPoints(const Point& A, const Point& B, const Point& C);
///Option one: create temporary objects:
void SetPoints(double xA, double yA, double xB, double yB, double xC, double yC) {
SetPoints(Point(xA, yA), Point(xB, yB), Point(xC, yC));
}
//Option two: decompose object arguments
void SetPoints(const Point& A, const Point& B, const Point& C) {
SetPoints(A.GetX(), A.GetY(), B.GetX(), B.GetY(), C.GetX(), C.GetY());
}
Overwhelmingly likely to be completely irrelevant. The compiler will likely not even generate different assembly for the two, and even if it did, the performance cost of a tiny thunk would be negligible. There's no reason to even think about this.
The best function is the one that is the most clear/etc, in this case.
I'd implement only the one that takes Point objects, then create a Point constructor that takes an std::initializer_list, so when you want to pass individual doubles, you can use something like:
SetPoints({xA, yA}, {xB, yB}, {xC, yC});
In my program -- which uses the Eigen library -- I need to operate on 2D vectors. In my inner loop I have the following function:
static inline double eval(double x, double y, double xi, double yi)
{
const double invlen2 = 1/(x*x + y*y);
const double invlen4 = invlen2*invlen2;
const double invlen6 = invlen4*invlen2;
const double x2 = x*x, y2 = y*y;
const double x3 = x2*x, y3 = y2*y;
const double xi2 = xi*xi, yi2 = yi*yi;
return x*invlen2 + invlen4*(x2*xi + 2*x*y*yi - xi*y2)
+ invlen6*(x3*xi2 + 3*x*y2*yi2 + 6*x2*y*xi*yi - 3*x*xi2*y2 - 2*y3*xi*yi - x3*yi2);
}
void f(Vector2d& out, const Vector2d& R, const Vector2d& r)
{
out.x() = eval(R.x(), R.y(), r.x(), r.y());
out.y() = eval(R.y(), R.x(), r.y(), r.x());
}
This expression, although messy, seems like a prime candidate for vectorisation as both the x() and y() computations follow identical paths. My question is how to do it with Eigen without needing to manually drop down to assembly.
This answer has nothing to do with Eigen, but since you mentioned manually dropping down to assembly, I'll add this.
You don't need to use assembly to vectorize code. There are compiler intrinsics that will let manually vectorize without assembly:
http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/intref_cls/common/intref_overview.htm#intref_overview
That said: It looks like Eigen already has internal support for vectorization, but it doesn't appear to be applicable in your example. So I can see why you want to do it manually.
Suppose we want two constructors for a class representing complex numbers:
Complex (double re, double img) // construct from cartesian coordinates
Complex (double A, double w) // construct from polar coordinates
but the parameters (number and type) are the same: what is the more elegant way
to identify what is intended? Adding a third parameter to one of the constructors?
It is better to add static methods with appropriate names and let them to create the objects.
static Complex createFromCartesian(double re, double img);
static Complex createFromPolar(double A, double w);
You can't have two constructors (or any functions) with the same signatures. The best solution is probably to create classes for your coordinate types and overload on those. For example:
struct CartCoord {
CartCoord( double re, double img ) : mRe(re), mImg(img) {}
double mRe, mImg;
};
struct PolarCoord {
PolarCoord( double a, double v ) : mA(a), mV(v) {}
double mA, mV;
};
Then your constructors become:
Complex( const CartCoord & c );
Complex( const PolarCoord & c);
In use:
Complex c( CartCoord( 1, 2 ) );
You can also use them with overloaded operators of the Complex class. For example, assuming you have a binary + operator for the class define as:
Complex operator+( const Complex &, const Complex & );
then:
Complex a( CartCoord( 0, 0 ) );
Complex b = a + PolarCoord( 1, 1 );
As we have a conversion constructor from PolarCoord to Complex, this will be used in the + expression. This is more natural (IMHO) than calling static functions to create the temporary..
This is an example of Koenig's dictum (or at least a version of it) - whenever faced with a difficult problem, introduce a new level of classes to solve it.
Use the named constructor idiom described here at the Parashift C++ FAQ.
You can't - if the method signatures are the same, you're stuffed.
Of course, you could always create a subclass for each type of coordinate system, but that's far from ideal - especially if you later find a good reason to want to subclass Complex for other reasons...
Instead of having two constructors, you need to have only one, but add a third parameter, for example:
Complex (double re, double img, enum type) {
if(type == polar) {
..treat as polar coordinates..
} else {
..treat as cartesian coordinates..
}
}
'enum type' can have a default type as well so you don't have to supply what type of coordinates you intend to use every time, the default should off course be what's most used.
Complex (double re, double img, enum type = polar);
Since no one mentioned it, you can use tags:
class Complex{
struct CartCoord{};
struct PolarCoord{};
Complex( CartCoord, double re, double img);
Complex( PolarCoord, double a, double v);
};
int main(){
auto c1 = Complex(Complex::CartCoord{}, 5, 6);
auto c2 = Complex(Complex::PolarCoord{}, 5, 6);
}
I don't know if it is good practice in C++ but I would name these two methods differently, at least for a maintainability point of view.
I would probably create more classes, but then I am an adept of Boost Strong Typedef library.
For me it does not make sense to use double to represent both coordinates, module and angles.
So I would have:
class CoordinateX {};
class CoordinateY {};
class Modulus {};
class Angle {};
class Complex
{
public:
Complex(CoordinateX, CoordinateY);
Complex(Modulus, Angle);
};
And there it's perfectly clear, and there is no ambiguity. Also you add some compile-time check of "units" in a loose sense. It rarely makes sense (if ever) to add an X-coordinate and an Y-coordinate, or worse a distance and an angle.
For me the more elegant way would be to create a class representing cartesian coordinates and another representing polar coordinates, then give object of the relevant class to the constructors.
That way you would have two constructor using different parameters.
I use this simple alternative way while practicing C++, I don't know if it is what you want.
class Vector{
public:
float x, y;
Vector();
Vector(float , float, bool);
float get_distance(Vector v); // find distance from another vector
float get_magnitude(); // find distance from origin point
Vector add(Vector v);
Vector subtract(Vector v);
Vector multiply(Vector v); // multiply by vector
Vector multiply(float scalar); // multiply by scalar
float get_angle();
};
Vector::Vector(float a, float b, bool is_cartesian = true){
if(is_cartesian){
x = a;
y = b;
}
else{
x = a * cos( b );
y = a * sin( b );
}
}