C++ Best practices for dealing with many constants, variables in scientific codes
$begingroup$
I am developing a code to simulate fluid flow with biological substances present in the flow. This involves the standard Navier-Stokes equations coupled to some additional biological models. There are many parameters/constants.
I have written functions to handle the major computations, but a problem I am having is the large number of constants/parameters that these computations depend on. It seems cumbersome to pass 10-20 arguments to a function.
One alternative is to make all the constants global variables, but I know this is frowned upon in C++.
What is the standard way of handling many inputs to a function? Should I make a struct and pass that instead?
Thank you
c++
$endgroup$
add a comment |
$begingroup$
I am developing a code to simulate fluid flow with biological substances present in the flow. This involves the standard Navier-Stokes equations coupled to some additional biological models. There are many parameters/constants.
I have written functions to handle the major computations, but a problem I am having is the large number of constants/parameters that these computations depend on. It seems cumbersome to pass 10-20 arguments to a function.
One alternative is to make all the constants global variables, but I know this is frowned upon in C++.
What is the standard way of handling many inputs to a function? Should I make a struct and pass that instead?
Thank you
c++
$endgroup$
5
$begingroup$
If it's possible, try to have the constants evaluated at compile time using constexpr. I try to include most of these in a separate header file. For variables, I have found that a separate class has benefits, but at the cost of potentially more bugs because you have to initialize the class before passing into the function.
$endgroup$
– Biswajit Banerjee
10 hours ago
1
$begingroup$
This is hard to answer properly without some kind of a code sample. Should I make a struct and pass that instead? In general, yes, this is absolutely the usual way to go. Group the parameters/constants by their meaning.
$endgroup$
– Kirill
3 hours ago
add a comment |
$begingroup$
I am developing a code to simulate fluid flow with biological substances present in the flow. This involves the standard Navier-Stokes equations coupled to some additional biological models. There are many parameters/constants.
I have written functions to handle the major computations, but a problem I am having is the large number of constants/parameters that these computations depend on. It seems cumbersome to pass 10-20 arguments to a function.
One alternative is to make all the constants global variables, but I know this is frowned upon in C++.
What is the standard way of handling many inputs to a function? Should I make a struct and pass that instead?
Thank you
c++
$endgroup$
I am developing a code to simulate fluid flow with biological substances present in the flow. This involves the standard Navier-Stokes equations coupled to some additional biological models. There are many parameters/constants.
I have written functions to handle the major computations, but a problem I am having is the large number of constants/parameters that these computations depend on. It seems cumbersome to pass 10-20 arguments to a function.
One alternative is to make all the constants global variables, but I know this is frowned upon in C++.
What is the standard way of handling many inputs to a function? Should I make a struct and pass that instead?
Thank you
c++
c++
asked 10 hours ago
EternusViaEternusVia
29018
29018
5
$begingroup$
If it's possible, try to have the constants evaluated at compile time using constexpr. I try to include most of these in a separate header file. For variables, I have found that a separate class has benefits, but at the cost of potentially more bugs because you have to initialize the class before passing into the function.
$endgroup$
– Biswajit Banerjee
10 hours ago
1
$begingroup$
This is hard to answer properly without some kind of a code sample. Should I make a struct and pass that instead? In general, yes, this is absolutely the usual way to go. Group the parameters/constants by their meaning.
$endgroup$
– Kirill
3 hours ago
add a comment |
5
$begingroup$
If it's possible, try to have the constants evaluated at compile time using constexpr. I try to include most of these in a separate header file. For variables, I have found that a separate class has benefits, but at the cost of potentially more bugs because you have to initialize the class before passing into the function.
$endgroup$
– Biswajit Banerjee
10 hours ago
1
$begingroup$
This is hard to answer properly without some kind of a code sample. Should I make a struct and pass that instead? In general, yes, this is absolutely the usual way to go. Group the parameters/constants by their meaning.
$endgroup$
– Kirill
3 hours ago
5
5
$begingroup$
If it's possible, try to have the constants evaluated at compile time using constexpr. I try to include most of these in a separate header file. For variables, I have found that a separate class has benefits, but at the cost of potentially more bugs because you have to initialize the class before passing into the function.
$endgroup$
– Biswajit Banerjee
10 hours ago
$begingroup$
If it's possible, try to have the constants evaluated at compile time using constexpr. I try to include most of these in a separate header file. For variables, I have found that a separate class has benefits, but at the cost of potentially more bugs because you have to initialize the class before passing into the function.
$endgroup$
– Biswajit Banerjee
10 hours ago
1
1
$begingroup$
This is hard to answer properly without some kind of a code sample. Should I make a struct and pass that instead? In general, yes, this is absolutely the usual way to go. Group the parameters/constants by their meaning.
$endgroup$
– Kirill
3 hours ago
$begingroup$
This is hard to answer properly without some kind of a code sample. Should I make a struct and pass that instead? In general, yes, this is absolutely the usual way to go. Group the parameters/constants by their meaning.
$endgroup$
– Kirill
3 hours ago
add a comment |
3 Answers
3
active
oldest
votes
$begingroup$
If you have constants that will not change before runs, declare them in a header file:
//constants.hpp
#ifndef _constants_hpp_
#define _constants_hpp_
constexpr double G = 6.67408e-11;
constexpr double M_EARTH = 5.972e24;
constexpr double GM_EARTH = G*M_EARTH;
#endif
//main.cpp
auto f_earth = GM_EARTH*m/r/r; //Good
auto f_earth = G*M_EARTH*m/r/r; //Also good: compiler probably does math here too
The reason why you would want to do this is that it allows the compiler to calculate constant values ahead before run-time, which is good if you have a lot of them.
You can also use a simple class to pass values around:
class Params {
public:
double a,b,c,d;
Params(std::string config_file_name){
//Load configuration here
}
};
void Foo(const Params ¶ms) {
...
}
int main(int argc, char **argv){
Params params(argv[1]);
Foo(params);
}
$endgroup$
$begingroup$
All great answers but the class-solution works best for my situation.
$endgroup$
– EternusVia
19 mins ago
add a comment |
$begingroup$
Another alternative that may be in line with your train of thought is to use a namespace (or nested namespaces) to properly group constants. An example might be:
namespace constants {
namespace earth {
constexpr double G = 6.67408e-11;
constexpr double Mass_Earth = 5.972e24;
constexpr double GM = G*Mass_Earth;
}// constant properties about Earth
namespace fluid {
constexpr density = 0.999; // g/cm^3
constexpr dyn_viscosity = 1.6735; //mPa * s
}// constants about fluid at 2C
// ...
} // end namespace for constants
Using the above technique, you can localize reference constants to some desired files and namespaces, making them more controlled than global variables while getting some of the similar benefits. When you use the constants, it is as simple as doing:
constexpr double G_times_2 = 2.0*constants::earth::G;
If you dislike long chains of nested namespaces, you can always shorten things when necessary by using a namespace alias:
namespace const_earth = constants::earth;
constexpr double G_times_2 = 2.0*const_earth::G;
$endgroup$
add a comment |
$begingroup$
One way that I do is to use singleton.
When you start your program you initiate your singleton and fill it with the constant data (probably from a properties file that you have for the run). You get this in every class that you need the values and just use it.
$endgroup$
$begingroup$
Warning: I've occasionally had singletons serialize accesses in multi-threaded code. So you may want to check on this as part of your profiling stage.
$endgroup$
– Richard
5 hours ago
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["$", "$"], ["\\(","\\)"]]);
});
});
}, "mathjax-editing");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "363"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fscicomp.stackexchange.com%2fquestions%2f30999%2fc-best-practices-for-dealing-with-many-constants-variables-in-scientific-code%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
If you have constants that will not change before runs, declare them in a header file:
//constants.hpp
#ifndef _constants_hpp_
#define _constants_hpp_
constexpr double G = 6.67408e-11;
constexpr double M_EARTH = 5.972e24;
constexpr double GM_EARTH = G*M_EARTH;
#endif
//main.cpp
auto f_earth = GM_EARTH*m/r/r; //Good
auto f_earth = G*M_EARTH*m/r/r; //Also good: compiler probably does math here too
The reason why you would want to do this is that it allows the compiler to calculate constant values ahead before run-time, which is good if you have a lot of them.
You can also use a simple class to pass values around:
class Params {
public:
double a,b,c,d;
Params(std::string config_file_name){
//Load configuration here
}
};
void Foo(const Params ¶ms) {
...
}
int main(int argc, char **argv){
Params params(argv[1]);
Foo(params);
}
$endgroup$
$begingroup$
All great answers but the class-solution works best for my situation.
$endgroup$
– EternusVia
19 mins ago
add a comment |
$begingroup$
If you have constants that will not change before runs, declare them in a header file:
//constants.hpp
#ifndef _constants_hpp_
#define _constants_hpp_
constexpr double G = 6.67408e-11;
constexpr double M_EARTH = 5.972e24;
constexpr double GM_EARTH = G*M_EARTH;
#endif
//main.cpp
auto f_earth = GM_EARTH*m/r/r; //Good
auto f_earth = G*M_EARTH*m/r/r; //Also good: compiler probably does math here too
The reason why you would want to do this is that it allows the compiler to calculate constant values ahead before run-time, which is good if you have a lot of them.
You can also use a simple class to pass values around:
class Params {
public:
double a,b,c,d;
Params(std::string config_file_name){
//Load configuration here
}
};
void Foo(const Params ¶ms) {
...
}
int main(int argc, char **argv){
Params params(argv[1]);
Foo(params);
}
$endgroup$
$begingroup$
All great answers but the class-solution works best for my situation.
$endgroup$
– EternusVia
19 mins ago
add a comment |
$begingroup$
If you have constants that will not change before runs, declare them in a header file:
//constants.hpp
#ifndef _constants_hpp_
#define _constants_hpp_
constexpr double G = 6.67408e-11;
constexpr double M_EARTH = 5.972e24;
constexpr double GM_EARTH = G*M_EARTH;
#endif
//main.cpp
auto f_earth = GM_EARTH*m/r/r; //Good
auto f_earth = G*M_EARTH*m/r/r; //Also good: compiler probably does math here too
The reason why you would want to do this is that it allows the compiler to calculate constant values ahead before run-time, which is good if you have a lot of them.
You can also use a simple class to pass values around:
class Params {
public:
double a,b,c,d;
Params(std::string config_file_name){
//Load configuration here
}
};
void Foo(const Params ¶ms) {
...
}
int main(int argc, char **argv){
Params params(argv[1]);
Foo(params);
}
$endgroup$
If you have constants that will not change before runs, declare them in a header file:
//constants.hpp
#ifndef _constants_hpp_
#define _constants_hpp_
constexpr double G = 6.67408e-11;
constexpr double M_EARTH = 5.972e24;
constexpr double GM_EARTH = G*M_EARTH;
#endif
//main.cpp
auto f_earth = GM_EARTH*m/r/r; //Good
auto f_earth = G*M_EARTH*m/r/r; //Also good: compiler probably does math here too
The reason why you would want to do this is that it allows the compiler to calculate constant values ahead before run-time, which is good if you have a lot of them.
You can also use a simple class to pass values around:
class Params {
public:
double a,b,c,d;
Params(std::string config_file_name){
//Load configuration here
}
};
void Foo(const Params ¶ms) {
...
}
int main(int argc, char **argv){
Params params(argv[1]);
Foo(params);
}
answered 5 hours ago
RichardRichard
39019
39019
$begingroup$
All great answers but the class-solution works best for my situation.
$endgroup$
– EternusVia
19 mins ago
add a comment |
$begingroup$
All great answers but the class-solution works best for my situation.
$endgroup$
– EternusVia
19 mins ago
$begingroup$
All great answers but the class-solution works best for my situation.
$endgroup$
– EternusVia
19 mins ago
$begingroup$
All great answers but the class-solution works best for my situation.
$endgroup$
– EternusVia
19 mins ago
add a comment |
$begingroup$
Another alternative that may be in line with your train of thought is to use a namespace (or nested namespaces) to properly group constants. An example might be:
namespace constants {
namespace earth {
constexpr double G = 6.67408e-11;
constexpr double Mass_Earth = 5.972e24;
constexpr double GM = G*Mass_Earth;
}// constant properties about Earth
namespace fluid {
constexpr density = 0.999; // g/cm^3
constexpr dyn_viscosity = 1.6735; //mPa * s
}// constants about fluid at 2C
// ...
} // end namespace for constants
Using the above technique, you can localize reference constants to some desired files and namespaces, making them more controlled than global variables while getting some of the similar benefits. When you use the constants, it is as simple as doing:
constexpr double G_times_2 = 2.0*constants::earth::G;
If you dislike long chains of nested namespaces, you can always shorten things when necessary by using a namespace alias:
namespace const_earth = constants::earth;
constexpr double G_times_2 = 2.0*const_earth::G;
$endgroup$
add a comment |
$begingroup$
Another alternative that may be in line with your train of thought is to use a namespace (or nested namespaces) to properly group constants. An example might be:
namespace constants {
namespace earth {
constexpr double G = 6.67408e-11;
constexpr double Mass_Earth = 5.972e24;
constexpr double GM = G*Mass_Earth;
}// constant properties about Earth
namespace fluid {
constexpr density = 0.999; // g/cm^3
constexpr dyn_viscosity = 1.6735; //mPa * s
}// constants about fluid at 2C
// ...
} // end namespace for constants
Using the above technique, you can localize reference constants to some desired files and namespaces, making them more controlled than global variables while getting some of the similar benefits. When you use the constants, it is as simple as doing:
constexpr double G_times_2 = 2.0*constants::earth::G;
If you dislike long chains of nested namespaces, you can always shorten things when necessary by using a namespace alias:
namespace const_earth = constants::earth;
constexpr double G_times_2 = 2.0*const_earth::G;
$endgroup$
add a comment |
$begingroup$
Another alternative that may be in line with your train of thought is to use a namespace (or nested namespaces) to properly group constants. An example might be:
namespace constants {
namespace earth {
constexpr double G = 6.67408e-11;
constexpr double Mass_Earth = 5.972e24;
constexpr double GM = G*Mass_Earth;
}// constant properties about Earth
namespace fluid {
constexpr density = 0.999; // g/cm^3
constexpr dyn_viscosity = 1.6735; //mPa * s
}// constants about fluid at 2C
// ...
} // end namespace for constants
Using the above technique, you can localize reference constants to some desired files and namespaces, making them more controlled than global variables while getting some of the similar benefits. When you use the constants, it is as simple as doing:
constexpr double G_times_2 = 2.0*constants::earth::G;
If you dislike long chains of nested namespaces, you can always shorten things when necessary by using a namespace alias:
namespace const_earth = constants::earth;
constexpr double G_times_2 = 2.0*const_earth::G;
$endgroup$
Another alternative that may be in line with your train of thought is to use a namespace (or nested namespaces) to properly group constants. An example might be:
namespace constants {
namespace earth {
constexpr double G = 6.67408e-11;
constexpr double Mass_Earth = 5.972e24;
constexpr double GM = G*Mass_Earth;
}// constant properties about Earth
namespace fluid {
constexpr density = 0.999; // g/cm^3
constexpr dyn_viscosity = 1.6735; //mPa * s
}// constants about fluid at 2C
// ...
} // end namespace for constants
Using the above technique, you can localize reference constants to some desired files and namespaces, making them more controlled than global variables while getting some of the similar benefits. When you use the constants, it is as simple as doing:
constexpr double G_times_2 = 2.0*constants::earth::G;
If you dislike long chains of nested namespaces, you can always shorten things when necessary by using a namespace alias:
namespace const_earth = constants::earth;
constexpr double G_times_2 = 2.0*const_earth::G;
answered 1 hour ago
spektrspektr
2,4061812
2,4061812
add a comment |
add a comment |
$begingroup$
One way that I do is to use singleton.
When you start your program you initiate your singleton and fill it with the constant data (probably from a properties file that you have for the run). You get this in every class that you need the values and just use it.
$endgroup$
$begingroup$
Warning: I've occasionally had singletons serialize accesses in multi-threaded code. So you may want to check on this as part of your profiling stage.
$endgroup$
– Richard
5 hours ago
add a comment |
$begingroup$
One way that I do is to use singleton.
When you start your program you initiate your singleton and fill it with the constant data (probably from a properties file that you have for the run). You get this in every class that you need the values and just use it.
$endgroup$
$begingroup$
Warning: I've occasionally had singletons serialize accesses in multi-threaded code. So you may want to check on this as part of your profiling stage.
$endgroup$
– Richard
5 hours ago
add a comment |
$begingroup$
One way that I do is to use singleton.
When you start your program you initiate your singleton and fill it with the constant data (probably from a properties file that you have for the run). You get this in every class that you need the values and just use it.
$endgroup$
One way that I do is to use singleton.
When you start your program you initiate your singleton and fill it with the constant data (probably from a properties file that you have for the run). You get this in every class that you need the values and just use it.
answered 7 hours ago
AshkanAshkan
1663
1663
$begingroup$
Warning: I've occasionally had singletons serialize accesses in multi-threaded code. So you may want to check on this as part of your profiling stage.
$endgroup$
– Richard
5 hours ago
add a comment |
$begingroup$
Warning: I've occasionally had singletons serialize accesses in multi-threaded code. So you may want to check on this as part of your profiling stage.
$endgroup$
– Richard
5 hours ago
$begingroup$
Warning: I've occasionally had singletons serialize accesses in multi-threaded code. So you may want to check on this as part of your profiling stage.
$endgroup$
– Richard
5 hours ago
$begingroup$
Warning: I've occasionally had singletons serialize accesses in multi-threaded code. So you may want to check on this as part of your profiling stage.
$endgroup$
– Richard
5 hours ago
add a comment |
Thanks for contributing an answer to Computational Science Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fscicomp.stackexchange.com%2fquestions%2f30999%2fc-best-practices-for-dealing-with-many-constants-variables-in-scientific-code%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
5
$begingroup$
If it's possible, try to have the constants evaluated at compile time using constexpr. I try to include most of these in a separate header file. For variables, I have found that a separate class has benefits, but at the cost of potentially more bugs because you have to initialize the class before passing into the function.
$endgroup$
– Biswajit Banerjee
10 hours ago
1
$begingroup$
This is hard to answer properly without some kind of a code sample. Should I make a struct and pass that instead? In general, yes, this is absolutely the usual way to go. Group the parameters/constants by their meaning.
$endgroup$
– Kirill
3 hours ago