I need to solve some quadratic programs using CGAL by specifying the problem through iterators. Below is a dummy example which runs fine (problem is infeasible). The problem is when I change the constraints to be ">=":
std::array<CGAL::Comparison_result, numAConstraints> relationships
= { CGAL::LARGER,CGAL::LARGER,CGAL::LARGER,CGAL::LARGER, };
Then I get:
"basis-inverse check: failed (row=0 | col=1)" from qp_solver_imp.h line 1155.
This is the sample code that runs without crashing, all constraints are "<=":
#include "stdafx.h"
#include <array>
#include <iterator>
#include <vector>
#include <CGAL/basic.h>
#include <CGAL/QP_models.h>
#include <CGAL/QP_functions.h>
#include <CGAL/MP_Float.h>
typedef double ET;
int main(){
const int numAConstraints = 4;
const int numVariables = 3;
typedef CGAL::Quadratic_program_from_iterators
<double**, // for A
double*, // for b
std::array<CGAL::Comparison_result, numAConstraints>::const_iterator, // for r
bool*, // for fl
double*, // for l
bool*, // for fu
double*, // for u
double**, // for D
double*> // for c
Program;
typedef CGAL::Quadratic_program_solution<ET> Solution;
double Ax[] = { 1, -1, -1, 1 }; // column for x
double Ay[] = { -2, -2, 2, -1 };
double Az[] = { 1, 0.0, -5, 5 };
double* A[] = { Ax, Ay, Az }; // A comes columnwise
double b[] = { -2.4, -6, -2, 1.0 }; // right-hand side
std::array<CGAL::Comparison_result, numAConstraints> relationships
= { CGAL::SMALLER,CGAL::SMALLER,CGAL::SMALLER, CGAL::SMALLER };
bool fl[] = { true, true, true }; // both x, y are lower-bounded
double l[] = { 0, 0, 0 };
bool fu[] = { false, false, false }; // only y is upper-bounded
double u[] = { 0, 0, 0 }; // x's u-entry is ignored
double D1[] = { 1 }; // 2D_{1,1}
double D2[] = { 0, 0.1 };
double D3[] = { 10, 0.0, 100.0 };
double* D[] = { D1, D2, D3 }; // D-entries on/below diagonal ROWISE
double c[] = { -200, -5, -25 };
double c0 = 64;
Program qp(numVariables, numAConstraints, A, b, relationships.begin(), fl, l, fu, u, D, c, c0);
// solve the program, using ET as the exact type
Solution s = CGAL::solve_quadratic_program(qp, ET());
std::cout << s;
return 0;
}
Related
I'm trying to transform a float3 array by using containers into a container of a specific structure. Code below:
#include <thrust/device_ptr.h>
#include <thrust/extrema.h>
#include <thrust/reduce.h>
#include <thrust/execution_policy.h>
#include <thrust/functional.h>
// Ouput structure for thrust::transform
struct cloud_point_index_idx {
unsigned int idx;
float3 cloud_point;
cloud_point_index_idx(unsigned int idx_, float3 cloud_point_) :
idx(idx_), cloud_point(cloud_point_) {}
bool operator < (const cloud_point_index_idx &p) const {
return (idx < p.idx);
}
};
// Functor for thrust::transform
struct point2voxelcentroid {
float3 leaf_size;
int min_x, min_y, min_z;
point2voxelcentroid(float3 leaf_size,int min_x, int min_y, int min_z) {
this->leaf_size = leaf_size;
this->min_x = min_x; this->min_y = min_y; this->min_z = min_z;
}
__host__ __device__
cloud_point_index_idx operator()(const float3 point) const {
int ijk0 = static_cast<int>(floor(point.x / leaf_size.x) -
static_cast<float>(min_x));
int ijk1 = static_cast<int>(floor(point.y / leaf_size.y) -
static_cast<float>(min_y));
int ijk2 = static_cast<int>(floor(point.z / leaf_size.z) -
static_cast<float>(min_z));
int voxel_idx = ijk0 + ijk1 + ijk2;
return cloud_point_index_idx(static_cast<unsigned int>(voxel_idx), point);
}
};
int main() { // Example
int num_points = 5;
float3 data[5] = {{1, 0, 2}, {2, 1, 3}, {1, 1, -5}, {-1, 3, -2}, {-5, -2, 0}}; // Set the data
int min_b_[3] = {-5, -2, -5};
float3 leaf_size = {0.5, 0.5, 0.5};
thrust::device_vector<float3> d_ptr(data, data + num_points); // Wrap it into a device_vector
thrust::device_vector<cloud_point_index_idx> voxel_idx_vector; // Output
voxel_idx_vector.reserve(num_points);
thrust::transform(
thrust::device,
d_ptr.begin(), d_ptr.end(),
voxel_idx_vector.begin(),
point2voxelcentroid(leaf_size, min_b_[0], min_b_[1], min_b_[2]));
thrust::host_vector<cloud_point_index_idx> indices; // Host vector to verify
indices.reserve(num_points);
thrust::copy(voxel_idx_vector.begin(), voxel_idx_vector.end(), indices.begin()); // Copy device to host
// Print out values
std::cout << "\n---\nAfter assignment\n";
for (int i = 0; i < num_points; i++) {
std::cout << "Voxel idx: " << indices[i].idx << ". Point: [" << indices[i].cloud_point.x << ", "
<< indices[i].cloud_point.y << ", " << indices[i].cloud_point.z << std::endl;
}
}
I inspected my functor values and they seem to correctly parse the data but when I print my host_vector I get really weird values, nothing related to what my output must be. I suspect I'm not initializing my output host/device vectors correctly. I tried other methods to initialize them but they all give me errors when compiling. I'm not sure what I'm doing wrong.
There are a couple of problems here, but the most severe is the use of reserve which doesn't actually allocate memory for a thrust container.
What you need to do is define a default constructor and explicitly allocate a size at instantiation. Something like this:
struct cloud_point_index_idx {
int idx;
float3 cloud_point;
cloud_point_index_idx()=default;
__host__ __device__
cloud_point_index_idx(unsigned int idx_, float3 cloud_point_) :
idx(idx_), cloud_point(cloud_point_) {}
__host__ __device__
bool operator < (const cloud_point_index_idx &p) const {
return (idx < p.idx);
}
};
(requires -std=c++11) will define a default constructor on both device and host which the container must call during initialization of each class instance.
This modification of your code works for me:
$ cat bodgey.cu
#include <thrust/device_vector.h>
#include <thrust/device_ptr.h>
#include <thrust/extrema.h>
#include <thrust/reduce.h>
#include <thrust/execution_policy.h>
#include <thrust/functional.h>
#include <iostream>
// Ouput structure for thrust::transform
struct cloud_point_index_idx {
int idx;
float3 cloud_point;
cloud_point_index_idx()=default;
__host__ __device__
cloud_point_index_idx(unsigned int idx_, float3 cloud_point_) :
idx(idx_), cloud_point(cloud_point_) {}
__host__ __device__
bool operator < (const cloud_point_index_idx &p) const {
return (idx < p.idx);
}
};
// Functor for thrust::transform
struct point2voxelcentroid {
float3 leaf_size;
int min_x, min_y, min_z;
point2voxelcentroid(float3 leaf_size,int min_x, int min_y, int min_z) {
this->leaf_size = leaf_size;
this->min_x = min_x; this->min_y = min_y; this->min_z = min_z;
}
__host__ __device__
cloud_point_index_idx operator()(const float3 point) const {
int ijk0 = static_cast<int>(floor(point.x / leaf_size.x) -
static_cast<float>(min_x));
int ijk1 = static_cast<int>(floor(point.y / leaf_size.y) -
static_cast<float>(min_y));
int ijk2 = static_cast<int>(floor(point.z / leaf_size.z) -
static_cast<float>(min_z));
int voxel_idx = ijk0 + ijk1 + ijk2;
return cloud_point_index_idx(voxel_idx, point);
}
};
int main() { // Example
int num_points = 5;
float3 data[5] = {{1, 0, 2}, {2, 1, 3}, {1, 1, -5}, {-1, 3, -2}, {-5, -2, 0}}; // Set the data
int min_b_[3] = {-5, -2, -5};
float3 leaf_size = {0.5, 0.5, 0.5};
thrust::device_vector<float3> d_ptr(data, data + num_points); // Wrap it into a device_vector
thrust::device_vector<cloud_point_index_idx> voxel_idx_vector(num_points); // Output
thrust::transform(
thrust::device,
d_ptr.begin(), d_ptr.end(),
voxel_idx_vector.begin(),
point2voxelcentroid(leaf_size, min_b_[0], min_b_[1], min_b_[2]));
thrust::host_vector<cloud_point_index_idx> indices(num_points); // Host vector to verify
thrust::copy(voxel_idx_vector.begin(), voxel_idx_vector.end(), indices.begin()); // Copy device to host
// Print out values
std::cout << "\n---\nAfter assignment\n";
for (int i = 0; i < num_points; i++) {
std::cout << "Voxel idx: " << indices[i].idx << ". Point: [" << indices[i].cloud_point.x << ", "
<< indices[i].cloud_point.y << ", " << indices[i].cloud_point.z << std::endl;
}
}
$ nvcc -std=c++11 -arch=sm_52 -o bodgey bodgey.cu
$ ./bodgey
---
After assignment
Voxel idx: 18. Point: [1, 0, 2
Voxel idx: 24. Point: [2, 1, 3
Voxel idx: 6. Point: [1, 1, -5
Voxel idx: 12. Point: [-1, 3, -2
Voxel idx: -2. Point: [-5, -2, 0
I am trying to port the Harmonic Oscillator tutorial from ODEINT to Eigen, so that I could use VectorXd for state vectors. I cannot, however, make it compile.
I've been following some questions, for instance this is the closest except that I don't use any stepper here.
This is the code:
#include <iostream>
#include <vector>
#include <Eigen/Dense>
#include <boost/numeric/odeint.hpp>
typedef Eigen::VectorXd state_type;
// was vector<double>
const double gam = 0.15;
/* The rhs of x' = f(x) defined as a class */
class harm_osc
{
public:
void operator() ( const state_type &x , state_type &dxdt , const double /* t */ )
{
dxdt(0) = x(1);
dxdt(1) = -x(0) - gam*x(1);
// dxdt[0] = x[1];
// dxdt[1] = -x[0] - gam*x[1];
}
};
/* The rhs of x' = f(x) */
void harmonic_oscillator(const state_type &x, state_type &dxdt, const double /* t */ )
{
dxdt(0) = x(1);
dxdt(1) = -x(0) - gam*x(1);
// dxdt[0] = x[1];
// dxdt[1] = -x[0] - gam*x[1];
}
void printer(const state_type &x , const double t)
{
// std::cout << t << "," << x[0] << "," << x[1] << std::endl;
std::cout << t << "," << x(0) << "," << x(1) << std::endl;
};
int main(int argc, const char * argv[])
{
state_type x(2);
x(0) = 1.0;
x(1) = 0.0;
// x[0] = 1.0;
// x[1] = 0.0;
std::cout << ">>>> FUNCTION" << std::endl;
// boost::numeric::odeint::integrate(harmonic_oscillator, x, 0.0, 10.0, 0.1, printer);
// boost::numeric::odeint::runge_kutta4<state_type, double, state_type, double, boost::numeric::odeint::vector_space_algebra> stepper();
boost::numeric::odeint::integrate<double, decltype(harmonic_oscillator), state_type, double, decltype(printer)>(harmonic_oscillator, x, 0.0, 10.0, 0.1, printer);
std::cout << ">>>> CLASS" << std::endl;
x(0) = 1.0;
x(1) = 0.0;
// x[0] = 1.0;
// x[1] = 0.0;
harm_osc ho;
boost::numeric::odeint::integrate<double, decltype(harmonic_oscillator), state_type, double, decltype(printer)>(ho, x, 0.0, 10.0, 0.1, printer);
return 0;
}
The compiler complains about No matching function for call to 'begin' in range_algebra.hpp from ODEINT in both class and function versions of integrate. As a matter of fact, Eigen matrices have no begin/end.
I've tried to play with the template parameters (as you see) with no avail.
Any hint?
Assertion failed using Eigen from repo
Using the latest Eigen from the repo (not the latest stable version), I can, as suggested, compile it and run. However, it fails an assertion in the integrate call tree:
Assertion failed: (index >= 0 && index < size()), function operator(), file eigen/include/eigen3/Eigen/src/Core/DenseCoeffsBase.h, line 427.
The call that fails is dxdt(0) = x(1); and subsequently in DenseCoeffsBase.h:
EIGEN_DEVICE_FUNC
EIGEN_STRONG_INLINE Scalar&
operator()(Index index)
{
eigen_assert(index >= 0 && index < size()); // <---- INDEX IS 0, SIZE IS 0
return coeffRef(index);
}
Is it possible that ODEINT is trying to default-construct a VectorXd? I followed the path to my ODE call and dxdt is actually NULL:
(lldb) e dxdt
(state_type) $1 = {
Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > = {
m_storage = {
m_data = 0x0000000000000000
m_rows = 0
}
}
}
What is worse is that when using resizeLike to allow resizing dxdt, in the second step (so the first real computation of integrate) I have a x with NULL values:
(lldb) e dxdt
(state_type) $0 = {
Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > = {
m_storage = {
m_data = 0x0000000000000000
m_rows = 0
}
}
}
(lldb) e x
(state_type) $1 = {
Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > = {
m_storage = {
m_data = 0x0000000000000000
m_rows = 0
}
}
}
I found that ODEINT actually works fine with Eigen... only it is not documented, as far as I can see.
Digging around ODEINT's code, I have found a promising eigen.hpp header deep in the external directory.
And lo and behold, it works flawlessly:
#include <fstream>
#include <iostream>
#include <vector>
#include <boost/numeric/odeint/external/eigen/eigen.hpp>
#include <Eigen/Eigenvalues>
#define FMT_HEADER_ONLY
#include "fmt/core.h"
#include "fmt/format.h"
#include "fmt/format-inl.h"
#include "fmt/printf.h"
using namespace std;
int main(int argc, char *argv[])
{
Eigen::VectorXd v;
v.resize(2);
typedef Eigen::VectorXd state_type;
const double gam = 0.15;
v(0) = 1.0;
v(1) = 1.1;
auto harmonic_oscillator = [&](const state_type &x, state_type &dxdt, const double t)
{
dxdt[0] = x[1];
dxdt[1] = -x[0] - gam*x[1];
};
auto printer = [&](const state_type &x, const double t)
{
fmt::print(out, "time: {} state: {}\n", t, x);
};
odeint::integrate(harmonic_oscillator, v, 0.0 , 10.0 , 0.01, printer);
return 0;
}
Hope it helps others.
I have designed a matrix class. Now I would like to initialize via list
Matrix3D m2{{1,2,3},{4,5,6},{7,8,9}};
instead of
Matrix3D m1(1,2,3,4,5,6,7,8,9);
I have added a static assert to force the size of the matrix which does not work.
How should I modify the constructor?
#include <iostream>
using namespace std;
class Matrix3D
{
int a11;
int a12;
int a13;
int a21;
int a22;
int a23;
int a31;
int a32;
int a33;
public:
Matrix3D(
int a11,
int a12,
int a13,
int a21,
int a22,
int a23,
int a31,
int a32,
int a33):
a11(a11),
a12(a12),
a13(a13),
a21(a21),
a22(a22),
a23(a23),
a31(a31),
a32(a32),
a33(a33)
{
}
Matrix3D(std::initializer_list<std::initializer_list<double>> listlist);
};
Matrix3D::Matrix3D(std::initializer_list<std::initializer_list<double>> listlist)
{
constexpr int rows = (int)(listlist.begin()).size();
constexpr int cols = (int)listlist.size();
static_assert(rows == 3, "");
static_assert(cols == 3, "");
a11=(listlist.begin()+0)[0];
a12=(listlist.begin()+0)[1];
a13=(listlist.begin()+0)[2];
a21=(listlist.begin()+1)[0];
a22=(listlist.begin()+1)[1];
a23=(listlist.begin()+1)[2];
a31=(listlist.begin()+2)[0];
a32=(listlist.begin()+2)[1];
a33=(listlist.begin()+2)[2];
}
int main() {
Matrix3D m1(1,2,3,4,5,6,7,8,9);
Matrix3D m2{{1,2,3},{4,5,6},{7,8,9}};
return 0;
}
I have added a static assert to force the size of the matrix which does not work.
Unfortunately for your situation std::initializer_list<Elem> is designed for a variable number of elements, which is why you cannot statically say anything about its size in the general case. The fact that its size member is constexpr is a red herring:
constexpr std::initializer_list<int> constant_expr = { 0, 2, 4, 6 };
// this is what a constexpr size member makes possible
static_assert( constant_expr.size() == 4 );
std::initializer_list<int> non_constant_expr = { 1, 3, 5 };
// this can't work
//static_assert( non_constant_expr.size() == 3 );
Function parameters are not constant expressions.
Instead, you would be better served by a type with a statically known number of elements. Array references can be suited to your needs:
class Matrix3D {
using index_type = int;
static constexpr index_type cols = 3;
using row_arg_type = int[cols];
public:
Matrix3D(row_arg_type const& row0, row_arg_type const& row1, row_arg_type const& row2);
// rest of class omitted
};
// number of rows and row width are statically enforced
Matrix3D m = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
Coliru demo
Below is the code I use to compute the intersection of two polyhedra with cgal. I know it's big but I did the best I could to minimize.
This code works for one example, but for the example included below, it crashes. The compilation runs fine but when I run the executable it crashes. When I run it from Haskell I get the error message "Access violation in generated code when reading xxx" (where xxx is an address).
The program firstly builds two polyhedra P1 and P2. There's no problem at this step. Then the problem occurs when the program reaches this line:
Nef_polyhedron nef1(P1);
I would appreciate any help to figure out what happens.
#include <vector>
#include <fstream>
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Polyhedron_incremental_builder_3.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>
#include <CGAL/Nef_polyhedron_3.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/convert_nef_polyhedron_to_polygon_mesh.h>
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef CGAL::Polyhedron_3<Kernel> Polyhedron;
typedef Polyhedron::HalfedgeDS HalfedgeDS;
typedef CGAL::Surface_mesh<Kernel::Point_3> Surface_mesh;
typedef CGAL::Nef_polyhedron_3<Kernel, CGAL::SNC_indexed_items> Nef_polyhedron;
// helper functions to convert arrays to vectors
std::vector<int> iarray2vector(int* array, size_t n){
std::vector<int> out;
for(size_t i=0; i<n; i++){
out.push_back(array[i]);
}
return out;
}
std::vector<double> darray2vector(double* array, size_t n){
std::vector<double> out;
for(size_t i=0; i<n; i++){
out.push_back(array[i]);
}
return out;
}
// A modifier creating a polyhedron with the incremental builder.
class polyhedron_builder : public CGAL::Modifier_base<HalfedgeDS> {
public:
std::vector<double> &coords;
std::vector<int> &faces;
std::vector<int> &facesizes;
polyhedron_builder(
std::vector<double> &_coords,
std::vector<int> &_faces,
std::vector<int> &_facesizes
) : coords(_coords), faces(_faces), facesizes(_facesizes) {}
void operator()( HalfedgeDS& hds) {
typedef typename HalfedgeDS::Vertex Vertex;
typedef typename Vertex::Point Point;
/* create a cgal incremental builder */
CGAL::Polyhedron_incremental_builder_3<HalfedgeDS> B( hds, true);
B.begin_surface( coords.size()/3, faces.size());
/* add the polyhedron vertices */
for(int i=0; i<(int)coords.size(); i+=3){
B.add_vertex( Point( coords[i+0], coords[i+1], coords[i+2] ) );
}
/* add the polyhedron faces */
int i=0;
for(int k=0; k<(int)facesizes.size(); k++){
int fs = facesizes[k];
B.begin_facet();
for(int j=0; j<fs; j++){
B.add_vertex_to_facet( faces[i+j] );
}
B.end_facet();
i += fs;
}
/* finish up the surface */
B.end_surface();
}
};
Polyhedron buildPolyhedron(
double* vertices,
size_t nvertices,
int* faces,
int* facesizes,
size_t nfaces)
{
/* calculate length of `faces`*/
size_t l = 0;
for(size_t i=0; i < nfaces; i++){
l += facesizes[i];
}
/* make vectors from arrays */
std::vector<double> vs = darray2vector(vertices, 3*nvertices);
std::vector<int> fs = iarray2vector(faces, l);
std::vector<int> fzs = iarray2vector(facesizes, nfaces);
/* build the polyhedron */
Polyhedron P;
polyhedron_builder builder(vs, fs, fzs);
P.delegate( builder );
/**/
return P;
}
void intersectPolyhedra(Polyhedron P1, Polyhedron P2){
/* convert polyhedra to nefs */
printf("make nef1\n");
Nef_polyhedron nef1(P1);
printf("make nef2\n");
Nef_polyhedron nef2(P2);
/* compute the intersection */
printf("make nefs intersection\n");
Nef_polyhedron nef = nef1*nef2;
/* surface mesh */
Surface_mesh smesh;
CGAL::convert_nef_polyhedron_to_polygon_mesh(nef, smesh);
/* write OFF file */
std::ofstream outfile;
outfile.open("intersection.off");
outfile << smesh;
outfile.close();
}
void intersectionTwoPolyhedra(
double* vertices1,
size_t nvertices1,
int* faces1,
int* facesizes1,
size_t nfaces1,
double* vertices2,
size_t nvertices2,
int* faces2,
int* facesizes2,
size_t nfaces2)
{
printf("build P1\n");
Polyhedron P1 = buildPolyhedron(vertices1, nvertices1, faces1, facesizes1, nfaces1);
printf("P1 is closed: %u\n", P1.is_closed());
std::cout << P1;
printf("build P2\n");
Polyhedron P2 = buildPolyhedron(vertices2, nvertices2, faces2, facesizes2, nfaces2);
printf("P2 is closed: %u\n", P2.is_closed());
std::cout << P2;
printf("run intersection\n");
intersectPolyhedra(P1, P2);
}
int main(){
double x = (1 + sqrt(5))/2;
double y = x - 1;
double vertices[60] = { -1, 1, 1,
0, y, x,
y, x, 0,
-y, x, 0,
0, y, -x,
0, -y, x,
1, -1, 1,
x, 0, y,
1, 1, 1,
1, 1, -1,
x, 0, -y,
y, -x, 0,
1, -1, -1,
-1, -1, 1,
-x, 0, y,
-1, 1, -1,
-x, 0, -y,
-1, -1, -1,
-y, -x, 0,
0, -y, -x };
int faces1[24] = { 3,1,7,9,
1,3,16,13,
9,19,16,3,
16,19,11,13,
1,13,11,7,
9,7,11,19 };
int faces2[24] = { 2,4,16,0,
2,7,12,4,
2,0,5,7,
4,12,18,16,
0,16,18,5,
7,5,18,12 };
int facesizes[6] = { 4, 4, 4, 4, 4, 4};
intersectionTwoPolyhedra(
vertices,
20,
faces1,
facesizes,
6,
vertices,
20,
faces2,
facesizes,
6
);
return 0;
}
Both calls P1.is_valid() and P2.is_valid() return false. So it seems your input polyhedra are not valid.
I suggest that you try to use the more user friendly polygon_soup_to_polygon_mesh() function to create your polyhedra.
Also you might want to use directly Surface_mesh and the Boolean operations available in the polygon mesh processing package. See here.
This answer is helpful, but I would like to know how to pass multiple parameters of different types to the ODE model, perhaps in a struct. For my immediate use case, I need to be able to pass one std::array<double, 6>, two std::vector<std::vector<double>> and two two double scalars for a total of four parameters to be passed. In the linked example, as well as in harmonic_oscillator.cpp, there is only a single double passed parameter. Thanks.
Here's an example of the struct I would need passed to the ODE force model and used within the rate equations.
struct T
{
std::array<double, 6> IC;
double S;
double M;
std::vector<std::vector<double>> C;
std::vector<std::vector<double>> WT;
};
I believe I've come up with a struct solution that works, but am not sure if it has any variable/memory scope no-no's. Here's an example:
#include <vector>
#include <boost/numeric/odeint.hpp>
// define structure
struct T
{
std::array<double, 6> IC;
double S;
};
// force model
class harm_osc
{
struct T T1;
public:
harm_osc(struct T G) : T1(G) {}
void operator() ( const std::vector< double > &x , std::vector< double > &dxdt , const double /* t */ )
{
dxdt[0] = x[1];
dxdt[1] = -x[0] - T1.IC[0]*x[1] + T1.S;
}
};
// print integrated state solution
void write_solution( const std::vector< double > &x , const double t )
{
printf("%-6.2f %-6.2f %-6.2f\n", t, x[0], x[1]);
}
// problem setup
int main()
{
std::vector< double > x(2);
x[0] = 1.0;
x[1] = 0.0;
struct T T2;
T2.IC = {0.15, 0.15, 0.15, 0.15, 0.15, 0.15};
T2.S = 0.0;
harm_osc ho(T2);
boost::numeric::odeint::integrate(ho, x, 0.0, 10.0, 0.1, write_solution);
}