logging results of a user defined function that uses a subset of the population as input

20 views
Skip to first unread message

font...@gmail.com

unread,
May 7, 2024, 11:19:15 AMMay 7
to slim-discuss
Hello Ben and all.

I have an user defined function in my simulation:

function (float)Ne_Het(o sampley)

{

pi = calcHeterozygosity(sampley.genomes);

return pi / (4 * 1e-7);

}


where sampley is a object vector that I plan on defining as

 

sampley = sample (p1.individuals, asInteger(p1.individualCount/CONST);


where CONST is a constant that defines the proportion of the subset of the population.


I am planning on defining a custom column in a log file for this result:


1 early() {

sim.addSubpop("p1", 10);

log = community.createLogFile("TESTLOGCSV.csv");

log.addCycle();

log.addSubpopulationSize(p1);

log.addCustomColumn("sampley_ne", "Ne_Het(sampley);");

log.logRow();

}


My idea was to have this log csv to receive outputs later on by adding a log.logRow() in the ticks that I need. But I also want this csv to be started on tick 1 (as above).


It has not worked for me.


If I comment out log.logRow();, the simulation runs, but no log output (as expected).


When I leave it there, it says:

ERROR (EidosSymbolTable::_GetValue): undefined identifier sampley.


Then I tried to generate sampley with it:


1 early() {

sim.addSubpop("p1", 10);

sampley = sample(p1.individuals, asInteger(p1.individualCount/CONST));

log = community.createLogFile("TESTLOGCSV.csv");

log.addCycle();

log.addSubpopulationSize(p1);

log.addCustomColumn("sampley_ne", "Ne_Het(sampley);");

log.logRow();


which also doesn't work. I get the same undefined identifier (if I comment log.logRow(), it runs but the log is not created properly)


When I try to create sampley as a global constant (defineGlobal), SLiM/EIDOS tell me it can't because we are dealing with individuals.


Ideally, I would like to generate the "empty" log on  1 early() then log the rows at 1: late() of further ticks.


So what could be a solution here? I've tried with optional arguments for the function (using []) but also no good.


This works fine when I don't try to subset the population (use p1 as the argument for sampley in the function).


It is fine for sampley to be defined every generation or when I need it to be logged, but I am trying to generate a sampley object that will be the same for the log and for a vcf output (e.g. sampley.genomes.outputVCF() )


Thanks


JP









Ben Haller

unread,
May 7, 2024, 12:23:03 PMMay 7
to font...@gmail.com, slim-discuss
Hi JP!

Yes, because individuals are ephemeral and might be deallocated by SLiM, you can't keep a permanent reference to them.  SLiM/Eidos prevent you from doing anything that might lead to a stale reference to a deallocated object.

There are two approaches you could take here:

(1) Turn on pedigree tracking with initializeSLiMOptions(), then use the pedigreeID of the individuals to track them (remember ing a vector of pedigree IDs, rather than individuals, using defineGlobal for example), and use the Species method individualsWithPedigreeIDs() to look up individuals from their ids; or,

(2) use the addSuppliedColumn() method of LogFile, which is really designed for this sort of thing and probably is the simpler/cleaner solution here.  Just add "sampley_ne" as a supplied column, and then call setSuppliedValue() to give the value for that column before calling logRow().  See the addSuppliedColumn() doc.

Let me know if you need more help, but it seems like you're far enough down the road that this answer will probably make sense to you.  :->  Happy modeling!

Cheers,
-B.

Benjamin C. Haller
Messer Lab
Cornell University


font...@gmail.com wrote on 5/7/24 5:19 PM:
--
SLiM forward genetic simulation: http://messerlab.org/slim/
---
You received this message because you are subscribed to the Google Groups "slim-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to slim-discuss...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/slim-discuss/803b5c54-83ba-4cf5-a595-ee13f4c0a334n%40googlegroups.com.

Ben Haller

unread,
May 9, 2024, 1:09:31 AMMay 9
to João Pedro Fontenelle, slim-discuss
Hi JP!  You could (a) use a counter to generate the column's value in ticks when auto-logging will use it, (b) just generate the column's value in every tick, if that is not too time-consuming, and auto-logging will pick it up when it fires (otherwise the generated value will just go unused), or (c) switch from auto-logging to calling logRow() yourself, which is what I thought you were doing.  :->  Any of those ought to work, I think; up to you.


Cheers,
-B.

Benjamin C. Haller
Messer Lab
Cornell University


João Pedro Fontenelle wrote on 5/8/24 9:48 PM:
Hi Ben,

Thanks for the reply.

Indeed, the addSuppliedColumn() / setSuppliedValue() approach seems to fit what I am looking for. Thanks!

However, and I believe this is expected, this approach doesn't seem to work with .setLogInterval() for automatic logging, right?

Is there an alternative or it will be the case of creating a counter variable that will force the output once the counter reached the log interval I need?

Thanks!

JP
--

_______{: }---'-

João Pedro Fontenelle, PhD

OG-CO Postdoctoral Fellow in Genome Data Science


João Pedro Fontenelle

unread,
May 10, 2024, 1:53:21 AMMay 10
to Ben Haller, slim-discuss
Hi Ben,

Thanks for the reply.

Indeed, the addSuppliedColumn() / setSuppliedValue() approach seems to fit what I am looking for. Thanks!

However, and I believe this is expected, this approach doesn't seem to work with .setLogInterval() for automatic logging, right?

Is there an alternative or it will be the case of creating a counter variable that will force the output once the counter reached the log interval I need?

Thanks!

JP

On Tue, May 7, 2024 at 12:23 PM Ben Haller <bha...@mac.com> wrote:

Ben Haller

unread,
May 10, 2024, 2:02:17 AMMay 10
to slim-discuss
Hi João,

Here is a minimal example of using addSuppliedColumn() with automatic logging, by setting the supplied value in each tick:

initialize() {

}

1 early() {

log = community.createLogFile("~/Desktop/log.txt", logInterval=10);

log.addTick();

log.addSuppliedColumn("foo");

defineConstant("LOG", log);

}

late() {

LOG.setSuppliedValue("foo", community.tick * 2);

}

2000 late() { }


It works fine, as long as calculating the supplied value is not too time-consuming.  If it is, then you'd probably want to calculate/set it only in those ticks when auto-logging will actually use it.

Cheers,
-B.

Benjamin C. Haller
Messer Lab
Cornell University

Reply all
Reply to author
Forward
0 new messages