Skip to content

Commit e84df49

Browse files
committed
fix #516: support suppression of the LogFile header line
1 parent 83215b3 commit e84df49

6 files changed

Lines changed: 74 additions & 34 deletions

File tree

QtSLiM/help/SLiMHelpClasses.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,12 @@
199199
<p class="p5">verbosity &lt;–&gt; (integer$)</p>
200200
<p class="p6">The verbosity level, for SLiM’s logging of information about the simulation.<span class="Apple-converted-space">  </span>This is <span class="s1">1</span> by default, but can be changed at the command line with the <span class="s1">-l[ong]</span> option.<span class="Apple-converted-space">  </span>It is provided here so that scripts can consult it to govern the level of verbosity of their own output, or set the verbosity level for particular sections of their code.<span class="Apple-converted-space">  </span>A verbosity level of 0 suppresses most of SLiM’s optional output; 2 adds some extra output beyond SLiM’s standard output.</p>
201201
<p class="p2"><i>5.3.2<span class="Apple-converted-space">  </span></i><span class="s1"><i>Community</i></span><i> methods</i></p>
202-
<p class="p5">– (object&lt;LogFile&gt;$)createLogFile(string$ filePath, [Ns initialContents = NULL], [logical$ append = F], [logical$ compress = F], [string$ sep = ","], [Ni$ logInterval = NULL], [Ni$ flushInterval = NULL])</p>
202+
<p class="p5">– (object&lt;LogFile&gt;$)createLogFile(string$ filePath, [Ns initialContents = NULL], [logical$ append = F], [logical$ compress = F], [string$ sep = ","], [Ni$ logInterval = NULL], [Ni$ flushInterval = NULL], [logical$ header = T])</p>
203203
<p class="p6">Creates and returns a new <span class="s1">LogFile</span> object that logs data from the simulation (see the documentation for the <span class="s1">LogFile</span> class for details).<span class="Apple-converted-space">  </span>Logged data will be written to the file at <span class="s1">filePath</span>, overwriting any existing file at that path by default, or appending to it instead if <span class="s1">append</span> is <span class="s1">T</span> (successive rows of the log table will always be appended to the previously written content, of course).<span class="Apple-converted-space">  </span>Before the header line for the log is written out, any <span class="s1">string</span> elements in <span class="s1">initialContents</span> will be written first, separated by newlines, allowing for a user-defined file header.<span class="Apple-converted-space">  </span>If <span class="s1">compress</span> is <span class="s1">T</span>, the contents will be compressed with <span class="s1">zlib</span> as they are written, and the standard <span class="s1">.gz</span> extension for gzip-compressed files will be appended to the filename in <span class="s1">filePath</span> if it is not already present.</p>
204204
<p class="p6">The <span class="s1">sep</span> parameter specifies the separator between data values within a row.<span class="Apple-converted-space">  </span>The default of <span class="s1">","</span> will generate a “comma-separated value” (CSV) file, while passing <span class="s1">sep="\t"</span> will use a tab separator instead to generate a “tab-separated value” (TSV) file.<span class="Apple-converted-space">  </span>Other values for <span class="s1">sep</span> may also be used, but are less standard.</p>
205205
<p class="p6">LogTable supports periodic automatic logging of a new row of data, enabled by supplying a non-<span class="s1">NULL</span> value for <span class="s1">logInterval</span>.<span class="Apple-converted-space">  </span>In this case, a new row will be logged (as if <span class="s1">logRow()</span> were called on the <span class="s1">LogFile</span>) at the end of every <span class="s1">logInterval</span> ticks (just before the tick counter increments, in both WF and nonWF models), starting at the end of the tick in which the <span class="s1">LogFile</span> was created.<span class="Apple-converted-space">  </span>A <span class="s1">logInterval</span> of <span class="s1">1</span> will cause automatic logging at the end of every tick, whereas a <span class="s1">logInterval</span> of <span class="s1">NULL</span> disables automatic logging.<span class="Apple-converted-space">  </span>Automatic logging can always be disabled or reconfigured later with the <span class="s1">LogFile</span> method <span class="s1">setLogInterval()</span>, or logging can be triggered manually by calling <span class="s1">logRow()</span>.</p>
206206
<p class="p6">When compression is enabled, <span class="s1">LogFile</span> flushes new data lazily by default, for performance reasons, buffering data for multiple rows before writing to disk.<span class="Apple-converted-space">  </span>Passing a non-<span class="s1">NULL</span> value for <span class="s1">flushInterval</span> requests a flush every <span class="s1">flushInterval</span> rows (with a value of <span class="s1">1</span> providing unbuffered operation).<span class="Apple-converted-space">  </span>Note that flushing very frequently will likely result in both lower performance and a larger final file size (in one simple test, <span class="s1">48943</span> bytes instead of <span class="s1">4280</span> bytes, or more than a 10× increase in size).<span class="Apple-converted-space">  </span>Alternatively, passing a very large value for <span class="s1">flushInterval</span> will effectively disable automatic flushing, except at the end of the simulation (but be aware that this may use a large amount of memory for large log files).<span class="Apple-converted-space">  </span>In any case, the log file will be created immediately, with its requested initial contents; the initial write is not buffered.<span class="Apple-converted-space">  </span>When compression is not enabled, the <span class="s1">flushInterval</span> setting is ignored.</p>
207+
<p class="p6">The <span class="s1">header</span> parameter controls whether a header line is written out at the beginning of logging.<span class="Apple-converted-space">  </span>If it is <span class="s1">T</span> (the default), a header line is written out; if <span class="s1">F</span>, no header is written.<span class="Apple-converted-space">  </span>Suppressing the header output can be useful if you are using <span class="s1">LogFile</span> to append data to an existing file that already has a header line.</p>
207208
<p class="p6">The <span class="s1">LogFile</span> documentation discusses how to configure and use <span class="s1">LogFile</span> to write out the data you are interested in from your simulation.</p>
208209
<p class="p5">– (integer$)estimatedLastTick(void)</p>
209210
<p class="p6">Returns SLiM’s current estimate of the last tick in which the model will execute.<span class="Apple-converted-space">  </span>Because script blocks can be added, removed, and rescheduled, and because the simulation may end prematurely (due to a call to <span class="s1">simulationFinished()</span>, for example), this is only an estimate, and may change over time.</p>
@@ -651,8 +652,8 @@
651652
<p class="p6">You can get the <span class="s1">LogFile</span> instance, in order to call <span class="s1">logRow()</span> on it, from <span class="s1">community.logFiles</span>, or you can remember it in a global constant with <span class="s1">defineConstant()</span>.</p>
652653
<p class="p5">– (void)setLogInterval([Ni$ logInterval = NULL])</p>
653654
<p class="p6">Sets the automatic logging interval.<span class="Apple-converted-space">  </span>A <span class="s1">logInterval</span> of <span class="s1">NULL</span> stops automatic logging immediately.<span class="Apple-converted-space">  </span>Other values request that a new row should be logged (as if <span class="s1">logRow()</span> were called) at the end of every <span class="s1">logInterval</span> ticks (just before the tick count increment, in both WF and nonWF models), starting at the end of the tick in which <span class="s1">setLogInterval()</span> was called.</p>
654-
<p class="p5">– (void)setFilePath(string$ filePath, [Ns initialContents = NULL], [logical$ append = F], [Nl$ compress = NULL], [Ns$ sep = NULL])</p>
655-
<p class="p6">Redirects the <span class="s1">LogFile</span> to write new rows to a new <span class="s1">filePath</span>.<span class="Apple-converted-space">  </span>Any rows that have been buffered but not flushed will be written to the previous file first, as if <span class="s1">flush()</span> had been called.<span class="Apple-converted-space">  </span>With this call, new <span class="s1">initialContents</span> may be supplied, which will either replace any existing file or will be appended to it, depending upon the value of <span class="s1">append</span>.<span class="Apple-converted-space">  </span>New values may be supplied for <span class="s1">compress</span> and <span class="s1">sep</span>; the meaning of these parameters is identical to their meaning in <span class="s1">createLogFile()</span>, except that a value of <span class="s1">NULL</span> for these means “do not change this setting from its previous value”.<span class="Apple-converted-space">  </span>In effect, then, this method lets you start a completely new log file at a new path, without having to create and configure a new <span class="s1">LogFile</span> object.<span class="Apple-converted-space">  </span>The new file will be created (or appended) synchronously, with the specified initial contents.</p>
655+
<p class="p5">– (void)setFilePath(string$ filePath, [Ns initialContents = NULL], [logical$ append = F], [Nl$ compress = NULL], [Ns$ sep = NULL], [Nl$ header = NULL])</p>
656+
<p class="p6">Redirects the <span class="s1">LogFile</span> to write new rows to a new <span class="s1">filePath</span>.<span class="Apple-converted-space">  </span>Any rows that have been buffered but not flushed will be written to the previous file first, as if <span class="s1">flush()</span> had been called.<span class="Apple-converted-space">  </span>With this call, new <span class="s1">initialContents</span> may be supplied, which will either replace any existing file or will be appended to it, depending upon the value of <span class="s1">append</span>.<span class="Apple-converted-space">  </span>New values may be supplied for <span class="s1">compress</span>, <span class="s1">sep</span>, and <span class="s1">header</span>; the meaning of these parameters is identical to their meaning in <span class="s1">createLogFile()</span>, except that a value of <span class="s1">NULL</span> for these means “do not change this setting from its previous value”.<span class="Apple-converted-space">  </span>In effect, then, this method lets you start a completely new log file at a new path, without having to create and configure a new <span class="s1">LogFile</span> object.<span class="Apple-converted-space">  </span>The new file will be created (or appended) synchronously, with the specified initial contents.</p>
656657
<p class="p5">– (void)setSuppliedValue(string$ columnName, +$ value)</p>
657658
<p class="p6">Registers a value, passed in <span class="s1">value</span>, to be used for the supplied column named <span class="s1">columnName</span> when a row is next logged.<span class="Apple-converted-space">  </span>This column must have been added with <span class="s1">addSuppliedColumn()</span>.<span class="Apple-converted-space">  </span>A value of <span class="s1">NULL</span> may be passed to log <span class="s1">NA</span>, but logging <span class="s1">NA</span> is the default behavior for supplied columns in any case.<span class="Apple-converted-space">  </span>Otherwise, the value must be a singleton, and its type should match the values previously supplied for the column (otherwise the log file may be difficult to parse, since the values within the column will not be of one consistent type).<span class="Apple-converted-space">  </span>See <span class="s1">addSuppliedColumn()</span> for further details.</p>
658659
<p class="p5">– (void)setValue(is$ key, * value)</p>

SLiMgui/SLiMHelpClasses.rtf

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,7 @@ The type of model being simulated, as specified in
10601060
\f1\fs22 methods\
10611061
\pard\pardeftab529\li720\fi-446\ri720\sb180\sa60\partightenfactor0
10621062

1063-
\f3\i0\fs18 \cf2 \'96\'a0(object<LogFile>$)createLogFile(string$\'a0filePath, [Ns\'a0initialContents\'a0=\'a0NULL], [logical$\'a0append\'a0=\'a0F], [logical$\'a0compress\'a0=\'a0F], [string$\'a0sep\'a0=\'a0","], [Ni$\'a0logInterval\'a0=\'a0NULL], [Ni$\'a0flushInterval\'a0=\'a0NULL])\
1063+
\f3\i0\fs18 \cf2 \'96\'a0(object<LogFile>$)createLogFile(string$\'a0filePath, [Ns\'a0initialContents\'a0=\'a0NULL], [logical$\'a0append\'a0=\'a0F], [logical$\'a0compress\'a0=\'a0F], [string$\'a0sep\'a0=\'a0","], [Ni$\'a0logInterval\'a0=\'a0NULL], [Ni$\'a0flushInterval\'a0=\'a0NULL], [logical$\'a0header\'a0=\'a0T])\
10641064
\pard\pardeftab720\li547\ri720\sb60\sa60\partightenfactor0
10651065

10661066
\f4\fs20 \cf2 Creates and returns a new
@@ -1144,6 +1144,15 @@ When compression is enabled,
11441144
\f3\fs18 flushInterval
11451145
\f4\fs20 setting is ignored.\
11461146
The
1147+
\f3\fs18 header
1148+
\f4\fs20 parameter controls whether a header line is written out at the beginning of logging. If it is
1149+
\f3\fs18 T
1150+
\f4\fs20 (the default), a header line is written out; if
1151+
\f3\fs18 F
1152+
\f4\fs20 , no header is written. Suppressing the header output can be useful if you are using
1153+
\f3\fs18 LogFile
1154+
\f4\fs20 to append data to an existing file that already has a header line.\
1155+
The
11471156
\f3\fs18 LogFile
11481157
\f4\fs20 documentation discusses how to configure and use
11491158
\f3\fs18 LogFile
@@ -5771,7 +5780,7 @@ You can get the
57715780
\f4\fs20 was called.\
57725781
\pard\pardeftab720\li720\fi-446\ri720\sb180\sa60\partightenfactor0
57735782

5774-
\f3\fs18 \cf2 \'96\'a0(void)setFilePath(string$\'a0filePath, [Ns\'a0initialContents\'a0=\'a0NULL], [logical$\'a0append\'a0=\'a0F], [Nl$\'a0compress\'a0=\'a0NULL], [Ns$\'a0sep\'a0=\'a0NULL])\
5783+
\f3\fs18 \cf2 \'96\'a0(void)setFilePath(string$\'a0filePath, [Ns\'a0initialContents\'a0=\'a0NULL], [logical$\'a0append\'a0=\'a0F], [Nl$\'a0compress\'a0=\'a0NULL], [Ns$\'a0sep\'a0=\'a0NULL], [Nl$\'a0header\'a0=\'a0NULL])\
57755784
\pard\pardeftab720\li547\ri720\sb60\sa60\partightenfactor0
57765785

57775786
\f4\fs20 \cf2 Redirects the
@@ -5786,8 +5795,10 @@ You can get the
57865795
\f3\fs18 append
57875796
\f4\fs20 . New values may be supplied for
57885797
\f3\fs18 compress
5789-
\f4\fs20 and
5798+
\f4\fs20 ,
57905799
\f3\fs18 sep
5800+
\f4\fs20 , and
5801+
\f3\fs18 header
57915802
\f4\fs20 ; the meaning of these parameters is identical to their meaning in
57925803
\f3\fs18 createLogFile()
57935804
\f4\fs20 , except that a value of

VERSIONS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Note that not every commit will be logged here; that is what the Github commit h
77

88
development head (in the master branch):
99
add recipe 16.11, life-long monogamous mating
10+
add the ability to suppress the header line of a LogFile, with a new [logical$ header = T] parameter to createLogFile() (#516), and adding [Nl$ header = NULL] for setFilePath()
1011

1112

1213
version 5.0 (Eidos version 4.0):

core/community_eidos.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ EidosValue_SP Community::ExecuteInstanceMethod(EidosGlobalStringID p_method_id,
571571
}
572572
}
573573

574-
// ********************* – (object<LogFile>$)createLogFile(string$ filePath, [Ns initialContents = NULL], [logical$ append = F], [logical$ compress = F], [string$ sep = ","], [Ni$ logInterval = NULL], [Ni$ flushInterval = NULL])
574+
// ********************* – (object<LogFile>$)createLogFile(string$ filePath, [Ns initialContents = NULL], [logical$ append = F], [logical$ compress = F], [string$ sep = ","], [Ni$ logInterval = NULL], [Ni$ flushInterval = NULL], [logical$ header = T])
575575
EidosValue_SP Community::ExecuteMethod_createLogFile(EidosGlobalStringID p_method_id, const std::vector<EidosValue_SP> &p_arguments, EidosInterpreter &p_interpreter)
576576
{
577577
#pragma unused (p_method_id, p_arguments, p_interpreter)
@@ -584,6 +584,7 @@ EidosValue_SP Community::ExecuteMethod_createLogFile(EidosGlobalStringID p_metho
584584
EidosValue_String *sep_value = (EidosValue_String *)p_arguments[4].get();
585585
EidosValue *logInterval_value = p_arguments[5].get();
586586
EidosValue *flushInterval_value = p_arguments[6].get();
587+
EidosValue *header_value = p_arguments[7].get();
587588

588589
// process parameters
589590
const std::string &filePath = filePath_value->StringRefAtIndex_NOCAST(0, nullptr);
@@ -593,6 +594,7 @@ EidosValue_SP Community::ExecuteMethod_createLogFile(EidosGlobalStringID p_metho
593594
const std::string &sep = sep_value->StringRefAtIndex_NOCAST(0, nullptr);
594595
bool autologging = false, explicitFlushing = false;
595596
int64_t logInterval = 0, flushInterval = 0;
597+
bool emit_header = header_value->LogicalAtIndex_NOCAST(0, nullptr);
596598

597599
if (initialContents_value->Type() != EidosValueType::kValueNULL)
598600
{
@@ -637,7 +639,7 @@ EidosValue_SP Community::ExecuteMethod_createLogFile(EidosGlobalStringID p_metho
637639
// Configure it
638640
logfile->SetLogInterval(autologging, logInterval);
639641
logfile->SetFlushInterval(explicitFlushing, flushInterval);
640-
logfile->ConfigureFile(filePath, initialContents, append, do_compress, sep);
642+
logfile->ConfigureFile(filePath, initialContents, append, emit_header, do_compress, sep);
641643

642644
// Check for duplicate LogFiles using the same path; this is a common error so I'm making it illegal
643645
const std::string &resolved_path = logfile->ResolvedFilePath();
@@ -1367,7 +1369,7 @@ const std::vector<EidosMethodSignature_CSP> *Community_Class::Methods(void) cons
13671369

13681370
methods = new std::vector<EidosMethodSignature_CSP>(*super::Methods());
13691371

1370-
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_createLogFile, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_LogFile_Class))->AddString_S(gEidosStr_filePath)->AddString_ON("initialContents", gStaticEidosValueNULL)->AddLogical_OS("append", gStaticEidosValue_LogicalF)->AddLogical_OS("compress", gStaticEidosValue_LogicalF)->AddString_OS("sep", gStaticEidosValue_StringComma)->AddInt_OSN("logInterval", gStaticEidosValueNULL)->AddInt_OSN("flushInterval", gStaticEidosValueNULL));
1372+
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_createLogFile, kEidosValueMaskObject | kEidosValueMaskSingleton, gSLiM_LogFile_Class))->AddString_S(gEidosStr_filePath)->AddString_ON("initialContents", gStaticEidosValueNULL)->AddLogical_OS("append", gStaticEidosValue_LogicalF)->AddLogical_OS("compress", gStaticEidosValue_LogicalF)->AddString_OS("sep", gStaticEidosValue_StringComma)->AddInt_OSN("logInterval", gStaticEidosValueNULL)->AddInt_OSN("flushInterval", gStaticEidosValueNULL)->AddLogical_OS("header", gStaticEidosValue_LogicalT));
13711373
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_estimatedLastTick, kEidosValueMaskInt | kEidosValueMaskSingleton)));
13721374
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_deregisterScriptBlock, kEidosValueMaskVOID))->AddIntObject("scriptBlocks", gSLiM_SLiMEidosBlock_Class));
13731375
methods->emplace_back((EidosInstanceMethodSignature *)(new EidosInstanceMethodSignature(gStr_genomicElementTypesWithIDs, kEidosValueMaskObject, gSLiM_GenomicElementType_Class))->AddInt("ids"));

0 commit comments

Comments
 (0)