I'm currently working with CUSPARSE. I'm having trouble because I don't know how to print a complex number. For example, when I write:
cuComplex a;
a.x=1.2;
a.y=2.2;
How do I print the varable a?
I've tried :
cout<< a;
but it doesn't work.
You will need to overload the << operator to take in cuComplex and cuDoubleComplex data types.
std::ostream& operator<<(std::ostream& strm, const cuComplex& in)
{
char sgn[2] = "+-"
strm << in.x << sgn[in.y < 0] << " i"<< std::abs(in.y);
return strm;
}
You can do the same for cuDoubleComplex
The data in std::complex is identical to the corresponding data in a cuComplex, i.e. you can reinterpret_cast pointers (and therefore arrays, too) of one type to the other – it works in practise and is, I think, actually guaranteed by C++11, you can test it like this:
namespace check_stdComplexdouble_to_cuDoubleComplex_binary_compatibility{
using std::complex;
const complex<double> testarr[] = { complex<double>(0.,.5)
, complex<double>(1.,1.5) };
const cuDoubleComplex* cucomplexd
= reinterpret_cast<const cuDoubleComplex*>(testarr);
auto tester() -> bool {
assert( cuCreal(cucomplexd[0])==0. && cuCimag(cucomplexd[0])==.5
&& cuCreal(cucomplexd[1])==1. && cuCimag(cucomplexd[1])==1.5 );
return true;
}
const bool ok = tester();
bool good(){return ok;}
};
If you call a CUBLAS function that's supposed to read/write from/to an std::complex<float>, you can just give it a reinterpret_casted pointer, e.g.
std::complex<double> result;
xhandle->cublasstat = yhandle->cublasstat
= cublasZdotc( *xhandle->cublashandle
, xhandle->vect_dimension
, xhandle->vector, 1
, yhandle->vector, 1
, reinterpret_cast<cuDoubleComplex*>(&result) );
Related
I have a .csv file:
lp;imie;nazwisko;ulica;numer;kod;miejscowosc;telefon;email;data_ur
1;Jan;Kowalski;ul. Nowa;1a;11-234;Budry;123-123-456;jan#go.xxx;1980.05.13
2;Jerzy;Nowak;ul. Konopnicka;13a/3;00-900;Lichowice;(55)333-44-55;jer#wu.to;1990.03.23
And I need to read this in C. I have some code, but only for the connection.
Hopefully this would get you started
See it live on http://ideone.com/l23He (using stdin)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ";");
tok && *tok;
tok = strtok(NULL, ";\n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE* stream = fopen("input", "r");
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp = strdup(line);
printf("Field 3 would be %s\n", getfield(tmp, 3));
// NOTE strtok clobbers tmp
free(tmp);
}
}
Output:
Field 3 would be nazwisko
Field 3 would be Kowalski
Field 3 would be Nowak
The following code is in plain c language and handles blank spaces.
It only allocates memory once, so one free() is needed, for each processed line.
http://ideone.com/mSCgPM
/* Tiny CSV Reader */
/* Copyright (C) 2015, Deligiannidis Konstantinos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://w...content-available-to-author-only...u.org/licenses/>. */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/* For more that 100 columns or lines (when delimiter = \n), minor modifications are needed. */
int getcols( const char * const line, const char * const delim, char ***out_storage )
{
const char *start_ptr, *end_ptr, *iter;
char **out;
int i; //For "for" loops in the old c style.
int tokens_found = 1, delim_size, line_size; //Calculate "line_size" indirectly, without strlen() call.
int start_idx[100], end_idx[100]; //Store the indexes of tokens. Example "Power;": loc('P')=1, loc(';')=6
//Change 100 with MAX_TOKENS or use malloc() for more than 100 tokens. Example: "b1;b2;b3;...;b200"
if ( *out_storage != NULL ) return -4; //This SHOULD be NULL: Not Already Allocated
if ( !line || !delim ) return -1; //NULL pointers Rejected Here
if ( (delim_size = strlen( delim )) == 0 ) return -2; //Delimiter not provided
start_ptr = line; //Start visiting input. We will distinguish tokens in a single pass, for good performance.
//Then we are allocating one unified memory region & doing one memory copy.
while ( ( end_ptr = strstr( start_ptr, delim ) ) ) {
start_idx[ tokens_found -1 ] = start_ptr - line; //Store the Index of current token
end_idx[ tokens_found - 1 ] = end_ptr - line; //Store Index of first character that will be replaced with
//'\0'. Example: "arg1||arg2||end" -> "arg1\0|arg2\0|end"
tokens_found++; //Accumulate the count of tokens.
start_ptr = end_ptr + delim_size; //Set pointer to the next c-string within the line
}
for ( iter = start_ptr; (*iter!='\0') ; iter++ );
start_idx[ tokens_found -1 ] = start_ptr - line; //Store the Index of current token: of last token here.
end_idx[ tokens_found -1 ] = iter - line; //and the last element that will be replaced with \0
line_size = iter - line; //Saving CPU cycles: Indirectly Count the size of *line without using strlen();
int size_ptr_region = (1 + tokens_found)*sizeof( char* ); //The size to store pointers to c-strings + 1 (*NULL).
out = (char**) malloc( size_ptr_region + ( line_size + 1 ) + 5 ); //Fit everything there...it is all memory.
//It reserves a contiguous space for both (char**) pointers AND string region. 5 Bytes for "Out of Range" tests.
*out_storage = out; //Update the char** pointer of the caller function.
//"Out of Range" TEST. Verify that the extra reserved characters will not be changed. Assign Some Values.
//char *extra_chars = (char*) out + size_ptr_region + ( line_size + 1 );
//extra_chars[0] = 1; extra_chars[1] = 2; extra_chars[2] = 3; extra_chars[3] = 4; extra_chars[4] = 5;
for ( i = 0; i < tokens_found; i++ ) //Assign adresses first part of the allocated memory pointers that point to
out[ i ] = (char*) out + size_ptr_region + start_idx[ i ]; //the second part of the memory, reserved for Data.
out[ tokens_found ] = (char*) NULL; //[ ptr1, ptr2, ... , ptrN, (char*) NULL, ... ]: We just added the (char*) NULL.
//Now assign the Data: c-strings. (\0 terminated strings):
char *str_region = (char*) out + size_ptr_region; //Region inside allocated memory which contains the String Data.
memcpy( str_region, line, line_size ); //Copy input with delimiter characters: They will be replaced with \0.
//Now we should replace: "arg1||arg2||arg3" with "arg1\0|arg2\0|arg3". Don't worry for characters after '\0'
//They are not used in standard c lbraries.
for( i = 0; i < tokens_found; i++) str_region[ end_idx[ i ] ] = '\0';
//"Out of Range" TEST. Wait until Assigned Values are Printed back.
//for ( int i=0; i < 5; i++ ) printf("c=%x ", extra_chars[i] ); printf("\n");
// *out memory should now contain (example data):
//[ ptr1, ptr2,...,ptrN, (char*) NULL, "token1\0", "token2\0",...,"tokenN\0", 5 bytes for tests ]
// |__________________________________^ ^ ^ ^
// |_______________________________________| | |
// |_____________________________________________| These 5 Bytes should be intact.
return tokens_found;
}
int main()
{
char in_line[] = "Arg1;;Th;s is not Del;m;ter;;Arg3;;;;Final";
char delim[] = ";;";
char **columns;
int i;
printf("Example1:\n");
columns = NULL; //Should be NULL to indicate that it is not assigned to allocated memory. Otherwise return -4;
int cols_found = getcols( in_line, delim, &columns);
for ( i = 0; i < cols_found; i++ ) printf("Column[ %d ] = %s\n", i, columns[ i ] ); //<- (1st way).
// (2nd way) // for ( i = 0; columns[ i ]; i++) printf("start_idx[ %d ] = %s\n", i, columns[ i ] );
free( columns ); //Release the Single Contiguous Memory Space.
columns = NULL; //Pointer = NULL to indicate it does not reserve space and that is ready for the next malloc().
printf("\n\nExample2, Nested:\n\n");
char example_file[] = "ID;Day;Month;Year;Telephone;email;Date of registration\n"
"1;Sunday;january;2009;123-124-456;jitter#go.xyz;2015-05-13\n"
"2;Monday;March;2011;(+30)333-22-55;buffer#wl.it;2009-05-23";
char **rows;
int j;
rows = NULL; //getcols() requires it to be NULL. (Avoid dangling pointers, leaks e.t.c).
getcols( example_file, "\n", &rows);
for ( i = 0; rows[ i ]; i++) {
{
printf("Line[ %d ] = %s\n", i, rows[ i ] );
char **columnX = NULL;
getcols( rows[ i ], ";", &columnX);
for ( j = 0; columnX[ j ]; j++) printf(" Col[ %d ] = %s\n", j, columnX[ j ] );
free( columnX );
}
}
free( rows );
rows = NULL;
return 0;
}
A complete example which leaves the fields as NULL-terminated strings in the original input buffer and provides access to them via an array of char pointers. The CSV processor has been confirmed to work with fields enclosed in "double quotes", ignoring any delimiter chars within them.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// adjust BUFFER_SIZE to suit longest line
#define BUFFER_SIZE 1024 * 1024
#define NUM_FIELDS 10
#define MAXERRS 5
#define RET_OK 0
#define RET_FAIL 1
#define FALSE 0
#define TRUE 1
// char* array will point to fields
char *pFields[NUM_FIELDS];
// field offsets into pFields array:
#define LP 0
#define IMIE 1
#define NAZWISKo 2
#define ULICA 3
#define NUMER 4
#define KOD 5
#define MIEJSCOw 6
#define TELEFON 7
#define EMAIL 8
#define DATA_UR 9
long loadFile(FILE *pFile, long *errcount);
static int loadValues(char *line, long lineno);
static char delim;
long loadFile(FILE *pFile, long *errcount){
char sInputBuf [BUFFER_SIZE];
long lineno = 0L;
if(pFile == NULL)
return RET_FAIL;
while (!feof(pFile)) {
// load line into static buffer
if(fgets(sInputBuf, BUFFER_SIZE-1, pFile)==NULL)
break;
// skip first line (headers)
if(++lineno==1)
continue;
// jump over empty lines
if(strlen(sInputBuf)==0)
continue;
// set pFields array pointers to null-terminated string fields in sInputBuf
if(loadValues(sInputBuf,lineno)==RET_FAIL){
(*errcount)++;
if(*errcount > MAXERRS)
break;
} else {
// On return pFields array pointers point to loaded fields ready for load into DB or whatever
// Fields can be accessed via pFields, e.g.
printf("lp=%s, imie=%s, data_ur=%s\n", pFields[LP], pFields[IMIE], pFields[DATA_UR]);
}
}
return lineno;
}
static int loadValues(char *line, long lineno){
if(line == NULL)
return RET_FAIL;
// chop of last char of input if it is a CR or LF (e.g.Windows file loading in Unix env.)
// can be removed if sure fgets has removed both CR and LF from end of line
if(*(line + strlen(line)-1) == '\r' || *(line + strlen(line)-1) == '\n')
*(line + strlen(line)-1) = '\0';
if(*(line + strlen(line)-1) == '\r' || *(line + strlen(line)-1 )== '\n')
*(line + strlen(line)-1) = '\0';
char *cptr = line;
int fld = 0;
int inquote = FALSE;
char ch;
pFields[fld]=cptr;
while((ch=*cptr) != '\0' && fld < NUM_FIELDS){
if(ch == '"') {
if(! inquote)
pFields[fld]=cptr+1;
else {
*cptr = '\0'; // zero out " and jump over it
}
inquote = ! inquote;
} else if(ch == delim && ! inquote){
*cptr = '\0'; // end of field, null terminate it
pFields[++fld]=cptr+1;
}
cptr++;
}
if(fld > NUM_FIELDS-1){
fprintf(stderr, "Expected field count (%d) exceeded on line %ld\n", NUM_FIELDS, lineno);
return RET_FAIL;
} else if (fld < NUM_FIELDS-1){
fprintf(stderr, "Expected field count (%d) not reached on line %ld\n", NUM_FIELDS, lineno);
return RET_FAIL;
}
return RET_OK;
}
int main(int argc, char **argv)
{
FILE *fp;
long errcount = 0L;
long lines = 0L;
if(argc!=3){
printf("Usage: %s csvfilepath delimiter\n", basename(argv[0]));
return (RET_FAIL);
}
if((delim=argv[2][0])=='\0'){
fprintf(stderr,"delimiter must be specified\n");
return (RET_FAIL);
}
fp = fopen(argv[1] , "r");
if(fp == NULL) {
fprintf(stderr,"Error opening file: %d\n",errno);
return(RET_FAIL);
}
lines=loadFile(fp,&errcount);
fclose(fp);
printf("Processed %ld lines, encountered %ld error(s)\n", lines, errcount);
if(errcount>0)
return(RET_FAIL);
return(RET_OK);
}
Use fscanf to read the file until you encounter ';' or \n, then just skip it with fscanf(f, "%*c").
int main()
{
char str[128];
int result;
FILE* f = fopen("test.txt", "r");
/*...*/
do {
result = fscanf(f, "%127[^;\n]", str);
if(result == 0)
{
result = fscanf(f, "%*c");
}
else
{
//Put here whatever you want to do with your value.
printf("%s\n", str);
}
} while(result != EOF);
return 0;
}
This code is fairly simple, but effective. It parses comma-separated files with parenthesis. You can easily modify it to suit your needs.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
// argv[1] path to csv file
// argv[2] number of lines to skip
// argv[3] length of longest value (in characters)
FILE *pfinput;
unsigned int nSkipLines, currentLine, lenLongestValue;
char *pTempValHolder;
int c;
unsigned int vcpm; // Value character marker
int QuotationOnOff; // 0 - off, 1 - on
nSkipLines = atoi(argv[2]);
lenLongestValue = atoi(argv[3]);
pTempValHolder = (char*)malloc(lenLongestValue);
if(pfinput = fopen(argv[1], "r")) {
rewind(pfinput);
currentLine = 1;
vcpm = 0;
QuotationOnOff = 0;
// currentLine > nSkipLines condition
// skips / ignores first argv[2] lines
while((c = fgetc(pfinput)) != EOF)
{
switch(c)
{
case ',':
if(!QuotationOnOff && currentLine > nSkipLines)
{
pTempValHolder[vcpm] = '\0';
printf("%s,", pTempValHolder);
vcpm = 0;
}
break;
case '\n':
if(currentLine > nSkipLines)
{
pTempValHolder[vcpm] = '\0';
printf("%s\n", pTempValHolder);
vcpm = 0;
}
currentLine++;
break;
case '\"':
if(currentLine > nSkipLines)
{
if(!QuotationOnOff) {
QuotationOnOff = 1;
pTempValHolder[vcpm] = c;
vcpm++;
} else {
QuotationOnOff = 0;
pTempValHolder[vcpm] = c;
vcpm++;
}
}
break;
default:
if(currentLine > nSkipLines)
{
pTempValHolder[vcpm] = c;
vcpm++;
}
break;
}
}
fclose(pfinput);
free(pTempValHolder);
}
return 0;
}
#include <conio.h>
#include <stdio.h>
#include <string.h>
// Driver Code
int main()
{
// Substitute the full file path
// for the string file_path
FILE* fp = fopen("Movie.csv", "r");
char *wrds[40];
if (!fp)
printf("Can't open file\n");
else {
// Here we have taken size of
// array 1024 you can modify it
char buffer[1024];
int row = 0;
int column = 0;
while (fgets(buffer, 1024, fp)) {
column = 0;
row++;
// To avoid printing of column
// names in file can be changed
// according to need
if (row == 1)
continue;
// Splitting the data
char* value = strtok(buffer, ", ");
while (value) {
// Column 1
if (column == 0) {
printf("Name :");
}
// Column 2
if (column == 1) {
printf("\tAccount No. :");
}
// Column 3
if (column == 2) {
printf("\tAmount :");
}
printf("%s", value);
wrds[column] = value;
value = strtok(NULL, ", ");
column++;
}
printf("\n");
}
// Close the file
fclose(fp);
}
getchar();
return 0;
}
I have an SQL callback function after querying the database and I'm then trying to stuff that data into a TCL dictionary so I can capture it in a TCL script.
I have this callback function which gets called for each select and it adds the column as key with it's value. I pass the Tcl_Interp* as the data arg.
int callback(void *interp, int argc, char **argv, char **azColName)
{
int i = 0;
Tcl_Obj *dictPtr = Tcl_NewDictObj();
for (i = 0; i < argc; i++) {
Tcl_Obj *key = Tcl_NewStringObj(azColName[i], -1);
Tcl_Obj *value = Tcl_NewStringObj((argv[i] ? argv[i] : "null"), -1);
Tcl_DictObjPut((Tcl_Interp*) interp, dictPtr, key, value);
}
return TCL_OK;
}
The problem is that when running this command like ...
set res [mycommand getrow]
foreach i $res {
puts "i = $i"
}
I see that the callback does get called and the correct key/val's are being added, but the result that gets printed is ...
i = 0
Am I missing anything here? I'm expecting my key (column) and val's (row) to be listed.
You're missing a call to Tcl_SetObjResult, which is probably best immediately before the function returns TCL_OK.
int callback(void *interp, int argc, char **argv, char **azColName)
{
int i = 0;
Tcl_Obj *dictPtr = Tcl_NewDictObj();
for (i = 0; i < argc; i++) {
Tcl_Obj *key = Tcl_NewStringObj(azColName[i], -1);
Tcl_Obj *value = Tcl_NewStringObj((argv[i] ? argv[i] : "null"), -1);
// Should handle refcounts correctly for keys
Tcl_IncrRefCount(key);
// Don't need to pass an interp; that's just for errors
Tcl_DictObjPut(NULL, dictPtr, key, value);
Tcl_DecrRefCount(key);
}
// This is the critical line
Tcl_SetObjResult((Tcl_Interp*) interp, dictPtr);
return TCL_OK;
}
The reason why Tcl_DictObjPut doesn't need an interp here? We can (trivially) prove that it never produces an error; the dictPtr argument is always a well-formed dictionary (and unshared, but getting that wrong would cause a panic).
I have an output of a string that is:
I need to print out only the parts that are between"tele": and then the ",". for example the first one i need to print out is hel. In the above string output. "text":"hel","source": is the first part. Every where there is a "tele": and the "," i need to be printed.
the code i have written so far prints out only the first one and is shown below
int comm_poss;
string econ;
tax= mes.find("tele");
econ=mes.substr(tax,15);
cout<<"msg test : "<<econ;
This prints out tele":"hel"," but not the other part that is between the "tele" and ","
how do i print only whats between those two and make the code do it multiple times?
thanks
EDIT: the other part in the output is "tele":"FIRS","code":" found near the end
Save yourself some trouble and use a JSON parser. For example using JsonCpp library and reading the JSON file from stdin (untested):
Json::Value root;
std::cin >> root;
for (int i = 0; i < root.size(); i++) {
std::string text = root[i]["text"].asString();
std::cout << text << std::endl;
}
Could something like this help.
string txt_test;
size_t poss_text;
poss_text= replyMsg.find("text:\":\""); // Search for text":"
replyMsg=replyMsg.substr(poss_text + 8); // Get rest of string
// Add 8 to get beyond text":"
poss_text= replyMsg.find("\","); // Search for ",
txt_test = replyMsg.substr(0, poss_text); // Get from start to ",
cout<< "msg test : " << txt_test;
You should however always check whether your string were found:
if (poss_text != std::string::npos)
{
// Found - so go on
}
else
{
// Not found - stop now
}
Now you can add the loop:
int main()
{
string replyMsg = "HEJtext:\":\"first\",\"hhhtext:\":\"second\",";
string txt_test;
size_t poss_text = 1;
while(poss_text != std::string::npos) // Loop while there is still something in replyMsg
{
poss_text= replyMsg.find("text:\":\""); // Search for text":"
if (poss_text != std::string::npos)
{
replyMsg=replyMsg.substr(poss_text + 8); // Get rest of string
// Add 8 to get beyond text":"
poss_text= replyMsg.find("\","); // Search for ",
if (poss_text != std::string::npos)
{
txt_test = replyMsg.substr(0, poss_text); // Get from start to ",
cout<< "msg test : " << txt_test << std::endl ;
replyMsg=replyMsg.substr(poss_text); // Prepare for next search
}
}
}
return 0;
}
This is a working solution.
I will not use any library since you probably want to know how to do it from scratch.
1. Using Strtok() with delim(':') and checking if the 6 characters to
the left is equal to "text", If TRUE, then pickup all characters to the right
until you hit ",".
2. When you're picking up characters to the right, to avoid reading past your domain, modify the content string by adding a '$' symbol to the end.
#include <iostream>
void get_text(char * token);
int main(){
char =content[]="586162004425048066\",\"text\":\"hel\",\"source\":...\"text\":\"yo\";$";
char * token;
token=strtok(content,":");
get_text(token);
while(token=strtok(NULL,":")){
get_text(token);
}
}
void get_text(char * token){
unsigned int len=strlen(token);
std::string temp;
if (len>=6){ // Reading the 6 characters to the left and storing it in temp
for (int i=-6; i<0; i++){
temp=temp+token[len+i];
}
}
if (temp=="\"text\""){
temp="";
unsigned i=len;
while(token[i]!=',' and token[i]!='$'){ // retrieve characters to the right until you hit a ',' or '$' (which indicates end of line as a boundary condition)
temp=temp+token[i];
i++;
}
std::cout<<temp;
}
}
OUTPUT
"hey" "yo"
I'm trying to execute MySQL query in C, however I get a Segmentation fault while calling mysql_num_rows().
Here's the code I'm using:
char *username = "test#mail.com";
char *password = "pass";
char query[1000];
int len;
char *q = "SELECT * FROM Users WHERE `Email` = '%s' AND `Password` = '%s'";
len = snprintf(query, strlen(q) + strlen(username) + strlen(password), q, username, password);
MYSQL_RES *result;
if (db_query(query, result))
{
if (result != NULL)
{
int test_count = mysql_num_rows(result);
printf("%d\n", test_count);
}
}
else
{
printf("Query error\n");
}
And here is the db_query() function:
bool db_query(const char *query, MYSQL_RES *result)
{
if (mysql_query(db_connection, query))
{
printf("mysql_query(): Error %u: %s\n", mysql_errno(db_connection), mysql_error(db_connection));
return false;
}
if (!(result = mysql_store_result(db_connection)))
{
printf("mysql_store_result(): Error %u: %s\n", mysql_errno(db_connection), mysql_error(db_connection));
return false;
}
return true;
}
I've tested the query and the problem isn't there, the connection is initiated too. Any ideas?
Thanks!
Your problem is here, in the db_query function:
if (!(result = mysql_store_result(db_connection)))
The assignment to result has no visible effect in the function's caller - you're passing a pointer by value, changing the value of result in the callee doesn't do anything to result in the caller.
You need to change your function to take a pointer-to-pointer, and adapt the call site and the db_query function.
bool db_query(const char *query, MYSQL_RES **result)
{
...
if (!(*result = mysql_store_result(db_connection)))
...
}
Any changes to result in your db_query function are not reflected back to the caller, hence it will still contain the arbitrary value it had when it was created (as an auto variable with no initialisation.
If you want to change the value and have it reflected back, you should pass a double pointer to it then dereference the double pointer to get at the actual value.
Even better would be to return the result value and use its NULL/non-NULL status for a success code rather than returning true/false.
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.