function IBuilder::buildEngineWithConfig() returns null - deep-learning

I am using tensorRT to build a small model as below:
#include "NvInfer.h"
#include "cuda_runtime_api.h"
#include <fstream>
#include <map>
#include <chrono>
#include <iostream>
#include "include/Utils.h"
#include <memory>
#include <vector>
#include <cassert>
#include "src/InferDeleter.cpp"
using namespace std;
using namespace nvinfer1;
class MyLogger : public ILogger {
void log(Severity severity, const char *msg) override {
if (severity != Severity::kINFO) {
cout << msg << endl;
}
}
} gLogger;
int main() {
//load weights
map<string, Weights> mWeightMap = Utils::getInstance().loadWeights("Weights/mnistapi.wts");
//a few configuration parameters
const char *INPUT_BLOB_NAME = "input";
const char *OUTPUT_BLOB_NAME = "output";
DataType dataType = nvinfer1::DataType::kFLOAT;
int INPUT_H = 28, INPUT_W = 28;
int batchSize = 1;
//define the network
IBuilder *builder = createInferBuilder(gLogger);
INetworkDefinition *network = builder->createNetworkV2(0U);
// Create input tensor of shape { 1, 1, 28, 28 }
ITensor *data = network->addInput(
INPUT_BLOB_NAME, DataType::kFLOAT, Dims3{1, INPUT_H, INPUT_W});
// Create scale layer with default power/shift and specified scale parameter.
const float scaleParam = 0.0125f;
const Weights power{DataType::kFLOAT, nullptr, 0};
const Weights shift{DataType::kFLOAT, nullptr, 0};
const Weights scale{DataType::kFLOAT, &scaleParam, 1};
IScaleLayer *scale_1 = network->addScale(*data, ScaleMode::kUNIFORM, shift, scale, power);
// Add convolution layer with 20 outputs and a 5x5 filter.
IConvolutionLayer *conv1 = network->addConvolutionNd(
*scale_1->getOutput(0), 20, Dims{2, {5, 5}, {}}, mWeightMap["conv1filter"], mWeightMap["conv1bias"]);
conv1->setStride(DimsHW{1, 1});
// Add max pooling layer with stride of 2x2 and kernel size of 2x2.
IPoolingLayer *pool1 = network->addPoolingNd(*conv1->getOutput(0), PoolingType::kMAX, Dims{2, {2, 2}, {}});
pool1->setStride(DimsHW{2, 2});
// Add second convolution layer with 50 outputs and a 5x5 filter.
IConvolutionLayer *conv2 = network->addConvolutionNd(
*pool1->getOutput(0), 50, Dims{2, {5, 5}, {}}, mWeightMap["conv2filter"], mWeightMap["conv2bias"]);
conv2->setStride(DimsHW{1, 1});
// Add second max pooling layer with stride of 2x2 and kernel size of 2x3>
IPoolingLayer *pool2 = network->addPoolingNd(*conv2->getOutput(0), PoolingType::kMAX, Dims{2, {2, 2}, {}});
pool2->setStride(DimsHW{2, 2});
// Add fully connected layer with 500 outputs.
IFullyConnectedLayer *ip1
= network->addFullyConnected(*pool2->getOutput(0), 500, mWeightMap["ip1filter"], mWeightMap["ip1bias"]);
// Add activation layer using the ReLU algorithm.
IActivationLayer *relu1 = network->addActivation(*ip1->getOutput(0), ActivationType::kRELU);
// Add second fully connected layer with 20 outputs.
IFullyConnectedLayer *ip2 = network->addFullyConnected(
*relu1->getOutput(0), 10, mWeightMap["ip2filter"], mWeightMap["ip2bias"]);
// Add softmax layer to determine the probability.
ISoftMaxLayer *prob = network->addSoftMax(*ip2->getOutput(0));
prob->getOutput(0)->setName(OUTPUT_BLOB_NAME);
network->markOutput(*prob->getOutput(0));
//build engine
IBuilderConfig *builderConfig = builder->createBuilderConfig();
builder->setMaxBatchSize(batchSize);
builderConfig->setMaxWorkspaceSize(1<<24);
//engine null
ICudaEngine *engine = builder->buildEngineWithConfig(*network, *builderConfig);
//later uses of engine.
return 0;
}
However, the function builder->buildEngineWithConfig(*network, *builderConfig) returns nullptr. I tried to change maxWorkSpace to other values but it still does not work. I also visited this post but nothing help. Anyone points out the causes of the problem. Thank you!

After a few days of rolling over this problem. I have found that if layers in the model does not match the weight passed in, there is no error will appear but you can not create an TensorRT engine to do later tasks. Therefore, the best way to do in this situation is carefully checking layer by layer and the .wts file.

Related

Thrust: selectively copy based on another vector

I'd like to use a set of thrust operations to selectively copy the elements of one vector A into a new vector B based on a predicate on elements in a third vector C.
Here's an example case: I want to copy elements (in order) from A when the corresponding element in B is 1 to C and don't if it is 0. I want |C| < |A| if there are 0s in B. We can pre-determine the size of C by a reduction on B. e.g:
A = [2, 3, 6, 0, 11]
B = [1, 0, 1, 1, 0]
C = [2, 6, 0]
Any help is greatly appreciated
This algorithm is known as stream compaction. It is implemented in thrust::copy_if.
The following example is taken from the Thrust documentation.
#include <thrust/copy.h>
...
struct is_even
{
__host__ __device__
bool operator()(const int x)
{
return (x % 2) == 0;
}
};
...
int N = 6;
int data[N] = { 0, 1, 2, 3, 4, 5};
int stencil[N] = {-2, 0, -1, 0, 1, 2};
int result[4];
thrust::copy_if(data, data + N, stencil, result, is_even());
// data remains = { 0, 1, 2, 3, 4, 5};
// stencil remains = {-2, 0, -1, 0, 1, 2};
// result is now { 0, 1, 3, 5}
Although Abator had given the right function to use. Let me try a complete example.
//~~~START:Wed, 06-Oct-2021, 21:41:22 IST
//~~~Author:Rajesh Pandian M | mrprajesh.co.in
//~~CompiledWith: nvcc a.cu -std=c++14 --expt-extended-lambda
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/copy.h>
#include <stdio.h>
int main(void) {
const int N=5;
int A[]={2, 3, 6, 0, 11}; //Data
int B[]={1, 0, 1, 1, 0 }; //Stencil
thrust::device_vector<int> dA(A, A + N);
thrust::device_vector<int> dB(B, B + N);
// Allocates memory based on #number of 1's
thrust::device_vector<int> dC(thrust::count(B, B+N,1));
//Condition on the stencil elements. If 1 is seen copy, else do not!
thrust::copy_if( dA.begin()
,dA.end()
,dB.begin()
,dC.begin()
,[] __host__ __device__ (const int& x){
return 1 == x;
});
//Prints
thrust::for_each(dC.begin(), dC.end(),
[] __host__ __device__(const int& x){ printf("%d ",x);});
return 0;
}

C++17 parallel algorithms on containers with object data

I am attempting to use C++17 parallel algorithms with containers holding non-fundamental types as illustrated in the minimal example below, compiled using GCC9.2.1/Intel TBB on Ubuntu 19.10. The sequential policy is OK, but compilation fails with par since the lambda is expected to accept double as the second argument. The issue persists on icc 19.0.1.
My question is if the code is valid or if this issue is simply because of the early development stage of the parallel implementation?
#include <numeric>
#include <algorithm>
#include <execution>
#include <vector>
struct Data {
double radius;
};
int main() {
double sum;
std::vector<double> v1;
std::vector<Data> v2;
// ok
sum = std::reduce(std::execution::par, v1.begin(), v1.end(), 0.0, [](double sum, auto i) { return sum + i; });
// ok
sum = std::reduce(std::execution::seq, v2.begin(), v2.end(), 0.0, [](double sum, const Data &i) { return sum + i.radius; });
// compile error
sum = std::reduce(std::execution::par, v2.begin(), v2.end(), 0.0, [](double sum, const Data &i) { return sum + i.radius; });
}
BinaryOp for std::reduce should be commutative, below both operations should be supported:
double + Data // your lambda supports only this
Data + double // this can be performed only by adding some conversions
If you want to make conversion double->Data you should add proper constructor. For conversion Data->double you should add proper conversion operator:
struct Data {
double radius;
// double -> Data
Data (double d) : radius(d) {}
// Data -> double
operator double() const {
return radius;
}
};
Live demo

Cuda Thrust - max vec3

When i want to perform a reduction on an array of float i usually do the following :
float res = *thrust::max_element(thrust::device,
thrust::device_ptr<float>(dDensities),
thrust::device_ptr<float>(dDensities+numParticles)
);
However what i would like to do now is pretty much the same thing on a vec3 (the glm library type) array :
float res = *thrust::max_element(thrust::device,
thrust::device_ptr<glm::vec3>(dDensities),
thrust::device_ptr<glm::vec3>(dDensities+numParticles)
);
As you can see, this has no sense because the '<' operator is not defined on. But i would like to get the maximum vec3 based on his length :
len = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
Is that possible ?
Yes, its possible. You may want to read the thrust quickstart guide if you're not already familiar with it.
If you review the thrust extrema documentation, you'll note that thrust::max_element comes in several different varieties (as do most thrust algorithms). One of these accepts a binary comparison functor. We can define a comparison functor which will do what you want.
Here's a trivial worked example:
$ cat t134.cu
#include <thrust/extrema.h>
#include <thrust/device_ptr.h>
#include <glm/glm.hpp>
#include <iostream>
struct comp
{
template <typename T>
__host__ __device__
bool operator()(T &t1, T &t2){
return ((t1.x*t1.x+t1.y*t1.y+t1.z*t1.z) < (t2.x*t2.x+t2.y*t2.y+t2.z*t2.z));
}
};
int main(){
int numParticles = 3;
glm::vec3 d[numParticles];
d[0].x = 0; d[0].y = 0; d[0].z = 0;
d[1].x = 2; d[1].y = 2; d[1].z = 2;
d[2].x = 1; d[2].y = 1; d[2].z = 1;
glm::vec3 *dDensities;
cudaMalloc(&dDensities, numParticles*sizeof(glm::vec3));
cudaMemcpy(dDensities, d, numParticles*sizeof(glm::vec3), cudaMemcpyHostToDevice);
glm::vec3 res = *thrust::max_element(thrust::device,
thrust::device_ptr<glm::vec3>(dDensities),
thrust::device_ptr<glm::vec3>(dDensities+numParticles),
comp()
);
std::cout << "max element x: " << res.x << " y: " << res.y << " z: " << res.z << std::endl;
}
$ nvcc -arch=sm_61 -o t134 t134.cu
$ ./t134
max element x: 2 y: 2 z: 2
$

LLVM MCJIT / SEH Exception handling

Lately, I've been attempting to get SEH exception handling to work in LLVM (3.8.1) together with MCJIT. So far without any luck.
From what I understand from the website ( http://llvm.org/docs/ExceptionHandling.html ), this is pretty much how this should be implemented. Compiling a minimal piece of code with clang gives pretty much the same LLVM IR code. However, when I try it, the program crashes with a nasty Stack cookie instrumentation code detected a stack-based buffer overrun..
To illustrate what I've been attempting to do, I've created a minimum test case (I apologise for the amount of code...):
#include <string>
#include <iostream>
#include <exception>
#pragma warning(push)
#pragma warning(disable: 4267)
#pragma warning(disable: 4244)
#pragma warning(disable: 4800)
#pragma warning(disable: 4996)
#pragma warning(disable: 4141)
#pragma warning(disable: 4146)
#pragma warning(disable: 4624)
#pragma warning(disable: 4291)
#define DONT_GET_PLUGIN_LOADER_OPTION
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Triple.h"
#include "llvm/PassRegistry.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#pragma warning(pop)
static void test()
{
// You can use this to see that function calls work fine.
// std::cout << "Foo!" << std::endl;
throw std::exception("Something we should try to catch.");
}
int main()
{
// Initialize LLVM
std::cout << "Initializing LLVM." << std::endl;
llvm::InitializeNativeTarget();
llvm::InitializeAllTargetMCs();
llvm::InitializeNativeTargetAsmPrinter();
llvm::InitializeNativeTargetAsmParser();
llvm::PassRegistry *Registry = llvm::PassRegistry::getPassRegistry();
llvm::initializeCore(*Registry);
llvm::initializeScalarOpts(*Registry);
llvm::initializeObjCARCOpts(*Registry);
llvm::initializeVectorization(*Registry);
llvm::initializeIPO(*Registry);
llvm::initializeAnalysis(*Registry);
llvm::initializeTransformUtils(*Registry);
llvm::initializeInstCombine(*Registry);
llvm::initializeInstrumentation(*Registry);
llvm::initializeTarget(*Registry);
// For codegen passes, only passes that do IR to IR transformation are
// supported.
llvm::initializeCodeGenPreparePass(*Registry);
llvm::initializeAtomicExpandPass(*Registry);
llvm::initializeRewriteSymbolsPass(*Registry);
llvm::initializeWinEHPreparePass(*Registry);
llvm::initializeDwarfEHPreparePass(*Registry);
llvm::initializeSjLjEHPreparePass(*Registry);
llvm::StringRef MCPU = llvm::sys::getHostCPUName();
std::string MTrip = llvm::sys::getProcessTriple();
static llvm::StringMap<bool, llvm::MallocAllocator> features;
llvm::sys::getHostCPUFeatures(features);
// Initialize module & context:
auto context = std::unique_ptr<llvm::LLVMContext>(new llvm::LLVMContext());
auto module = std::unique_ptr<llvm::Module>(new llvm::Module("native", *context));
// Create 'main' method:
llvm::Type* returnType = llvm::Type::getInt32Ty(*context);
std::vector<llvm::Type*> arguments;
// MCJIT only supports main(int, char**)
arguments.push_back(llvm::Type::getInt32Ty(*context));
arguments.push_back(llvm::Type::getInt8PtrTy(*context)->getPointerTo());
llvm::Function *fcn = llvm::cast<llvm::Function>(module->getOrInsertFunction("main", llvm::FunctionType::get(returnType, arguments, false)));
// Generate exception handler info for main:
llvm::AttrBuilder argBuilder;
argBuilder.addAttribute(llvm::Attribute::UWTable);
argBuilder.addAttribute("stack-protector-buffer-size", "8");
fcn->addAttributes(llvm::AttributeSet::FunctionIndex, llvm::AttributeSet::get(*context, llvm::AttributeSet::FunctionIndex, argBuilder));
// Exception handling requires a personality function. We want to use the SEH personality handler
llvm::Function *personalityHandler = llvm::cast<llvm::Function>(module->getOrInsertFunction("__CxxFrameHandler3", llvm::FunctionType::get(llvm::Type::getInt32Ty(*context), true)));
auto personalityPtr = llvm::ConstantExpr::getBitCast(personalityHandler, llvm::Type::getInt8PtrTy(*context));
fcn->setPersonalityFn(personalityPtr);
// Create some code. Basically we want to invoke our 'test' method
auto block = llvm::BasicBlock::Create(*context, "code", fcn);
llvm::IRBuilder<> builder(block);
// all other cases might throw an exception
auto continueBlock = llvm::BasicBlock::Create(*context, "invoke.cont", fcn);
auto catchDispatch = llvm::BasicBlock::Create(*context, "catch.dispatch", fcn);
// Register 'test' as an external function:
const void* testFunctionPtr = &test;
auto testFunctionType = llvm::FunctionType::get(builder.getVoidTy(), false);
auto testFunction = llvm::Function::Create(testFunctionType, llvm::Function::ExternalLinkage, "test", module.get());
// %call = invoke i32 #"test"() to label %invoke.cont unwind label %catch.dispatch
auto call = builder.CreateInvoke(testFunction, continueBlock, catchDispatch);
// return [ 0 from ok, 1 from catch handler ]
builder.SetInsertPoint(continueBlock);
auto phi = builder.CreatePHI(builder.getInt32Ty(), 2, "result");
phi->addIncoming(builder.getInt32(0), block);
builder.CreateRet(phi);
// Create exception handler:
// Create default catch block. Basically handles the exception and returns '1'.
builder.SetInsertPoint(catchDispatch);
auto parentPad = llvm::ConstantTokenNone::get(*context);
// %0 = catchswitch within none [label %catch] unwind to caller
auto catchSwitch = builder.CreateCatchSwitch(parentPad, nullptr, 1);
auto catchBlock = llvm::BasicBlock::Create(*context, "catch", fcn);
builder.SetInsertPoint(catchBlock);
catchSwitch->addHandler(catchBlock);
// MSVC code:
// %1 = catchpad within %0 [i8* null, i32 64, i8* null] == "catch all"
llvm::Value *nullPtr = llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(*context));
auto catchPad = builder.CreateCatchPad(catchSwitch, { nullPtr, builder.getInt32(0x40), nullPtr });
// catchret from %1 to label %return
auto const1 = builder.getInt32(1);
builder.CreateCatchRet(catchPad, continueBlock);
// set 1 for the catch handler
phi->addIncoming(builder.getInt32(1), catchBlock);
// *DONE* building the code.
// Dump the LLVM IR:
module->dump();
// Let's JIT the code:
std::string error;
auto trip = llvm::Triple::normalize(MTrip);
llvm::Triple triple(trip);
const llvm::Target *target = llvm::TargetRegistry::lookupTarget("x86-64", triple, error);
if (!target)
{
throw error.c_str();
}
llvm::TargetOptions Options;
std::unique_ptr<llvm::TargetMachine> targetMachine(
target->createTargetMachine(trip, MCPU, "", Options, llvm::Reloc::Default, llvm::CodeModel::Default, llvm::CodeGenOpt::Aggressive));
if (!targetMachine.get())
{
throw "Could not allocate target machine!";
}
// Create the target machine; set the module data layout to the correct values.
auto DL = targetMachine->createDataLayout();
module->setDataLayout(DL);
module->setTargetTriple(trip);
// Pass manager builder:
llvm::PassManagerBuilder pmbuilder;
pmbuilder.OptLevel = 3;
pmbuilder.BBVectorize = false;
pmbuilder.SLPVectorize = true;
pmbuilder.LoopVectorize = true;
pmbuilder.Inliner = llvm::createFunctionInliningPass(3, 2);
llvm::TargetLibraryInfoImpl *TLI = new llvm::TargetLibraryInfoImpl(triple);
pmbuilder.LibraryInfo = TLI;
// Generate pass managers:
// 1. Function pass manager:
llvm::legacy::FunctionPassManager FPM(module.get());
pmbuilder.populateFunctionPassManager(FPM);
// 2. Module pass manager:
llvm::legacy::PassManager PM;
PM.add(llvm::createTargetTransformInfoWrapperPass(targetMachine->getTargetIRAnalysis()));
pmbuilder.populateModulePassManager(PM);
// 3. Execute passes:
// - Per-function passes:
FPM.doInitialization();
for (llvm::Module::iterator I = module->begin(), E = module->end(); I != E; ++I)
{
if (!I->isDeclaration())
{
FPM.run(*I);
}
}
FPM.doFinalization();
// - Per-module passes:
PM.run(*module);
// All done, *RUN*.
llvm::EngineBuilder engineBuilder(std::move(module));
engineBuilder.setEngineKind(llvm::EngineKind::JIT);
engineBuilder.setMCPU(MCPU);
engineBuilder.setMArch("x86-64");
engineBuilder.setUseOrcMCJITReplacement(false);
engineBuilder.setOptLevel(llvm::CodeGenOpt::None);
llvm::ExecutionEngine* engine = engineBuilder.create();
// Register global 'test' function:
engine->addGlobalMapping(testFunction, const_cast<void*>(testFunctionPtr)); // Yuck...
// Finalize
engine->finalizeObject();
// Invoke:
std::vector<llvm::GenericValue> args(2);
args[0].IntVal = llvm::APInt(32, static_cast<uint64_t>(0), true);
args[1].PointerVal = nullptr;
llvm::GenericValue gv = engine->runFunction(fcn, args);
auto result = int(gv.IntVal.getSExtValue());
std::cout << "Result after execution: " << result << std::endl;
std::string s;
std::getline(std::cin, s);
}
This produces the following IR code:
; ModuleID = 'native'
; Function Attrs: uwtable
define i32 #main(i32, i8**) #0 personality i8* bitcast (i32 (...)* #__CxxFrameHandler3 to i8*) {
code:
invoke void #test()
to label %invoke.cont unwind label %catch.dispatch
invoke.cont: ; preds = %catch, %code
%result = phi i32 [ 0, %code ], [ 1, %catch ]
ret i32 %result
catch.dispatch: ; preds = %code
%2 = catchswitch within none [label %catch] unwind to caller
catch: ; preds = %catch.dispatch
%3 = catchpad within %2 [i8* null, i32 64, i8* null]
catchret from %3 to label %invoke.cont
}
declare i32 #__CxxFrameHandler3(...)
declare void #test()
attributes #0 = { uwtable "stack-protector-buffer-size"="8" }
Q: What am I missing, why doesn't this work and how to fix it?
After posting this issue on the llvm developer list, I got a friendly reply explaining how this issue is related to a known bug: https://llvm.org/bugs/show_bug.cgi?id=24233 .
Basically what happens is that LLVM doesn't implement the code that Windows (more specifically: SEH and debugging) requires for handling stack frames. I'm by no means an expert on this subject, but until this is implemented, SEH won't know what to do, which means C++ exception basically won't work.
An obvious workaround is of course to pass the object as a pointer during the function call and perform an if-then-else. That way, exceptions are avoided. However, this is pretty nasty and will probably give a serious performance penalty. Also, this makes the flow in the compiler as well as the generated program much more complicated. In other words: let's just say I'd rather not.
I'll leave the question open; if someone happens to find a hack or figure out a workaround, I'll gladly accept it.

odeint streaming observer and related questions

I have a system of 4 coupled equations to solve and a parameter Gamma[i] to iterate over. Since I am quite new to C++, my code is a very rudimentary. If it looks sophisticated and elegant in certain parts, it is only because I have adapted code from the author of odeint. :)
This question is related to (http://stackoverflow.com/questions/12060111/using-odeint-function-definition/12066958#comment16253600_12066958) but not exactly the same. Please do not delete this. :(
Questions have been inserted between the lines of code.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <boost/numeric/odeint.hpp>
#include <cmath>
#include <vector>
#include <fstream>
#include <iomanip>
using namespace std;
using namespace boost::numeric::odeint;
class NLI_class {
private:
double gamma;
public:
NLI_class (double r) : gamma(r) {}
void operator()( vector<double> &u , vector<double> &du , double z ) {
du[0] = u[0]*u[1]*cos(u[3]); //u1
du[1] = -u[0]*u[0]*cos(u[3]); //u2
du[2] = gamma * (2/(u[0]*u[0]) - 1/(u[1]*u[1])); //theta
du[3] = gamma * (1.0/(u[0]*u[0])); //phi1
du[4] = gamma * (1.0/(u[1]*u[1])); //phi2;
}
};
Question #1:
In my original program, I had something like this to pipe the output to a csv file:
inline void save(vector<double>& v, string filename)
{
ofstream output(filename);
for(int i=0;i<v.size();++i){
output << setprecision(64) << v[i] << endl;
}
}
How do I adapt streaming_observer to do what my save() does? Basically, I want to generate .csv files for each iteration i. At this point, I am doing it the ugly way, i.e compiling everything, opening a windows command prompt and then piping the exe output to a text file. This generates one big file with all iterations thrown in there.
This becomes very painful to analyze for a large number of iterations.
struct streaming_observer {
std::ostream &m_out;
streaming_observer( std::ostream &out ) : m_out( out ) {}
void operator()( const vector<double> &x , double t ) const
{
m_out << t;
for( size_t i=0 ; i < x.size() ; ++i )
m_out << "\t" << x[i];
m_out << "\n";
}
};
int main(){
vector<double> x( 5 );
vector<double> Gamma;
vector<double>delta;
const double pi=acos(-1.0);
short delta_n=5;
const double delta_step=(2*pi)/delta_n;
const double dz = 0.01;
const double zeta = 3.0;
const double theta_initial=0.0;
const double u20=tanh(zeta);
const double u10=sqrt(1.0-(u20*u20));
double d=0.0;
double G=0.0;
for(int i=0;i<=delta_n;i++){
//When i=0, the d=0.0 and G=0.0 are pushed into the vector.
delta.push_back(d);
Gamma.push_back(G);
// Compute delta and Gamma
d=d+delta_step;
G=-u10*u10*u20*sin(theta_initial+d);
}
save(delta,"delta.csv");
save(Gamma,"Gamma.csv");
Question#2:
The results I get here do not agree with what I get with what I get using a simple explicit Euler method. Hence, I would like to see the RK4 coefficients (preferably dump them to a file) or the intermediate steps. How can I get this information?
//Numeric Integration
for (unsigned i = 0; i < Gamma.size(); ++i) {
x[0] = u10;
x[1] = u20;
x[2] = 0.0;
x[3] = 0.0;
x[4] = 0.0;
NLI_class nli_obj(Gamma[i]);
integrate_const( runge_kutta4< vector<double > >(), nli_obj, x , 0.0 , 3.0 , dz,streaming_observer( std::cout ) );
}
}
Thank you for all those who helped!
Edit:
Is there some way to get a running error estimate? Note that u[0]*u[0]+u[1]*u[1]=1 at all times.
Question #1 :
I do not understand exactly what kind of output you need. But if you want to write the result after each iteration you can implement an output observer like this:
struct output_observer
{
string filename_;
size_t count_;
output_observer( const string &filename ) : filename_( filename ) , count_( 0 ) { }
void operator()( const state_type &x , time_type dt )
{
char fn[512] = "";
sprintf( fn , "%s_%04lu.csv" , filename_.c_str() , count_ );
ofstream fout( fn );
for( size_t i=0 ; i<x.size() ; ++i ) fout << x[i] << "\n";
++count_;
}
};
You can apply this observer simply by
integrate_const( runge_kutta4< vector<double > >() , nli_obj , x ,
0.0 , 3.0 , dz , output_observer( "filename" ) );
Is this the desired functionality?
Question #2 :
It is not possible to see the intermediate e steps of runge_kutta4. The coefficients are the standard ones for the classical Runge-Kutta method: http://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods
Question #3 :
odeint has several error steppers, which estimate the error made during one step. You can use for example the Runge_Kutta Cash Karp algorithm;
runge_kutta_cash_karp54< state_type > rk;
state_type xerr;
rk.do_step( nli_obj , x , t , xerr );
which makes ONE step and estimates the error and writes the error result in xerr.