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

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



 

 


De : keilholz, werner
Envoyé : lundi 25 janvier 2010 14:16
À : Mark.Goldsworthy@csiro.au
Objet : RE: [TRNSYS-users] C++ file names and labels in TRNSYS

 

Mark,

 

You can use the Special cards for that, you may just have to add the declaration of the function to access the special cards to Trnsys.h (it is not declared there by default). In this case, you should not declare the file as an “External file” in the PROFORMA, and handle opening and closing it yourself, as you suggested.

 

This is a bit complicated, due to the way strings are handled in FORTRAN ; I’ve described the principle for the MESSAGE function here:

 

https://www-old.cae.wisc.edu/pipermail/trnsys-users/2009/004778.html

 

Werner

 


De : Mark.Goldsworthy@csiro.au [mailto:Mark.Goldsworthy@csiro.au]
Envoyé : dimanche 17 janvier 2010 23:48
À : keilholz, werner
Objet : RE: [TRNSYS-users] C++ file names and labels in TRNSYS

 

Werner,

Thanks for your help. I have implemented your code below and downloaded the header files and I can get it to compile. I think it opens the file but doesn't read any lines (prints "null").


However, what I really want is to just pass the filename so that I can use my existing 'C' code (i.e. fscanf etc.) statements to do what I need.

Using the labels (special cards) seems like a good way to do this but I could not get this to work (please see my code in the previous email).

It seems to me that a much simpler solution is to use the labels anyway -> could you please tell me what I am doing wrong with that?

 

Thank you

 

Mark

 

 

 

 


From: keilholz, werner [mailto:werner.keilholz@cstb.fr]
Sent: Friday, 15 January 2010 7:31 PM
To: Goldsworthy, Mark (DET, Newcastle); trnsys-users@cae.wisc.edu
Subject: 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