[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [TRNSYS-users] C++ file names and labels in TRNSYS



Hi,

 

I had a similar problem once concerning using external files from C and proposed a solution in the mail below; maybe it is of use for you. TRNSYS 17 should introduce a new FILE keyword to solve this problem more properly.


Werner

 

---

 

Reading TRNSYS external files from C or C++ is somewhat tricky.

 

The problem comes from the fact that

a)       the TRNSYS kernel (not the TYPE) will open the external file at the beginning of the simulation and (assign file handles)

b)       file handles are not interoperable between compilers (sometimes not even between the release and debug version of the same FORTRAN compiler)

 

To work around the problem, it has been proposed to use the special cards mechanism instead:

  1. specify the file name as a special card
  2. read it and open() the file in the initialization of the C code
  3. close() it in the type at simulation stop

 

Recently, I implemented another method to use ‘real’ external files with TYPES written in C/C++. It is way bizarre, but works:

  1. A DLL, FileReader.dll, is implemented in FORTRAN; this Dll provides functions to read the next character for a given external file
  2. The C type implements a function to read the next line in a given external file based on 1. and uses the external file like a traditional type in FORTRAN would.

 

I provided the FileReader.DLLs for those who do not have a FORTRAN compiler and the C++ code implementing a class to access it follows (made with Compaq Visual FORTRAN for compatibility with the official TRNSYS 16.1 release):

ftp://ftp.cstb.fr/software/Trnsys/FileReader/

 

 

With this, you can just read the file in C++ like this:

 

                  double LUN;

                  LUN=par[0];

 

                  iunit=info[0];

                  itype=info[1];

 

 

                std::string code;

                TrnsysFileReader theReader;

 

                while (!theReader.Eof())

                  {

                        string tmp = theReader.ReadNextLine((int) LUN);

                        code.append(rtrim(tmp));

                        code.append("\r\n");

                  }

 

 

Hope this helps,

 

Werner

#include <cmath>

#include <fstream>

 

//#include "windows.h"

#include "TrnsysFileReader.h"        

 

typedef int (__cdecl* LPFNDLLFUNC1)(int*);

LPFNDLLFUNC1 lpfnDllFunc1;

 

TrnsysFileReader::TrnsysFileReader()

{

        lpfProcFunction = NULL;

       

        TCHAR path[1024];

        GetModuleFileName(NULL, path, sizeof(path));

 

            std::string str = path;

 

            unsigned tmp1, tmp2;

            tmp1 = tmp2 = 0;

 

            for(unsigned i = 0; i < str.length(); i++)

            {

                  if(path[i] == '\\')

                  {

                        tmp2 = tmp1;

                        tmp1 = i;

                  }

            }

 

            str.resize(tmp2);

             

            #ifdef _DEBUG

                  str.append("\\Userlib\\DebugDLLs\\FileReader.dll");

            #else

                  str.append("\\Userlib\\ReleaseDLLs\\FileReader.dll");

            #endif

 

            hLibrary = LoadLibrary(str.c_str());

       

        eof = false;

        maxFileWidth=1000; // from TrnsysConstants.f90

      }

 

TrnsysFileReader::~TrnsysFileReader()

      {

          FreeLibrary(hLibrary);

      }

 

      bool TrnsysFileReader::Eof()

      {

        return eof;

      }

 

      int TrnsysFileReader::ReadNextChar(int LUN)

      {

        int c;

 

        if (hLibrary == NULL) return -1;

        lpfnDllFunc1 = (LPFNDLLFUNC1) GetProcAddress( hLibrary,

                        "READNEXTCHAR");

        int ilun = (int) LUN;

        c = lpfnDllFunc1(&ilun);

            if(c == -2) throw std::bad_exception("Problème avec le fichier");

        if (c == -1) eof = true;

        return c;

 

      }

 

      std::string TrnsysFileReader::ReadFile(int LUN)

      {

        std::string result;

        char c;

        while ((c = ReadNextChar(LUN)) && (!eof))

        {         

          std::string s;

          s.append(&c,1);

          result.append(s);

        }

 

        return result;

      }

 

      std::string TrnsysFileReader::ReadNextLine(int LUN)

      {

        std::string result;

        char c;

        while ((c = ReadNextChar(LUN)) && (!eof) && (result.length() < (unsigned int)maxFileWidth-1))

        {         

          std::string s;

          s.append(&c,1);

          result.append(s);

        }

 

        return result;

      }

 

 

 

 

 

 

TrnsysFileReader.h :

 

#ifndef trnsyfilereaderincluded

#define trnsyfilereaderincluded

 

#include <cmath>

#include <fstream>

#include "windows.h"

#include <string.h>

#include "TRNSYS.h" //TRNSYS acess functions (allow to acess TIME etc.)

 

typedef int (__cdecl* LPFNDLLFUNC1)(int*);

 

class TrnsysFileReader

{

 

private :

      HMODULE hLibrary;

      FARPROC lpfProcFunction;  

      bool eof;

      LPFNDLLFUNC1 lpfnDllFunc1;

      int maxFileWidth;

 

public:

      TrnsysFileReader();

      ~TrnsysFileReader();

      bool Eof();

      int ReadNextChar(int LUN);

      std::string ReadNextLine(int LUN);

      std::string ReadFile(int LUN);

};

 

 

 

#endif

 

 

 


De : Mark.Goldsworthy@csiro.au [mailto:Mark.Goldsworthy@csiro.au]
Envoyé : mercredi 13 janvier 2010 00:17
À : trnsys-users@cae.wisc.edu
Objet : [TRNSYS-users] C++ file names and labels in TRNSYS

 

Hi,

 

I have read some posts on passing file names or labels to C++ TRNSYS types but I don't think this question has been definitively answered.

 

This is what I have done:

 

In the TRNSYS.h file I have the following lines which map the fortran functions to C:

extern "C" __declspec(dllimport) char* _cdecl TRNSYSFUNCTIONS_mp_GETLUFILENAME(int* LU);
extern "C" __declspec(dllimport) char* _cdecl TRNSYSFUNCTIONS_mp_GETLABEL(int*, int*);
#define getLUfilename TRNSYSFUNCTIONS_mp_GETLUFILENAME
#define getLabel TRNSYSFUNCTIONS_mp_GETLABEL

Then in the type I have:

char *ss, *ss2; 
int LU=(int) par[0]; 
int iu=info[0];
int num=1;
ss=getLabel(&iu,&num);
ss2=getLUfilename(&LU);
FILE *log; fopen_s(&log,"log.dat","w");
fprintf(log,"\n%s\n%s",ss,ss2); fclose(log);

This code works (doesn't crash) but prints to the log file:

"Label not available"

"Cannot find a file associated with that logical unit"

 

I did link the file, logical unit and labels correctly in the proforma so that is not the problem.

 

Does anyone know what I am doing wrong?

 

Thanks,

 

Mark