C++ Best practices for dealing with many constants, variables in scientific codes












4












$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










share|cite|improve this question









$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


















4












$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










share|cite|improve this question









$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
















4












4








4





$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










share|cite|improve this question









$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++






share|cite|improve this question













share|cite|improve this question











share|cite|improve this question




share|cite|improve this question










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
















  • 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












3 Answers
3






active

oldest

votes


















3












$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 &params) {
...
}

int main(int argc, char **argv){
Params params(argv[1]);
Foo(params);
}





share|cite|improve this answer









$endgroup$













  • $begingroup$
    All great answers but the class-solution works best for my situation.
    $endgroup$
    – EternusVia
    25 mins ago



















2












$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;





share|cite|improve this answer









$endgroup$





















    0












    $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.






    share|cite|improve this answer









    $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











    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
    });


    }
    });














    draft saved

    draft discarded


















    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









    3












    $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 &params) {
    ...
    }

    int main(int argc, char **argv){
    Params params(argv[1]);
    Foo(params);
    }





    share|cite|improve this answer









    $endgroup$













    • $begingroup$
      All great answers but the class-solution works best for my situation.
      $endgroup$
      – EternusVia
      25 mins ago
















    3












    $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 &params) {
    ...
    }

    int main(int argc, char **argv){
    Params params(argv[1]);
    Foo(params);
    }





    share|cite|improve this answer









    $endgroup$













    • $begingroup$
      All great answers but the class-solution works best for my situation.
      $endgroup$
      – EternusVia
      25 mins ago














    3












    3








    3





    $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 &params) {
    ...
    }

    int main(int argc, char **argv){
    Params params(argv[1]);
    Foo(params);
    }





    share|cite|improve this answer









    $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 &params) {
    ...
    }

    int main(int argc, char **argv){
    Params params(argv[1]);
    Foo(params);
    }






    share|cite|improve this answer












    share|cite|improve this answer



    share|cite|improve this answer










    answered 5 hours ago









    RichardRichard

    39019




    39019












    • $begingroup$
      All great answers but the class-solution works best for my situation.
      $endgroup$
      – EternusVia
      25 mins ago


















    • $begingroup$
      All great answers but the class-solution works best for my situation.
      $endgroup$
      – EternusVia
      25 mins ago
















    $begingroup$
    All great answers but the class-solution works best for my situation.
    $endgroup$
    – EternusVia
    25 mins ago




    $begingroup$
    All great answers but the class-solution works best for my situation.
    $endgroup$
    – EternusVia
    25 mins ago











    2












    $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;





    share|cite|improve this answer









    $endgroup$


















      2












      $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;





      share|cite|improve this answer









      $endgroup$
















        2












        2








        2





        $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;





        share|cite|improve this answer









        $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;






        share|cite|improve this answer












        share|cite|improve this answer



        share|cite|improve this answer










        answered 1 hour ago









        spektrspektr

        2,4061812




        2,4061812























            0












            $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.






            share|cite|improve this answer









            $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
















            0












            $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.






            share|cite|improve this answer









            $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














            0












            0








            0





            $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.






            share|cite|improve this answer









            $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.







            share|cite|improve this answer












            share|cite|improve this answer



            share|cite|improve this answer










            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


















            • $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


















            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Accessing regular linux commands in Huawei's Dopra Linux

            Can't connect RFCOMM socket: Host is down

            Kernel panic - not syncing: Fatal Exception in Interrupt