Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ export:
- type: CSVExporter
parameters:
fileNameRoot: "test_base"
interval: 1.0
decimalPlacesCount: 3
data:
- time

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,14 @@ import org.slf4j.LoggerFactory
* @property exportPath the directory to write exported files (temporary folder is used when omitted)
* @property appendTime if true a timestamp is appended to the file name to avoid overwriting
* @property fileExtension the extension for the exported files (default: 'csv')
* @property decimalPlacesCount the count of places after decimal
*/
class CSVExporter<T, P : Position<P>>
@JvmOverloads
constructor(
private val fileNameRoot: String = "",
val interval: Double = DEFAULT_INTERVAL,
val decimalPlacesCount: Int = 2,
val exportPath: String =
createTempDirectory("alchemist-export")
.absolutePathString()
Expand Down Expand Up @@ -100,17 +102,21 @@ constructor(
val data = extractor.extractDataAsText(environment, reaction, time, step)
val names = extractor.columnNames
when {
data.size <= 1 -> data.values.joinToString(" ")
data.size <= 1 ->
roundValues(data.values, decimalPlacesCount).joinToString(" ")
// Labels and keys match
data.size == names.size && data.keys.containsAll(names) ->
Comment on lines 104 to 108

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Nathekip, add a test with multiple columns, please, and if that it goes red, apply a fix!
Thank you, let me know

names.joinToString(" ") {
requireNotNull(data[it]) {
BugReporting.reportBug(
"Bug in ${this::class.simpleName}",
mapOf("key" to it, "data" to data),
)
}
}
roundValues(
names.map { name ->
requireNotNull(data[name]) {
BugReporting.reportBug(
"Bug in ${this::class.simpleName}",
mapOf("key" to name, "data" to data),
)
}
},
decimalPlacesCount,
).joinToString(" ")
// If the labels do not match keys, require predictable iteration order
else -> {
require(data.hasPredictableIteration) {
Expand All @@ -122,7 +128,7 @@ constructor(
""".trimIndent(),
)
}
data.values.joinToString(" ")
roundValues(data.values, decimalPlacesCount).joinToString(" ")
}
}
}
Expand All @@ -140,6 +146,15 @@ constructor(
}
}

private fun roundValues(values: Collection<String>, decimalsNumber: Int): Collection<String> = values.map { raw ->
val number = raw.toDoubleOrNull()
if (number == null || !number.isFinite() || number % 1.0 == 0.0) {
raw
} else {
String.format(Locale.US, "%.${decimalsNumber}f", number)
}
}

private companion object {
/**
* Character used to separate comments from data on export files.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class TestCSVExporter<T, P : Position<P>> :
}
"should have limited-length decimals" {
val limitedDecimalsFile = simulation.csvExporters()[1].dataFile("fixed-decimals_")
val precision2 = """(0\.0*\d\d|\d\.0*\d|\d\.\d|\d\d)(e(-|\+)\d+)?"""
val precision2 = """(\d\d\.\d\d|0\.0*\d\d|\d\.0*\d|\d\.\d|\d\d)(e(-|\+)\d+)?"""
val lineRegex = Regex("""^$precision2(\s($precision2))+$""")
limitedDecimalsFile.useLines { lines ->
lines
Expand Down Expand Up @@ -85,6 +85,29 @@ class TestCSVExporter<T, P : Position<P>> :
exporterFirstLine.shouldNotBeEmpty()
exporterFirstLine.shouldContain("0 1 2 3")
}
"should round every column independently" {
val simulation: Simulation<T, P> = loadAlchemist("testCSVExporterMultipleColumns.yml")
simulation.runInCurrentThread()

val exporter = simulation.csvExporters().first()

val outputFile = File(exporter.exportPath)
.listFiles()
?.first { it.name.startsWith("multiple-columns") }
.shouldNotBeNull()

val firstDataLine = outputFile
.readLines()
.first { line -> line.isNotBlank() && !line.startsWith("#") }

firstDataLine.split(" ") shouldBe listOf(
"0.0",
"1.23",
"2.35",
"3.0",
"4.57",
)
}
}) {
// common utility functions
companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
incarnation: protelis

variables:
seed: &seed
default: 0
min: 0
max: 99
step: 1
scenario_seed: &scenario_seed
formula: (seed + 31) * seed

seeds:
simulation: *seed
scenario: *scenario_seed

export:
- type: CSVExporter
parameters:
fileNameRoot: "multiple-columns"
interval: 1.0
decimalPlacesCount: 2
data:
- time
- molecule: "default_module:default_program"
property: 1.23456
aggregators: [ mean ]
- molecule: "default_module:default_program"
property: 2.34567
aggregators: [ mean ]
- molecule: "default_module:default_program"
property: 3
aggregators: [ mean ]
- molecule: "default_module:default_program"
property: 4.56789
aggregators: [ mean ]

environment:
type: Continuous2DEnvironment

deployments:
- type: Point
parameters: [1, 0, 0]
programs:
- program: "0"

terminate:
- type: AfterTime
parameters: 1
Loading