Calling Vensim from External Function

Use this forum to post Vensim related questions.
Post Reply
busquim
Junior Member
Posts: 10
Joined: Fri Aug 29, 2008 5:29 pm

Calling Vensim from External Function

Post by busquim »

Hi, I am working with a vensim model (i.e. model1) that must call another vensim model (i.e. model2). At each time step, model1 sends a vector to model2, model2 runs from 1 to 100 and then returns a set of values. I need to analyze the returned values to find the best among all of them (kind of brute force search). Is there a simple way to have a Vensim model calling another Vensim model, or should I use an external function inside model1 that calls model2? Thanks, any help will be great.
bob@vensim.com
Senior Member
Posts: 1107
Joined: Wed Mar 12, 2003 2:46 pm

Post by bob@vensim.com »

To get one Vensim model to call another you will need to use an external function that in turn calls the Vensim DLL. Be sure the models are in different directories so there is no conflict on files.
busquim
Junior Member
Posts: 10
Joined: Fri Aug 29, 2008 5:29 pm

Post by busquim »

OK, thank you Bob.

I've found two examples, vddext.xls and ddeserv.xls, that are working fine, but I don't know how to call vensim from vensim using visual c++ -- I've been playing with few different external function in c++ that are working fine.

To have a simple example that works, and learn how to do it, I would like to have two random numbers being generate in model1.mdl, be able to pass them to model2.mdl, do few calculations (could be the sum of them integrated over time to start), and them have the result back to model1.mdl (in fact, I will have few vectors being passed to model2.mdl, and a vector as return).

My questions is:

Should I call model2.mdl in the vdde_initiate (at VENEXT.C), or should I load the model, run it and stop the way you have in DDESEV.XLS?


I've been trying few differents way to do it, but it is not working at all. I am getting the error message: " Stop from Vensim Problems encountered in the simulation"?

Thanks,

Rodney
bob@vensim.com
Senior Member
Posts: 1107
Joined: Wed Mar 12, 2003 2:46 pm

Post by bob@vensim.com »

You won't be able to use the dde functionality for this. Start with venext.c and add a function to this to open a simulate a model. You will need to add vendll32.lib to the link statements for the project.

eg (untested)

double MYSIM(double x)
{
char buf[80] ;
float vals[101] ,times[101] ;
vensim_command("SPECIAL>LOADMODEL|c:\\temp\\mymodel.vpm") ;
vensim_command("SIMULATE>RUNNAME|base") ;
sprintf(buf,"SIMULATE>SETVAL|const=%lg",x) ;
vensim_command(buf) ;
vensim_command("MENU>RUN|O") ;
vensim_get_data("base.vds","outvar","Time",vals,times,101) ;
return vals[100] ;
}
busquim
Junior Member
Posts: 10
Joined: Fri Aug 29, 2008 5:29 pm

Post by busquim »

OK, thanks.

I see why it will not work the way I was doing -- it seems easier than I thought. However, I am trying to add the vendll32.lib to my project, but I keep having the " unresolved external symbol _vensim_get_data referenced in function _MYSIM" error message. Should I add one more .def file also?

Thank you
busquim
Junior Member
Posts: 10
Joined: Fri Aug 29, 2008 5:29 pm

Post by busquim »

Just to let you know: I added vendll32.lib using the visual c++ Property Pages (menu linker / Input / Additional Dependencies).
busquim
Junior Member
Posts: 10
Joined: Fri Aug 29, 2008 5:29 pm

Post by busquim »

Bob, I figured out the problem: I missed the #define EXPORTED_PROC __stdcall :)

Thanks a lot. I let you know if everything works fine later on.

Rodney
busquim
Junior Member
Posts: 10
Joined: Fri Aug 29, 2008 5:29 pm

Post by busquim »

Hi Bob, sorry about asking you more questions, I know that you are busy, but my models are getting a little bit more complicated, and I can't find a solution for the following problem:

I am passing a set of values to a second vensim model (this part is working fine after your help), and I would like to have back all the values of a subscripted variable, i.e., I have the variable output[Subs] where Subs goes from 1 to 100, and I would like to have all values for time=0 to 100. I need to be able to do calculation among the values of the matrix vals[100][101] (or should be vals[101][100] ?) using "for" and " if else" commands.

Is there a way to have back the full matrix for a fully subscripted variable? Again, thanks a lot, I appreciate any help.

Rodney
Administrator
Super Administrator
Posts: 4838
Joined: Wed Mar 05, 2003 3:10 am

Post by Administrator »

You can do this fairly easily.

Take a look at the MATRIX_INVERT function in the Vensim examples.

static FUNC_DESC Flist[] = {
...
{"MATRIX_INVERT"," {matrix} ",1,1,INVERT_FUNC,2,0,0,0},
...

The "2" after the INVERT_FUNC identifier tells Vensim to expect the function to fill in two subscript ranges. So your function might be

static FUNC_DESC Flist[] = {
...
{"MY_FUNC","{passed variables}",1,1,MY_FUNC_FUNC,1,0,0,0},
...

This will tell Vensim to fill in just one subscript range.

Your call might look something like

output[Subs] = MY_FUNC(some vars)

Vensim would only call MY_FUNC once.

Hope this makes sense.

Tony.
bob@vensim.com
Senior Member
Posts: 1107
Joined: Wed Mar 12, 2003 2:46 pm

Post by bob@vensim.com »

In case your question was about the vensim_get_data part of the operation that answer is simpler. Just use something like (assumes subs : (sub 1-sub 100) in Vensim).

float vals[100][101] ;
int subs ;
char varname[80] ;
for(subs=0;subs<100;subs++) {
sprintf(varname,"var[sub %d]",subs+1) ;
vensim_get_data("base.vdf",varname,"Time",vals[sub],times,101) ;
}
busquim
Junior Member
Posts: 10
Joined: Fri Aug 29, 2008 5:29 pm

Post by busquim »

Bob and Tony,

Thanks a lot. I figured out a similar way Bob described and seems that it is working fine -- although I have a lot of work to finish my model, I am happy with the results I am having for simple cases.

Have a great weekend,

Rodney :)
busquim
Junior Member
Posts: 10
Joined: Fri Aug 29, 2008 5:29 pm

Post by busquim »

Hey everyone,

I am almost done with the tools I need to implement the full version of my models, but I am having trouble with the following:

1. I have a vector in my c++ code, i.e. double myvector[101] (at each model1 time step I have a different myvector), that is suppose to be part of a lookup(Time, myvector) at model2;

2. I've tried to set the value of a subscripted variable in model2, input2[TimeT], i.e. fprintf(buf,"SIMULATE>SETVAL|""input2[TimeT]=%lg", myvector); and then, at model2, have the lookup using the VECTOR LOOKUP function;

3. I've tried to set the value of the lookup at model 2, i.e. sprintf(buf,"SIMULATE>SETVAL|mylookup2(time[101],myvector[101])".

None of the above solutions are working. Basically, it runs, but the variables input2 or the lookup2 doesn't change at all in model 2. Also, I have a myfile.txt file (just to help in the development) where I can verify the values that I should be expecting in model2.

Any hint about how to solve this problem?

Thanks a lot,

Rodney
Administrator
Super Administrator
Posts: 4838
Joined: Wed Mar 05, 2003 3:10 am

Post by Administrator »

Can you show us the actual code you are using in step 3?
busquim
Junior Member
Posts: 10
Joined: Fri Aug 29, 2008 5:29 pm

Post by busquim »

Yep, here you have part of the code -- not all of them -- and this tests are for two small models so I can validate the code:

time=VENGV->time;
double myvector[101];
int i;

....

// I start reading values from a file appended in the last time step -- it is from this file that comes the vector that, for simplicity, has 101 terms always.

i=0;
pFile = fopen("myfile.txt", "r" );
while ( fgets( buff, sizeof buff, pFile) != NULL ) {
fscanf(pFile, "%lg", &n);
myvector=n;
i++;
}

...

// I have to send the vector to Model2, get an value back, and then append myfile.txt with that value

vensim_command("SPECIAL>LOADMODEL|Model2.vpm") ;
vensim_command("SIMULATE>RUNNAME|base") ;
sprintf(buf,"SIMULATE>SETVAL|mylookup2((time[101],myvector[101]))") ;
vensim_command(buf) ;
vensim_command("MENU>RUN|O") ;
vensim_get_data("base.vds","output","Time",vals,times,101) ;
return vals[100];

I simulated again. Nothing changes and I don't get an error message.

Basically, I need to set a vector, or a lookup (that is better) in Model2 before it runs.

Thanks,

Rodney
Administrator
Super Administrator
Posts: 4838
Joined: Wed Mar 05, 2003 3:10 am

Post by Administrator »

It looks like you are not passing the lookup correctly.

This Venapp command will not work
"SIMULATE>SETVAL|mylookup2((time[101],myvector[101]))"

But if you create the venapp command like below, it should. You will need to check the command is in the correct format before passing it to Vensim.


int nNumValues = i; //store array size passed from Vensim

//start the venapp command
sprintf(buf,"SIMULATE>SETVAL|mylookup2((%f,%f)",time[0],myvector[0]) ;

char tempstring[20];
for ( i = 0 ; i < nNumValues ; i++ )
{
sprintf(tempstring,",(%f,%f)",time,myvector);
strcat(buf,tempstring);
}

//end the venapp command
strcat(buf,"))");

vensim_command("SPECIAL>LOADMODEL|Model2.vpm") ;
vensim_command("SIMULATE>RUNNAME|base") ;
vensim_command(buf) ;
vensim_command("MENU>RUN|O") ;
vensim_get_data("base.vds","output","Time",vals,times,101) ;
return vals[100];



buf should contain a venapp command something like the following (that you then pass to Vensim)
"SIMULATE>SETVAL|mylookup2((0,1),(1,2),(2,3),(3,4))"
busquim
Junior Member
Posts: 10
Joined: Fri Aug 29, 2008 5:29 pm

Post by busquim »

Thanks, Tony.

In fact, it makes a lot of sense the way you solved the problem. However, I was getting the following error message when running vensim:

Run-Time Check Failure #2 - Stack around the variable ' buf' was corrupted.

So, I changed the size of ' buf' and it is working now.

Again, thank you for your help.

Rodney
Post Reply