gcolumbus
gcolumbus

Reputation: 127

changing variables in a Fortran input file using C++

I was hoping someone could give me advice as to easily change the value of various variables within a Fortran input file from a C++ application.

I have a model written in Fortran but am writing a C++ application to execute the model in a loop but changing the value of the model parameters after each model execution.

Any advice would be appreciated.

Thanks!

    .Pnd file Subbasin: 1 7/26/2012 12:00:00 AM ArcSWAT 2009.93.7
Pond inputs:
           0.000    | PND_FR : Fraction of subbasin area that drains into ponds. The value for PND_FR should be between 0.0 and 1.0. If PND_FR = 1.0, the pond is at the outlet of the subbasin on the main channel
           0.000    | PND_PSA: Surface area of ponds when filled to principal spillway [ha]
           0.000    | PND_PVOL: Volume of water stored in ponds when filled to the principal spillway [104 m3]
           0.000    | PND_ESA: Surface area of ponds when filled to emergency spillway [ha]
           0.000    | PND_EVOL: Volume of water stored in ponds when filled to the emergency spillway [104 m3]
           0.000    | PND_VOL: Initial volume of water in ponds [104 m3]
           0.000    | PND_SED: Initial sediment concentration in pond water [mg/l]
           0.000    | PND_NSED: Normal sediment concentration in pond water [mg/l]
           0.000    | PND_K: Hydraulic conductivity through bottom of ponds [mm/hr].
               0    | IFLOD1: Beginning month of non-flood season
               0    | IFLOD2: Ending month of non-flood season
           0.000    | NDTARG: Number of days needed to reach target storage from current pond storage
          10.000    | PSETLP1: Phosphorus settling rate in pond for months IPND1 through IPND2 [m/year]
          10.000    | PSETLP2: Phosphorus settling rate in pond for months other than IPND1-IPND2 [m/year]
           5.500    | NSETLP1: Initial dissolved oxygen concentration in the reach [mg O2/l]
           5.500    | NSETLP2: Initial dissolved oxygen concentration in the reach [mg O2/l]
           1.000    | CHLAP: Chlorophyll a production coefficient for ponds [ ] 
           1.000    | SECCIP: Water clarity coefficient for ponds [m]
           0.000    | PND_NO3: Initial concentration of NO3-N in pond [mg N/l]
           0.000    | PND_SOLP: Initial concentration of soluble P in pond [mg P/L]
           0.000    | PND_ORGN: Initial concentration of organic N in pond [mg N/l]
           0.000    | PND_ORGP: Initial concentration of organic P in pond [mg P/l]
           5.000    | PND_D50: Median particle diameter of sediment [um]
               1    | IPND1: Beginning month of mid-year nutrient settling "season"
               1    | IPND2: Ending month of mid-year nutrient settling "season"
Wetland inputs:
           0.000    | WET_FR : Fraction of subbasin area that drains into wetlands
           0.000    | WET_NSA: Surface area of wetlands at normal water level [ha]
           0.000    | WET_NVOL: Volume of water stored in wetlands when filled to normal water level [104 m3] 
           0.000    | WET_MXSA: Surface area of wetlands at maximum water level [ha]
           0.000    | WET_MXVOL: Volume of water stored in wetlands when filled to maximum water level [104 m3]
           0.000    | WET_VOL: Initial volume of water in wetlands [104 m3]
           0.000    | WET_SED: Initial sediment concentration in wetland water [mg/l]
           0.000    | WET_NSED: Normal sediment concentration in wetland water [mg/l]
           0.000    | WET_K: Hydraulic conductivity of bottom of wetlands [mm/hr]
           0.000    | PSETLW1: Phosphorus settling rate in wetland for months IPND1 through IPND2 [m/year]
           0.000    | PSETLW2: Phosphorus settling rate in wetlands for months other than IPND1-IPND2 [m/year]
           0.000    | NSETLW1: Nitrogen settling rate in wetlands for months IPND1 through IPND2 [m/year]
           0.000    | NSETLW2: Nitrogen settling rate in wetlands for months other than IPND1-IPND2 [m/year]
           0.000    | CHLAW: Chlorophyll a production coefficient for wetlands [ ]
           0.000    | SECCIW: Water clarity coefficient for wetlands [m]
           0.000    | WET_NO3: Initial concentration of NO3-N in wetland [mg N/l]
           0.000    | WET_SOLP: Initial concentration of soluble P in wetland [mg P/l]
           0.000    | WET_ORGN: Initial concentration of organic N in wetland [mg N/l]
           0.000    | WET_ORGP: Initial concentration of organic P in wetland [mg P/l]
           0.000    | PNDEVCOEFF: Actual pond evaporation is equal to the potential evaporation times the pond evaporation coefficient
           0.000    | WETEVCOEFF: Actual wetland evaporation is equal to the potential evaporation times the wetland evaporation coefficient.

Upvotes: 1

Views: 280

Answers (5)

weymouth
weymouth

Reputation: 541

I know you asked for C++, but I have a very similar situation with my code and I use shell scripts.

I use sed s/var_name/value <template >input_file to change occurrences of the var_name in the template. My file format is set up to make this easy, but sed is a super flexible tool and I am sure it could do what you are asking. There is a tutorial here.

With that set up I write a script to loop through these sed commands and the application calls. This works like a charm. Besides, learning a little scripting will help you handle all kind of other tasks like sorting through the data generated from all those different runs.

Upvotes: 0

emsr
emsr

Reputation: 16353

I tools like there is a number inside a 20-byte ASCII field, a '|' symbol, and a variable name terminated by a ':'. The lines are variable length. So something like this:

// ./bin/bin/g++ -o hackpond hackpond.cpp

#include <fstream>
#include <string>
#include <cstddef>
#include <sstream>
#include <iomanip>

int
main()
{
    std::string variable_you_want = "PND_SOLP";
    std::string line;
    std::fstream pond("test.pnd");
    std::getline(pond, line);
    while (! pond.eof())
    {
    std::string value, variable;
    std::size_t loc = pond.tellg();
    std::getline(pond, line);
        if (line == "Pond inputs:")
            continue;
        else if (line == "Wetland inputs:")
            continue;
        std::ostringstream hack();
        value = line.substr(0, 20);
        std::size_t colon = line.find(':', 20);
        if (colon == std::string::npos)
            continue;
        variable = line.substr(22, colon - 22);
    if (variable == variable_you_want)
    {
            double new_value = 666.66;
            pond.seekp(loc);
            std::ostringstream thing;
            thing << std::setw(20) << new_value;
            pond.write(thing.str().c_str(), thing.str().length());
    }
        if (pond.eof())
            break;
    }
}

The basic idea is that you 1. note the starting location of the line you want to change (tellg), 2. create a 20 character string containing the new value, 3. go to the saved start position of that line (seekp) and write the new chunk.

Upvotes: 0

haraldkl
haraldkl

Reputation: 3819

As far as I understand your problem, you merely need some text-editing in C++. I guess the easiest thing would be to have all the parameters in the C++ code and let that code write the complete text file for each run. If you don't want to do that, I'd recommend to use some template toolbox, maybe something like cpptemplate or teng, though there are probably many more templating engines available for C++ out there, which might be suitable for your use case.

Upvotes: 0

High Performance Mark
High Performance Mark

Reputation: 78324

Take a look at Fortran's namelist I/O which may suit your purposes. The IBM XL Fortran documentation for this feature is here. Make sure you consult the documentation for your own compiler, each one has some quirky variations on the standard it seems (or perhaps the standard isn't quite tight enough).

Upvotes: 1

wonna
wonna

Reputation: 1

I'm not an expert on FORTRAN, but I think I would look into using command line arguments for each parameter that needs to change. This is only possible, however, if you are using FORTRAN 2003. I think that FORTRAN 95 is still one of the most common FORTRAN standards in use, but I don't know that for sure. If your implementation of FORTRAN does support command line arguments, see if this site can help you figure out how to use them: http://fortranwiki.org/fortran/show/Command-line+arguments Otherwise, you could have the FORTRAN program read in those values from a text file. If you want to get really nasty, you could have your C++ program actually alter the FORTRAN source file and recompile it each time it needs to run. If you do that, then back it up first. Good luck.

Upvotes: 0

Related Questions