CFD Online Discussion Forums

CFD Online Discussion Forums (https://www.cfd-online.com/Forums/)
-   Fluent UDF and Scheme Programming (https://www.cfd-online.com/Forums/fluent-udf/)
-   -   UDF save data to a file!! (https://www.cfd-online.com/Forums/fluent-udf/72509-udf-save-data-file.html)

spk February 8, 2010 13:48

UDF save data to a file!!
 
Hi guys,

I need help!!!
I'm not familiar with UDF. I compiled the Udf of cavitation rate which is found at udf manual. I add the last line (Message...) and everything is ok.
I can see the values of cavitation mass transfer rate at fluent window. But i want to save these values in a .txt file. How can i do this?

Thanks a lot!

#include
"udf.h"
#define c_evap 1.0
#define c_con 0.1
DEFINE_CAVITATION_RATE(user_cav_rate, c, t, p, rhoV, rhoL, mafV, p_v, cigma, f_gas, m_dot)
{
real p_vapor = *p_v;
real dp, dp0, source;
p_vapor += MIN(0.195*C_R(c,t)*C_K(c,t), 5.0*p_vapor);
dp = p_vapor - ABS_P(p[c], op_pres);
dp0 = MAX(0.1, ABS(dp));
source = sqrt(2.0/3.0*rhoL[c])*dp0;
if(dp > 0.0)
*m_dot = c_evap*rhoV[c]*source;
else
*m_dot = -c_con*rhoL[c]*source;
Message("Cavitation Mass Transfer Rate: %g\n",m_dot);
}

dmoroian February 9, 2010 07:15

Code:

#include"udf.h"
#define c_evap 1.0
#define c_con 0.1
DEFINE_CAVITATION_RATE(user_cav_rate, c, t, p, rhoV, rhoL, mafV, p_v, cigma, f_gas, m_dot)
{
  FILE *pf;
  real p_vapor = *p_v;
  real dp, dp0, source;
  p_vapor += MIN(0.195*C_R(c,t)*C_K(c,t), 5.0*p_vapor);
  dp = p_vapor - ABS_P(p[c], op_pres);
  dp0 = MAX(0.1, ABS(dp));
  source = sqrt(2.0/3.0*rhoL[c])*dp0;
  if(dp > 0.0)
      *m_dot = c_evap*rhoV[c]*source;
  else
      *m_dot = -c_con*rhoL[c]*source;

  Message("Cavitation Mass Transfer Rate: %g\n",m_dot);
 
  if(NULL == (pf = fopen("bubu.txt","a")))
      Error("Could not open file for append!\n");
 
  fprintf(pf,"%e\n",m_dot);
  fclose(pf);
}


spk February 9, 2010 13:39

Thanks friend!!!
It works!!!
:)

IvanCFD May 14, 2010 05:10

Hi dmoroian,

I'd like to use a UDF to save velocity field data on 50 cross-section planes (p-1, p-2,..., p-50) of my domain after every time step of an unsteady Fluent simulation.

Would you please let me know how?

Thanks a lot beforehand,

Ivan.

dmoroian May 14, 2010 13:06

Hello Ivan,
For that purpose, I would use macros (scheme scripts) instead of udf's. You can set fluent to export the data in those planes in many different formats (my preferate is DX format for the OpenDX postprocessor).

IvanCFD May 14, 2010 13:18

Hi Dragos,

I see. However, I heard that using macros Fluent overwrites the existing file so in the end what I would have stored would be the information at the last time step. I'd like to have velocity data on several planes at every time step, for me to be able to make time marching analysis.

I'd like to export the data in ASCII and then imported them into Matlab, which is what I'm familiar with.

Any suggestion?

Thanks a lot,

Ivan.

dmoroian May 14, 2010 15:41

Well, one of the facilities is that you can automatically change the name of the output file every iteration or every time step.

IvanCFD May 14, 2010 15:50

Really?

can you let me know how?

I mean, I want to save velocity data on 50 planes and I'd need to have every plane velocity data in one single file because that eases me a lot my life later when post-processing.

Thanks,

Ivan.

dmoroian May 14, 2010 17:45

Hi Ivan,
Check chapter 4.1.7 in the user manual for automatic numbering of files, and 4.13 for exporting solution data (I think you're interested in the ASCII format).
The simplest way is to record a macro (check chap. 4.10.1) that exports data from your planes into ASCII format with automatic file naming, and run it periodically into "Calculation activities".

IvanCFD May 17, 2010 04:40

Hi Dragos,

thanks a lot for that post, you explained just what I need. I've checked the sections you has recommended me and they look promising.

In section 40.10.1 the creation of transcript is explained. It says that between "start transcript" and "end transcript" everything that is done is recorder. I'm wondering if Fluent executes that transcript after every time step.

By the way, I can't find anything named as "Calculation activities" on Chapter 4.

I'll have a got up to what I've understand and let you know.

Thanks a lot,

Ivan.

dmoroian May 17, 2010 05:15

Quote:

Originally Posted by IvanCFD (Post 259046)
...
I'm wondering if Fluent executes that transcript after every time step.

No it does not execute the transcript unless you tell it to. There are several ways to tell fluent to run a script:
1. In the GUI, chose from the menu: File->Read->Scheme or File->Read->Journal
This will run once the chosen script
2. In the GUI, chose from menu: Solve->Calculation Activities...
Here you can specify one or several scripts to be run periodically, on an iteration or time step basis. In version 6.3 the item "Calculation Activities..." is called "Execute Commands...".
3. In the TUI you can do the same thing as in above, both periodically and one time, but I let you the challenge to find out how.

Quote:

By the way, I can't find anything named as "Calculation activities" on Chapter 4.
You probably have a fluent release 6.3, then instead of "Calculation Activities..." try "Execute Commands..."

Dragos

IvanCFD May 17, 2010 05:43

I see.

I know about the existence of Execute Commands. Actually, before you told me your solution, I was trying to create macros through the Execute Command window.

Unfortunately, I don't know what I do wrong but when I create a macro, it just doesn't want to run.

OK, following your instructions, which I've liked much, once I open the Execute Command window, what sort of command do I have to type to call the script just created?

I've been surfing on the Internet looking for some examples, but no luck.

I did a silly thing - typing in the command field the name of the file that contains my transcript, but it just didn't work.

By the way, the file auto-naming works fine.

Looking forward to hearing from you.

Ivan.

louiza May 17, 2010 05:51

two energy equation
 
Hi

I try to modeled arc burning discharge, and i didn't know how to introduce two temperature or energy equation, one for electrons and for heavey species.
if you have any suggestion answer me.
Thant's
louiza

dmoroian May 17, 2010 06:13

To Ivan:
If you check the help page for the "Execute Commands" dialog box, you'll find out that it can run commands defined using the button "Define Macro.." or text commands. In your case, the command should be something like:
Code:

  /file/read-macros Ivan_macro.scm

To Louiza:
Hi Louiza, please respect a bit of discipline on the threads. If you stump like this on a thrread with a completely different subject, and that is not finished, you will just annoy the participants.
As a suggestion for the future: if you have a question that was not asked before, put the question in a new thread or one that is related to it.

IvanCFD May 17, 2010 10:05

3 Attachment(s)
Hi Dragos,

thanks a lot for that info.

I tried what you said and didn't work because for some reason Fluent couldn't identify my transcript file as a macro one.

Therefore I created a journal (file attached) the same way you've told me to create a transcript, and then I specified its execution through Execute Commands (file attached).

Unfortunately, when I run the simulatio and it passes from one time step to the following it gives an error message (file attached).

Strangely, when I click 'ok' on the error message, the simulation continues (it doesn't do it until I hit the 'ok') and if I cancel iterating Fluent just blows away and disappear.

I have saved the journal file in the same folder where the .cas and .dat files are and when exporting the ASCII files they also should be stored in the same folder (see journal file).

I don't know what I'm doing badly...

dmoroian May 17, 2010 14:03

You'll have to experiment with this, but for the moment try changing:
Code:

(cx-gui-do cx-set-text-entry "Select File*FilterText" "e:\3_re_fluent_with_actuator\active\1hz\\*")
(cx-gui-do cx-activate-item "Select File*Apply")
(cx-gui-do cx-set-text-entry "Select File*Text" "x1_%6t.dat")
(cx-gui-do cx-activate-item "Select File*OK")

with:

Code:

(cx-gui-do cx-set-text-entry "Select File*FilterText" "e:\3_re_fluent_with_actuator\active\1hz\*")
(cx-gui-do cx-set-text-entry "Select File*Text" "x1_%6t.dat")
(cx-gui-do cx-activate-item "Select File*OK")


IvanCFD May 18, 2010 08:37

3 Attachment(s)
Hi Dragos,

thanks it works. Well, it works half-way...

At least I don't get that error any more. However, it doesn't behave as expected for 2 reasons:

1) Even though in the journal is clearly said (see attached file) that the data as to be saved here:

E:\3_RE_FLUENT_WITH_ACTUATOR\ACTIVE\1Hz\DATA_OUTPU T

it saves here:

E:\3_RE_FLUENT_WITH_ACTUATOR\ACTIVE\1Hz

(see attached picture)

2) Once Fluent saves the data and go for the next time step, the programme crashes due to out of memory (see attached picture).

This is curious because before, when I wasn't running the journal (and therefore not saving data files), Fluent kept working normally from one step to ther next one, over and over, without complaining about out of memory.

Do you have any clue?

Thanks a lot.

Ivan.

dmoroian May 19, 2010 03:02

/file/export ascii data_output/bubu.txt 13 () no pressure () no
 
Here come some comments:
1. The "Apply" line should not be removed (although it was my previous suggestion). This should fix the path for the output data.
2. In the picture you present there is a last command involving the stop of macro recording, which should not be there (and your archive doesn't contain it). I suspect this may be the cause of fluent crash (although it shouldn't).
3. I think it is time for you to go further and try the TUI instead of GUI. The whole script should be:
Code:

/file/export ascii data_output/bubu.txt 13 () no pressure () no
You can run the above command directly in the text interface, or include it in a file called e.g. "tui.jou" and run it in the text interface or "Execute Commands..." with "file rj tui.jou".
This is just a starting point, and I'm sure you can take it from here.

IvanCFD May 19, 2010 05:18

Hi Dragos,

thanks for your comments.

There's something weird going on... As you say, on Fluent's screenshot it is said:

> (cx-gui-do cx-activate-item "Export*PanelButtons*PushButton2(Cancel)")
> (cx-gui-do cx-activate-item "MenuBar*WriteSubMenu*Stop Journal")


However,the actual journal file just contains:

(cx-gui-do cx-activate-item "MenuBar*FileMenu*Export...")
(cx-gui-do cx-set-toggle-button "Export*Frame1*Table1*Frame8(Delimiter)*ToggleBox8 (Delimiter)*Space" #f)
(cx-gui-do cx-activate-item "Export*Frame1*Table1*Frame8(Delimiter)*ToggleBox8 (Delimiter)*Space")
(cx-gui-do cx-set-list-selections "Export*Frame1*Table1*Frame2*List2(Surfaces)" '( 13))
(cx-gui-do cx-activate-item "Export*Frame1*Table1*Frame2*List2(Surfaces)")
(cx-gui-do cx-activate-item "Export*PanelButtons*PushButton1(OK)")
(cx-gui-do cx-set-text-entry "Select File*FilterText" "e:\3_re_fluent_with_actuator\active\1hz\data_outp ut\\*")
(cx-gui-do cx-set-text-entry "Select File*Text" "x1_%6t.dat")
(cx-gui-do cx-activate-item "Select File*OK")


Therefore, there's nothing in the journal file related to a previous version of the journal file. But I can guarantee you that I smashed the former journal file.

Besides, Fluent complains about malloc out of memory...

:confused:

dmoroian May 19, 2010 06:12

Most likely you run a journal file that is different from what you think it has inside. Did you try my version of script?

IvanCFD May 19, 2010 06:38

Hi,

I've checked many times that what there is in that journal file is what I want Fluent to pick up...

What I'm gonna do is to smash both the .cas and .dat files and start over. I'll even delete the folder where they're located.

I haven't run your script because I don't understand the meaning of
13 () no pressure () no
I'll let you know where I end up.

dmoroian May 19, 2010 07:25

Quote:

Originally Posted by IvanCFD (Post 259442)
Hi,

I've checked many times that what there is in that journal file is what I want Fluent to pick up...

What I'm gonna do is to smash both the .cas and .dat files and start over. I'll even delete the folder where they're located.

I haven't run your script because I don't understand the meaning of
13 () no pressure () no
I'll let you know where I end up.

Before you continue with your gui script, try to type in the text interface:
Code:

/file/export
then you will understand the meaning of the entire command from above.
The GUI record macro was just a pedagogical exercise.

IvanCFD May 19, 2010 09:58

2 Attachment(s)
I know what you mean.

Well it doesn't seem to work either.

I've created the journal file attached to this post, following your instructions ad you'll be able to see. However, I keep getting the same error message related to out of malloc memory (see picture attached).

On the other hand, just to see if that malloc memory issue could be solved somehow, I'm running a single precision simulation based on the same case and it seems to work.

I don't know what else I can do.

Do you have idea how many extra iterations per time step I have to run compared to a double precision case?

Cheers,

Ivan.

dmoroian May 19, 2010 11:36

The journal file looks ok, at first glance. Most likely there is something wrong with the case file.
You could ask fluent support for that error.
I don't think it matters how many iterations you run in single precision, if both calculations are converged, the double precision should always be more accurate. However, the difference may sometimes be insignificant.

DarrenC March 8, 2011 08:28

HI dmoroian

I am having a slightly different problem and I was wondering if you know of any other way around it. I need to monitor approximately 5000 points in my simulation per time step.

1.Surface point monitors do not work as they crash due to too many individual points

2. I tried file/transient-export TUI, this works in my PC. But when I load the simulation into a cluster, it does not give me the option to write it into 'ascii' format. Further investigation points out that Fluent Parallel dosent support transient-export in 'ascii' format.

Do you have any idea how else I can monitor so many individual points??

Thanks in advance.

dmoroian March 9, 2011 04:13

Code:

void mapCell(real *x, cell_t *cell, Thread **thread)
{
  Domain *d = Get_Domain(1);
  Thread *t;
  cell_t c;
  real centroid[ND_ND];
  real dist2[ND_ND];
  real min = 1.0e6;

  thread_loop_c(t,d)
  {
      begin_c_loop(c,t)
      {
        C_CENTROID(centroid,c,t);
        NV_VV(dist2,=,centroid,-,x);
        if (min > NV_MAG2(dist2))
        {
            min = NV_MAG2(dist2);
            *cell = c;
            *thread = t;
        }
      }
  }
}

DEFINE_EXECUTE_AT_END(bubu)
{
  static cell_c *mapCells = NULL;
  static Thread **mapThreads = NULL;
  static real points[5000][3] = {{0,0,0},{1,1,1}......};/*this is the vector defining the monitoring points*/
  int i;
  char name[100];
 
  if(NULL == (mapCells = (cell_c*)calloc(5000,sizeof(cell_c))))
      Error("Could not allocate the memory!\n");
  if(NULL == (mapThreads = (Thread**)calloc(5000,sizeof(Thread*))))
      Error("Could not allocate the memory!\n");
 
  for(i = 0; i < 5000; i++)
  {
      mapCell(points[i], &mapCells[i], &mapThreads[i]);
      sprintf(name,"m-%05d.out",i);
      pf = fopen(name,"a");
      fprintf(pf,"%f\n",C_T(mapCells[i],mapThreads[i]));
      fclose(pf);
  } 
}

I didn't know about the limitation with the high number of monitors. So here it is an example using an udf.
Take the above code as it is "just an example". I did not try it, it is not optimized, nor it correctly works in parallel.
Basically it finds the corresponding cell for each monitor and prints out the temperature in a separate file.

I hope this is helpful!

ian.maes October 16, 2012 04:23

Hi,

thank you for providing this example here!
Can I ask you 2 questions about it?
- How do you choose the value of 'min'? 1.0e6 seems like a very big value!
- Is it necessary to retreive the cell location and thread (filled in by mapmyCell) every time-step, or could it be possible to do this upon loading?

Thank you in advance,

Kind regards,

Ian

dmoroian October 16, 2012 15:44

Quote:

Originally Posted by ian.maes (Post 386819)
Hi,
- How do you choose the value of 'min'? 1.0e6 seems like a very big value!

The chosen value ensures that I will find at least one cell.

Quote:

- Is it necessary to retreive the cell location and thread (filled in by mapmyCell) every time-step, or could it be possible to do this upon loading?
All three arrays are declared as "static", so if you fill them once, they will keep their values as long as the udf is loaded into memory.

ian.maes October 18, 2012 04:58

Hi dmoroian,

Thanks for the answers!
This is the code that works, where the coordinates of a line across my domain are read in from xcord.txt.

Code:

#include "udf.h"
static real points[56][3];

DEFINE_EXECUTE_ON_LOADING(print_line,libname)
{
  int m1, m2, i, j;
  FILE *fin;
  m1=56;
  m2=3;
  fin=fopen("xcord.txt","r");
  for (i=0;i<m1;i++)
  {        for (j=0;j<m2;j++)
                fscanf(fin,"%lf\n",&points[i][j]);
  }
  fclose(fin);
  Message ("points is loaded!\n");
}

 
void mapCell(real *x, cell_t *cell, Thread **thread)
{
  Domain *d = Get_Domain(1);
  Thread *t;
  cell_t c;
  real centroid[ND_ND];
  real dist2[ND_ND];
  real min = 1.0e6;

  thread_loop_c(t,d)
  {
      begin_c_loop(c,t)
      {
        C_CENTROID(centroid,c,t);
        NV_VV(dist2,=,centroid,-,x);
        if (min > NV_MAG2(dist2))
        {
            min = NV_MAG2(dist2);
            *cell = c;
            *thread = t;
        }
      }
  end_c_loop(c,t)
  }
}

DEFINE_EXECUTE_AT_END(bubi)
{
  static cell_t *mapCells = NULL;
  static Thread **mapThreads = NULL;
  int i;
  FILE *pf;
 
  if(NULL == (mapCells = (cell_t*)calloc(56,sizeof(cell_t))))
      Error("Could not allocate the memory!\n");
  if(NULL == (mapThreads = (Thread**)calloc(56,sizeof(Thread*))))
      Error("Could not allocate the memory!\n");
 
  if(NULL == (pf = fopen("Ux.txt","a")))
      Error("Could not open file!\n");

  for(i = 0; i < 56; i++)
  {
      mapCell(points[i], &mapCells[i], &mapThreads[i]);
      fprintf(pf,"%f\t",C_T(mapCells[i],mapThreads[i]));
  }
  fprintf(pf,"\n");
  fclose(pf);
}

This works for a serial case, but when I run my case with this code on parallel cores, I get the following error at the end of the first time-step:

Code:

==============================================================================
Stack backtrace generated for node id 999999 (pid = 26808) on signal 11 :
/opt/Fluent13.0.0/ansys_inc/v130/fluent/fluent13.0.0/lnamd64/3ddp_host/fluent.13.0.0[0x129da24]
/opt/Fluent13.0.0/ansys_inc/v130/fluent/fluent13.0.0/lnamd64/3ddp_host/fluent.13.0.0[0x129e7a8]
/lib64/libpthread.so.0[0x37ffa0f500]
libudf/lnamd64/3ddp_host/libudf.so(bubi+0xcb)[0x7f39bd7a1876]
Check the file fluenterror.log for details.
Please include this information with any bug report you file on this issue!
==============================================================================

Can anyone give some suggestions on the origin of this problem and how I can get this to work on a parallel platform, please?

Thank you!

Ian

dmoroian October 18, 2012 08:03

Input/Ouput in parallel is not trivial, and certainly doesn't work straight from the serial implementation.
You'll have to look at the Fluent UDF Manual, chapter 7 "Parallel Considerations" for some more details.
There is a sample of udf debugging on cfd-online wiki: http://www.cfd-online.com/Wiki/Fluen..._udf_using_gdb

A.L.Verminburger June 29, 2013 15:14

Quote:

Originally Posted by dmoroian (Post 258867)
Hi Ivan,
Check chapter 4.1.7 in the user manual for automatic numbering of files, and 4.13 for exporting solution data (I think you're interested in the ASCII format).
The simplest way is to record a macro (check chap. 4.10.1) that exports data from your planes into ASCII format with automatic file naming, and run it periodically into "Calculation activities".

Hi Dragos,

I added the -%t for automated data export at each time step, but it seems to export only once filename-0000 and stops. Do I need to include some sort of a loop structure?

I am using:
Code:

file/export/ascii directory/filename-%t surface () no air-vof () yes
Thanks,
Alfred

dmoroian June 29, 2013 15:52

I would use the command within "execute-commands" and run it periodically every time-step or every iteration.

A.L.Verminburger June 29, 2013 16:44

Quote:

Originally Posted by dmoroian (Post 436808)
I would use the command within "execute-commands" and run it periodically every time-step or every iteration.

Worked like a charm. Thank you, Dragos.

Future reference for others. The full syntax is:
Code:

/solve/execute-commands/add-edit command-1 1 "time-step" "file/export/ascii directory/filename-%t surface () no parameter () yes"

pranab_jha July 17, 2013 09:15

UDF time step in file name
 
Hello friends,

On a related topic, I have been having trouble with saving files from a UDF every n time steps, while running Fluent in parallel in batch mode. Fluent does not allow me to save files in ascii format in parallel mode, so I chose to go with a UDF instead. I found part of the UDF online and from the Fluent manual and have modified the rest to suit my purpose.

Without the time part (between /*** ... ***/) the UDF runs well and gives me the output in desired format. But I want to add a timestep to my filename so that every time step, I have a new file. This does not work. My guess is that the time data is stored somewhere else, while I am trying to get it back from the host.

If you can spare a few minutes, it would be of great help.
Thanks.

Below is the UDF:

#include "udf.h"

#define FNAME "datafile"
#define TSTEP(t) (t % 2)

DEFINE_EXECUTE_AT_END(dod_writer)
{
FILE* fp;

#if !RP_HOST
int cell_counter = 0, dummy, len;
double pressure, cell_center[ND_ND] ;
Domain *d;
Thread *t;
cell_t c;
d = Get_Domain(1); /* Get the domain using Fluent utility */

#else
/***************************
int cur_ts = RP_Get_Integer("time-step");
char str1[] = "file-";
char str2[] = ".dat";

strcat (str1, cur_ts);
strcat (str1, str2);
len = strlen(str1);

Message("\n 1. current time step = %d, name = %s \n", cur_ts, str1);

/* Send time-step and filename to all nodes */
node_to_host_int_1(cur_ts);
host_to_node_string(str1,len); /* remember terminating NUL character ***************************************/
#endif

#if RP_NODE
if(!I_AM_NODE_ZERO_P)PRF_CRECV_INT(myid-1,&dummy,1,myid-1);
fp = fopen(filename,(I_AM_NODE_ZERO_P?"w":"a"));
#else
fp = fopen(filename,"w");
#endif /* for RP_NODE*/

#if !RP_NODE
if (fp!=NULL)
{
Message("\nThe file opened in the working directory \n");
}
else
{
Message("Error in opening file \n");
}
#endif /* for !RP_NODE*/

#if RP_NODE
fprintf(fp,"cell-number X-cord Y-cord Z-cord Pressure");
#endif

#if !RP_HOST
thread_loop_c(t,d)
{
/*Message0("starting the loopn");*/
begin_c_loop_int(c,t)
{
cell_counter++;
C_CENTROID(cell_center,c,t);
pressure=C_P(c,t);

#if RP_2D
fprintf(fp,"n %d %10.3e %10.3e %10.3e",cell_counter, cell_center[0], cell_center[1], pressure);
#else
fprintf(fp,"n %d %10.3e %10.3e %10.3e %10.3e",cell_counter, cell_center[0], cell_center[1], cell_center[2], pressure);
#endif
}
end_c_loop_int(c,t)
}
#endif /* for !RP_HOST*/

#if RP_NODE
fclose(fp);
if(!I_AM_NODE_LAST_P)PRF_CSEND_INT(myid+1,&dummy,1 ,myid);
#else
fclose(fp);
Message("\n The loop ends\n");
#endif /* for RP_NODE*/
}

dmoroian July 17, 2013 14:03

Stack overflow
 
This is a classical example of stack overflow programming error:
Code:

char str1[] = "file-";
char str2[] = ".dat";

strcat (str1, cur_ts);
strcat (str1, str2);

You allocate 6 bytes on the stack for str1, then put a lot more (the content of cur_ts and str2), overwriting some extra memory that most likely contains the code of your function. This generates a random behavior usually ending with a null pointer assignment or segmentation fault.
To solve the problem, just allocate enough memory in str1:
Code:

char str1[200];
sprintf(str1,"file-%d.dat",cur_ts);



All times are GMT -4. The time now is 10:06.