Lookup table, interpolation, etc. (unsure how to fix errors)

I am attempting to extract values from a pre-generated lookup table I have stored in an input data text file in the format of:
Particle charge (z) Energy (MeV) Dose (MeV)
1 100 0.681365
1 500 0.261032
2 200 1.69442
2 750 0.908794
3 125 5.22689
3 620 2.16828
4 330 5.06965
4 842 3.52304

except it is VERY large (every energy value ranging from 100-1500 MeV for every individual particle with charge 1-28). The goal is to input values for dose (generated measurements from another code and do not match values of dose in the lookup table exactly, hence why I'm using interpolation) and have the code utilize the lookup table to output the corresponding incident particle energy as well as the associated particle charge. I have not yet implemented as to how it will also output associated particle charge because I'm not exactly sure how to go about doing that. My biggest issue here is the error codes I keep getting. I'm not sure how to fix my code from here or find a better way to accomplish this as I've sort of ran into a brick wall. Any input would be sincerely appreciated!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <cassert>
#include <utility>
using namespace std;

//--------------------------------------

struct LTable                                        // Basic data structure
{
   double Charge;
   double Energy;
   double Dose;
};

//--------------------------------------

ifstream &operator >> ( ifstream &in, LTable &tr )     // Read one data item
{
   in >> tr.Charge >> tr.Energy >> tr.Dose;
   return in;
}

//--------------------------------------

vector<LTable> getData( istream &in )                // Read data from any input stream
{
   vector<LTable> result;
   string line;
   LTable tr;

   while ( getline( in, line ) )
   {
      ifstream ss( line );
      if ( ss >> tr ) result.push_back( tr );
   }

   return result;
}

//--------------------------------------

// Interpolate (NOT use closest).
// Independent variable x, dependent variable y
// NOTE: must be sorted by whatever is x

double interpolate( const vector<LTable> &data, double LTable::*x, double LTable::*y, double xValue )
{
   auto ip = lower_bound( data.begin(), data.end(), xValue, [ x ]( LTable a, double b ){ return a.*x < b; } );

   // No extrapolation beyond data limits
   if ( ip == data.end  () )
   {
     return data.back ().*y;
   }
   else if ( ip == data.begin() )
   {
     return data.front().*y;
   }

   // Otherwise, linear interpolation
   auto im = ip - 1;
   double slope = ( (*ip).*y - (*im).*y ) / ( (*ip).*x - (*im).*x );      // dY/dX
   return (*im).*y + slope * ( xValue - (*im).*x );                       // Y0 + (dY/dX) * ( X - X0 )
}

//--------------------------------------

int main()
{
  // Get data
  ifstream in( "LTable.in");

  vector<LTable> data = getData( in );

  // Do some interpolation: Dose to Energy
   cout <<  "Dose" << "\t" << "Particle Energy" << '\n';
   sort( data.begin(), data.end(), []( LTable a, LTable b ){ return a.Dose < b.Dose; } );

   double Dvalues[] = { 98.892, 98.913, 98.9341, 98.9553 };
   for ( double Dose : Dvalues ) cout << Dose << '\t' << interpolate( data, &LTable::Dose, &LTable::Energy, Dose ) << '\n';
   cout << '\n';

   return 0;
}

//--------------------------------------


*code credits to @lastchance*

Errors:
Lookup_Table.cpp: In function ‘double interpolate(const std::vector<LTable, std::allocator<LTable> >&, double LTable::*, double LTable::*, double)’:
Lookup_Table.cpp:55: error: expected primary-expression before ‘[’ token
Lookup_Table.cpp:55: error: expected primary-expression before ‘a’
Lookup_Table.cpp:55: error: expected primary-expression before ‘double’
Lookup_Table.cpp:55: error: unable to deduce ‘auto’ from ‘<expression error>’
Lookup_Table.cpp:68: error: unable to deduce ‘auto’ from ‘<expression error>’
Lookup_Table.cpp: In function ‘int main()’:
Lookup_Table.cpp:84: error: expected primary-expression before ‘[’ token
Lookup_Table.cpp:84: error: expected primary-expression before ‘]’ token
Lookup_Table.cpp:84: error: expected primary-expression before ‘a’
Lookup_Table.cpp:84: error: expected primary-expression before ‘b’
Lookup_Table.cpp:87: error: expected initializer before ‘:’ token
Lookup_Table.cpp:90: error: expected primary-expression before ‘return’
Lookup_Table.cpp:90: error: expected ‘)’ before ‘return’
Last edited on
You are not compiling as C++11 (or greater). Add -std=c++11 (or c++14 or c++17) to the compile command.
I've actually done that, and the list of errors as shown here significantly decreased as compared to before.
I don't get any errors at all compiling as:

g++ -std=c++11 -Wall -W -pedantic lookup.cpp

Last edited on
I believe I have version 4.4.7, so I have to use g++ -std=c++0x -Wall -W -pedantic Lookup_Table.cpp (didn't think that would make a difference though? I'm fairly new to this, my apologies). It's still giving me the same errors, only now there's an additional error saying "Lookup_Table.cpp:86: warning: unused variable ‘Dvalues’."
That's pretty old (2012?). You should update if possible.
I'm sure I've seen those interpolation routines before! Ah well!

You have to show the actual code that you are getting those "errors" from. (The last was actually a warning, not an error, but it's referring to a blank line in what you've posted, and there's no reason it should have occurred.)

Physically, I'm not sure that you could regard dose as the independent variable; you couldn't guarantee unique values of it in your table.
@dutch yeah it is, I was using puTTY & was connected to my school's remote desktop and doing stuff from there. Apparently, I can't update it bc I'm simply not an authorized "sudoer" as they put it lol. I went ahead and got Ubuntu and I transferred everything to there. I shall see how it turns out in the morning. I appreciate your help!!

@lastchance haha yes! I was wondering if you'd pop up here -- thought you might get a laugh or two. Absolutely all props to you for the code, couldn't thank your forum post enough! And yes, technically and physically speaking, dose is very much so the dependent variable. The issue at hand here is that I'll be doing some measurements soon, and basically the main thing I'll be reading/gathering will be the dose deposited. I want to see if I can utilize the dose measurements to identify its culprit. Like I just responded to dutch, I had some weird issues with permissions using my school's remote desktop through the puTTY UNIX system, so I'm getting everything onto Ubuntu now. I'll run everything through in the morning, hopefully at least with an updated version it'll be smoother. I'll update when I'm finished with it all. Thanks so much!
Last edited on
would this general interpolation structure work or should I change something?
Last edited on
@hfizz,
Your data will have 2 independent variables and one dependent one. If you fixed the particle charge then you could get energy from the dose, but not otherwise.

Look at the 8 lines that you gave in your example. Suppose you had a dose of 4.0 MeV. From that data alone you could have EITHER
- a particle charge of 3 and an energy somewhere between 125 and 620 MeV
- OR a particle charge of 4 and an energy somewhere between 330 and 842 MeV

Linear interpolation alone won't tell you which of those two it is. If you have a perfectly calibrated and executed test, and if there are only discrete possible charge/energy pairs then you could search for the nearest combination (or, probably, a set of near candidates).

You don't say how your particles are energised.
Last edited on
BTW, the original routines were at
http://www.cplusplus.com/forum/beginner/248449/#msg1095033

You shouldn't have
ifstream ss( line );
because that would create a new filestream. If using this technique (it's not the only possibility here) then use a stringstream
stringstream ss( line );

I probably wouldn't do the input that way now.


@lastchance and @dutch,

That's an old version of GCC, which doesn't fully support all C++11 features. GCC wasn't really C++11 compliant until around v4.9. If you compile that code with anything newer than v4.9, you should find it works.

One of the things on my to-do list is to open-source a calibration and engineering unit conversion library with support for look-up tables and polynomials for data acquisition and post-processing.
@lastchance oh the data I provided up there isn't even near the amount of data I have in my lookup table. I only provided such few numbers bc there was no way I could fit...this is ~39,200 lines lol so lots of data, not just the numbers provided above. That was just for getting across the general structure of the lookup table.
I see what you mean about using something more like searching for the nearest combination which initially I was going to do, I just wasn't sure if that or interpolation was the better way to go. But I may try to do that.
I know how the particles are energized, but for the purpose of this code it's not of importance. I just need to know that heavy charged particles are incident on the dosimeter's sensor & how can I utilize my measurement to figure out the incident particle's species and energy.

@dutch & @jwin Also, after using the updated version of GCC, my code compiled. However, when running it gives "Segmentation fault (core dumped)."
Last edited on
Try this one. I've grown up since I wrote the original routines.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <algorithm>
#include <utility>
using namespace std;

//--------------------------------------

struct LTable
{
   double Charge;
   double Energy;
   double Dose;
   friend istream &operator >> ( istream &in, LTable &tr ) { return in >> tr.Charge >> tr.Energy >> tr.Dose; }
};

//--------------------------------------

// Interpolate
// Independent variable x, dependent variable y, determined by member pointers
// NOTE: must be sorted by whatever is x

template <typename T>
double interpolate( const vector<T> &data, double T::*x, double T::*y, double xValue )
{
   auto ip = lower_bound( data.begin(), data.end(), xValue, [ x ]( T a, double b ){ return a.*x < b; } );

   // No extrapolation beyond data limits
   if      ( ip == data.end  () ) return data.back ().*y;
   else if ( ip == data.begin() ) return data.front().*y;

   // Otherwise, linear interpolation
   auto im = ip - 1;
   double slope = ( (*ip).*y - (*im).*y ) / ( (*ip).*x - (*im).*x );      // dY/dX
   return (*im).*y + slope * ( xValue - (*im).*x );                       // Y0 + (dY/dX) * ( X - X0 )
}

//--------------------------------------

int main()
{
   ifstream in( "LTable.in");

   // Read data
   vector<LTable> data;
   for ( LTable item; in >> item; ) data.push_back( item );
   sort( data.begin(), data.end(), []( LTable a, LTable b ){ return a.Dose < b.Dose; } );

   // Check data
   cout << "Dose-sorted data (Dose / Energy / Charge:\n";
   for ( auto item : data ) cout << setw( 12 ) << item.Dose << setw( 12 ) << item.Energy << '\t' << item.Charge << '\n';

   // Interpolated data
   cout << "\n\nInterpolated data (Dose / Energy):\n";
   double Dvalues[] = { 0.0, 1.0, 2.0, 3.0, 10.0 };
   for ( double Dose : Dvalues ) cout << setw( 12 ) << Dose << setw( 12 ) << interpolate( data, &LTable::Dose, &LTable::Energy, Dose ) << '\n';
}


Input file (NOTE: no header line) LTable.in
1 100 0.681365
1 500 0.261032
2 200 1.69442
2 750 0.908794
3 125 5.22689
3 620 2.16828
4 330 5.06965
4 842 3.52304


Output:
Dose-sorted data (Dose / Energy / Charge:
    0.261032         500	1
    0.681365         100	1
    0.908794         750	2
     1.69442         200	2
     2.16828         620	3
     3.52304         842	4
     5.06965         330	4
     5.22689         125	3


Interpolated data (Dose / Energy):
           0         500
           1     686.149
           2     470.847
           3     756.291
          10         125

Last edited on
However, when running it gives "Segmentation fault

In line 37 (using line numbers from listing above) where you say ifstream you mean to say istringstream. You also need to include <sstream> for that.

And technically, your operator>> overload should use istream instead of ifstream.
Hi all, sorry for the delayed response. I've had much work to do over the weekend. I decided to completely change the format of my code and what I want it to do. Thanks for all the help!
Last edited on
Topic archived. No new replies allowed.