GDML converter refactoring

This commit is contained in:
Alexander Nozik 2020-08-27 14:29:50 +03:00
parent 68cf4748d8
commit c83a25b0a1
2 changed files with 332 additions and 318 deletions

View File

@ -7,6 +7,7 @@ import hep.dataforge.names.Name
import hep.dataforge.names.asName import hep.dataforge.names.asName
import hep.dataforge.names.plus import hep.dataforge.names.plus
import hep.dataforge.names.toName import hep.dataforge.names.toName
import hep.dataforge.vision.MutableVisionGroup
import hep.dataforge.vision.set import hep.dataforge.vision.set
import hep.dataforge.vision.solid.* import hep.dataforge.vision.solid.*
import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY import hep.dataforge.vision.solid.SolidMaterial.Companion.MATERIAL_COLOR_KEY
@ -19,7 +20,7 @@ import kotlin.random.Random
private val solidsName = "solids".asName() private val solidsName = "solids".asName()
private val volumesName = "volumes".asName() private val volumesName = "volumes".asName()
class GDMLTransformer(val root: GDML) { class GDMLTransformer internal constructor(val root: GDML) {
//private val materialCache = HashMap<GDMLMaterial, Meta>() //private val materialCache = HashMap<GDMLMaterial, Meta>()
private val random = Random(222) private val random = Random(222)
@ -38,25 +39,35 @@ class GDMLTransformer(val root: GDML) {
/** /**
* A special group for local templates * A special group for local templates
*/ */
internal val proto by lazy { SolidGroup() } private val proto by lazy { SolidGroup() }
internal val solids by lazy { private val solids by lazy {
proto.group(solidsName) { proto.group(solidsName) {
config["edges.enabled"] = false config["edges.enabled"] = false
} }
} }
internal val volumes by lazy { private val referenceStore = HashMap<Name, MutableList<Proxy>>()
proto.group(volumesName)
private fun proxySolid(group: SolidGroup, solid: GDMLSolid, name: String): Proxy {
val templateName = solidsName + name
if (proto[templateName] == null) {
solids.addSolid(solid, name)
}
val ref = group.ref(templateName, name)
referenceStore.getOrPut(templateName) { ArrayList() }.add(ref)
return ref
} }
// fun proxySolid(group: SolidGroup, solid: GDMLSolid, name: String): Proxy { private fun proxyVolume(group: SolidGroup, physVolume: GDMLPhysVolume, volume: GDMLGroup): Proxy {
// val fullName = solidsName + name val templateName = volumesName + volume.name.asName()
// if (proto[fullName] == null) { if (proto[templateName] == null) {
// solids.addSolid(this, solid, name) proto[templateName] = volume(volume)
// } }
// return group.ref(fullName, name) val ref = group.ref(templateName, physVolume.name ?: "").withPosition(physVolume)
// } referenceStore.getOrPut(templateName) { ArrayList() }.add(ref)
return ref
}
private val styleCache = HashMap<Name, Meta>() private val styleCache = HashMap<Name, Meta>()
@ -70,14 +81,14 @@ class GDMLTransformer(val root: GDML) {
} }
} }
fun Solid.useStyle(name: String, builder: MetaBuilder.() -> Unit) { private fun Solid.useStyle(name: String, builder: MetaBuilder.() -> Unit) {
styleCache.getOrPut(name.toName()) { styleCache.getOrPut(name.toName()) {
Meta(builder) Meta(builder)
} }
useStyle(name) useStyle(name)
} }
internal fun configureSolid(obj: Solid, parent: GDMLVolume, solid: GDMLSolid) { private fun configureSolid(obj: Solid, parent: GDMLVolume, solid: GDMLSolid) {
val material = parent.materialref.resolve(root) ?: GDMLElement(parent.materialref.ref) val material = parent.materialref.resolve(root) ?: GDMLElement(parent.materialref.ref)
val styleName = "material[${material.name}]" val styleName = "material[${material.name}]"
@ -92,33 +103,12 @@ class GDMLTransformer(val root: GDML) {
var onFinish: GDMLTransformer.() -> Unit = {} var onFinish: GDMLTransformer.() -> Unit = {}
internal fun finalize(final: SolidGroup): SolidGroup {
//final.prototypes = proto
final.prototypes {
proto.children.forEach { (token, item) ->
item.parent = null
set(token.asName(), item)
}
}
styleCache.forEach {
final.styleSheet {
define(it.key.toString(), it.value)
}
}
final.rotationOrder = RotationOrder.ZXY
onFinish(this@GDMLTransformer)
return final
}
} private fun <T : Solid> T.withPosition(
private fun Solid.withPosition(
lUnit: LUnit,
aUnit: AUnit = AUnit.RADIAN,
newPos: GDMLPosition? = null, newPos: GDMLPosition? = null,
newRotation: GDMLRotation? = null, newRotation: GDMLRotation? = null,
newScale: GDMLScale? = null newScale: GDMLScale? = null
): Solid = apply { ): T = apply {
newPos?.let { newPos?.let {
val point = Point3D(it.x(lUnit), it.y(lUnit), it.z(lUnit)) val point = Point3D(it.x(lUnit), it.y(lUnit), it.z(lUnit))
if (position != null || point != World.ZERO) { if (position != null || point != World.ZERO) {
@ -141,11 +131,10 @@ private fun Solid.withPosition(
//TODO convert units if needed //TODO convert units if needed
} }
private fun Solid.withPosition(context: GDMLTransformer, physVolume: GDMLPhysVolume) = withPosition( private fun <T : Solid> T.withPosition(physVolume: GDMLPhysVolume): T = withPosition(
context.lUnit, context.aUnit, physVolume.resolvePosition(root),
physVolume.resolvePosition(context.root), physVolume.resolveRotation(root),
physVolume.resolveRotation(context.root), physVolume.resolveScale(root)
physVolume.resolveScale(context.root)
) )
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
@ -155,12 +144,11 @@ private inline operator fun Number.times(d: Double) = toDouble() * d
private inline operator fun Number.times(f: Float) = toFloat() * f private inline operator fun Number.times(f: Float) = toFloat() * f
private fun SolidGroup.addSolid( private fun SolidGroup.addSolid(
context: GDMLTransformer,
solid: GDMLSolid, solid: GDMLSolid,
name: String = "" name: String = ""
): Solid { ): Solid {
//context.solidAdded(solid) //context.solidAdded(solid)
val lScale = solid.lscale(context.lUnit) val lScale = solid.lscale(lUnit)
val aScale = solid.ascale() val aScale = solid.ascale()
return when (solid) { return when (solid) {
is GDMLBox -> box(solid.x * lScale, solid.y * lScale, solid.z * lScale, name) is GDMLBox -> box(solid.x * lScale, solid.y * lScale, solid.z * lScale, name)
@ -195,10 +183,10 @@ private fun SolidGroup.addSolid(
} }
is GDMLScaledSolid -> { is GDMLScaledSolid -> {
//Add solid with modified scale //Add solid with modified scale
val innerSolid: GDMLSolid = solid.solidref.resolve(context.root) val innerSolid: GDMLSolid = solid.solidref.resolve(root)
?: error("Solid with tag ${solid.solidref.ref} for scaled solid ${solid.name} not defined") ?: error("Solid with tag ${solid.solidref.ref} for scaled solid ${solid.name} not defined")
addSolid(context, innerSolid, name).apply { addSolid(innerSolid, name).apply {
scaleX *= solid.scale.x.toFloat() scaleX *= solid.scale.x.toFloat()
scaleY *= solid.scale.y.toFloat() scaleY *= solid.scale.y.toFloat()
scaleZ = solid.scale.z.toFloat() scaleZ = solid.scale.z.toFloat()
@ -225,8 +213,8 @@ private fun SolidGroup.addSolid(
} }
} }
is GDMLBoolSolid -> { is GDMLBoolSolid -> {
val first: GDMLSolid = solid.first.resolve(context.root) ?: error("") val first: GDMLSolid = solid.first.resolve(root) ?: error("")
val second: GDMLSolid = solid.second.resolve(context.root) ?: error("") val second: GDMLSolid = solid.second.resolve(root) ?: error("")
val type: CompositeType = when (solid) { val type: CompositeType = when (solid) {
is GDMLUnion -> CompositeType.UNION is GDMLUnion -> CompositeType.UNION
is GDMLSubtraction -> CompositeType.SUBTRACT is GDMLSubtraction -> CompositeType.SUBTRACT
@ -234,17 +222,15 @@ private fun SolidGroup.addSolid(
} }
return composite(type, name) { return composite(type, name) {
addSolid(context, first).withPosition( addSolid(first).withPosition(
context.lUnit, context.aUnit, solid.resolveFirstPosition(root),
solid.resolveFirstPosition(context.root), solid.resolveFirstRotation(root),
solid.resolveFirstRotation(context.root),
null null
) )
addSolid(context, second).withPosition( addSolid(second).withPosition(
context.lUnit, context.aUnit, solid.resolvePosition(root),
solid.resolvePosition(context.root), solid.resolveRotation(root),
solid.resolveRotation(context.root),
null null
) )
@ -255,23 +241,17 @@ private fun SolidGroup.addSolid(
} }
private fun SolidGroup.addSolidWithCaching( private fun SolidGroup.addSolidWithCaching(
context: GDMLTransformer,
solid: GDMLSolid, solid: GDMLSolid,
name: String = solid.name name: String = solid.name
): Solid? { ): Solid? {
return when (context.solidAction(solid)) { return when (solidAction(solid)) {
GDMLTransformer.Action.ADD -> { Action.ADD -> {
addSolid(context, solid, name) addSolid(solid, name)
} }
GDMLTransformer.Action.PROTOTYPE -> { Action.PROTOTYPE -> {
// context.proxySolid(this, solid, name) proxySolid(this, solid, name)
val fullName = solidsName + solid.name.asName()
if (context.proto[fullName] == null) {
context.solids.addSolid(context, solid, solid.name)
} }
ref(fullName, name) Action.REJECT -> {
}
GDMLTransformer.Action.REJECT -> {
//ignore //ignore
null null
} }
@ -279,78 +259,112 @@ private fun SolidGroup.addSolidWithCaching(
} }
private fun SolidGroup.addPhysicalVolume( private fun SolidGroup.addPhysicalVolume(
context: GDMLTransformer,
physVolume: GDMLPhysVolume physVolume: GDMLPhysVolume
) { ) {
val volume: GDMLGroup = physVolume.volumeref.resolve(context.root) val volume: GDMLGroup = physVolume.volumeref.resolve(root)
?: error("Volume with ref ${physVolume.volumeref.ref} could not be resolved") ?: error("Volume with ref ${physVolume.volumeref.ref} could not be resolved")
// a special case for single solid volume // a special case for single solid volume
if (volume is GDMLVolume && volume.physVolumes.isEmpty() && volume.placement == null) { if (volume is GDMLVolume && volume.physVolumes.isEmpty() && volume.placement == null) {
val solid = volume.solidref.resolve(context.root) val solid = volume.solidref.resolve(root)
?: error("Solid with tag ${volume.solidref.ref} for volume ${volume.name} not defined") ?: error("Solid with tag ${volume.solidref.ref} for volume ${volume.name} not defined")
addSolidWithCaching(context, solid, physVolume.name ?: "")?.apply { addSolidWithCaching(solid, physVolume.name ?: "")?.apply {
context.configureSolid(this, volume, solid) configureSolid(this, volume, solid)
withPosition(context, physVolume) withPosition(physVolume)
} }
return return
} }
when (context.volumeAction(volume)) { when (volumeAction(volume)) {
GDMLTransformer.Action.ADD -> { Action.ADD -> {
val group: SolidGroup = volume(context, volume) val group: SolidGroup = volume(volume)
this[physVolume.name ?: ""] = group.withPosition(context, physVolume) this[physVolume.name ?: ""] = group.withPosition(physVolume)
} }
GDMLTransformer.Action.PROTOTYPE -> { Action.PROTOTYPE -> {
val fullName = volumesName + volume.name.asName() proxyVolume(this, physVolume, volume)
if (context.proto[fullName] == null) {
context.proto[fullName] = volume(context, volume)
} }
ref(fullName, physVolume.name ?: "").withPosition(context, physVolume) Action.REJECT -> {
}
GDMLTransformer.Action.REJECT -> {
//ignore //ignore
} }
} }
} }
private fun SolidGroup.addDivisionVolume( private fun SolidGroup.addDivisionVolume(
context: GDMLTransformer,
divisionVolume: GDMLDivisionVolume divisionVolume: GDMLDivisionVolume
) { ) {
val volume: GDMLGroup = divisionVolume.volumeref.resolve(context.root) val volume: GDMLGroup = divisionVolume.volumeref.resolve(root)
?: error("Volume with ref ${divisionVolume.volumeref.ref} could not be resolved") ?: error("Volume with ref ${divisionVolume.volumeref.ref} could not be resolved")
//TODO add divisions //TODO add divisions
set(Name.EMPTY, volume(context, volume)) set(Name.EMPTY, volume(volume))
} }
private fun volume( private fun volume(
context: GDMLTransformer,
group: GDMLGroup group: GDMLGroup
): SolidGroup = SolidGroup().apply { ): SolidGroup = SolidGroup().apply {
if (group is GDMLVolume) { if (group is GDMLVolume) {
val solid: GDMLSolid = group.solidref.resolve(context.root) val solid: GDMLSolid = group.solidref.resolve(root)
?: error("Solid with tag ${group.solidref.ref} for volume ${group.name} not defined") ?: error("Solid with tag ${group.solidref.ref} for volume ${group.name} not defined")
addSolidWithCaching(context, solid)?.apply { addSolidWithCaching(solid)?.apply {
context.configureSolid(this, group, solid) configureSolid(this, group, solid)
} }
when (val vol: GDMLPlacement? = group.placement) { when (val vol: GDMLPlacement? = group.placement) {
is GDMLPhysVolume -> addPhysicalVolume(context, vol) is GDMLPhysVolume -> addPhysicalVolume(vol)
is GDMLDivisionVolume -> addDivisionVolume(context, vol) is GDMLDivisionVolume -> addDivisionVolume(vol)
} }
} }
group.physVolumes.forEach { physVolume -> group.physVolumes.forEach { physVolume ->
addPhysicalVolume(context, physVolume) addPhysicalVolume(physVolume)
} }
} }
private fun finalize(final: SolidGroup): SolidGroup {
//final.prototypes = proto
final.useStyle("GDML") {
Solid.ROTATION_ORDER_KEY put RotationOrder.ZXY
}
//inline prototypes
// referenceStore.forEach { (protoName, list) ->
// val proxy = list.singleOrNull() ?: return@forEach
// val parent = proxy.parent as? MutableVisionGroup ?: return@forEach
// val token = parent.children.entries.find { it.value == proxy }?.key ?: error("Inconsistent reference cache")
// val prototype = proto[protoName] as? Solid ?: error("Inconsistent reference cache")
// prototype.parent = null
// parent[token] = prototype
// prototype.updateFrom(proxy)
//
// //FIXME update prototype
// proto[protoName] = null
// }
final.prototypes {
proto.children.forEach { (token, item) ->
item.parent = null
set(token.asName(), item)
}
}
styleCache.forEach {
final.styleSheet {
define(it.key.toString(), it.value)
}
}
onFinish(this@GDMLTransformer)
return final
}
val result by lazy {
finalize(volume(root.world))
}
}
fun GDML.toVision(block: GDMLTransformer.() -> Unit = {}): SolidGroup { fun GDML.toVision(block: GDMLTransformer.() -> Unit = {}): SolidGroup {
val context = GDMLTransformer(this).apply(block) val context = GDMLTransformer(this).apply(block)
return context.finalize(volume(context, world)) return context.result
} }
/** /**

View File

@ -18,20 +18,16 @@ expect class Counter() {
fun incrementAndGet(): Int fun incrementAndGet(): Int
} }
@DFExperimental private fun Point3D?.safePlus(other: Point3D?): Point3D? = if (this == null && other == null) {
private class GdmlOptimizer() : VisionVisitor {
val logger = KotlinLogging.logger("SingleChildReducer")
private operator fun Point3D?.plus(other: Point3D?): Point3D? = if (this == null && other == null) {
null null
} else { } else {
(this ?: Point3D(0, 0, 0)) + (other ?: Point3D(0, 0, 0)) (this ?: Point3D(0, 0, 0)) + (other ?: Point3D(0, 0, 0))
} }
private fun Vision.updateFrom(other: Vision): Vision { internal fun Vision.updateFrom(other: Vision): Vision {
if (this is Solid && other is Solid) { if (this is Solid && other is Solid) {
position += other.position position = position.safePlus(other.position)
rotation += other.rotation rotation = rotation.safePlus(other.rotation)
if (this.scale != null || other.scale != null) { if (this.scale != null || other.scale != null) {
scaleX = scaleX.toDouble() * other.scaleX.toDouble() scaleX = scaleX.toDouble() * other.scaleX.toDouble()
scaleY = scaleY.toDouble() * other.scaleY.toDouble() scaleY = scaleY.toDouble() * other.scaleY.toDouble()
@ -45,45 +41,49 @@ private class GdmlOptimizer() : VisionVisitor {
} }
return this return this
} }
//
private val depthCount = HashMap<Int, Counter>() //@DFExperimental
//private class GdmlOptimizer() : VisionVisitor {
override suspend fun visit(name: Name, vision: Vision) { // val logger = KotlinLogging.logger("SingleChildReducer")
val depth = name.length //
depthCount.getOrPut(depth) { Counter() }.incrementAndGet() // private val depthCount = HashMap<Int, Counter>()
} //
// override suspend fun visit(name: Name, vision: Vision) {
override fun skip(name: Name, vision: Vision): Boolean = vision is Proxy.ProxyChild // val depth = name.length
// depthCount.getOrPut(depth) { Counter() }.incrementAndGet()
override suspend fun visitChildren(name: Name, group: VisionGroup) { // }
if (name == "volumes".toName()) return //
if (group !is MutableVisionGroup) return // override fun skip(name: Name, vision: Vision): Boolean = vision is Proxy.ProxyChild
//
val newChildren = group.children.entries.associate { (visionToken, vision) -> // override suspend fun visitChildren(name: Name, group: VisionGroup) {
//Reduce single child groups // if (name == "volumes".toName()) return
if (vision is VisionGroup && vision !is Proxy && vision.children.size == 1) { // if (group !is MutableVisionGroup) return
val (token, child) = vision.children.entries.first() //
child.parent = null // val newChildren = group.children.entries.associate { (visionToken, vision) ->
if (token != visionToken) { // //Reduce single child groups
child.config["solidName"] = token.toString() // if (vision is VisionGroup && vision !is Proxy && vision.children.size == 1) {
} // val (token, child) = vision.children.entries.first()
visionToken to child.updateFrom(vision) // child.parent = null
} else { // if (token != visionToken) {
visionToken to vision // child.config["solidName"] = token.toString()
} // }
} // visionToken to child.updateFrom(vision)
if (newChildren != group.children) { // } else {
group.removeAll() // visionToken to vision
newChildren.forEach { (token, child) -> // }
group[token] = child // }
} // if (newChildren != group.children) {
} // group.removeAll()
} // newChildren.forEach { (token, child) ->
} // group[token] = child
// }
@DFExperimental // }
suspend fun SolidGroup.optimizeGdml(): Job = coroutineScope { // }
prototypes?.let { //}
VisionVisitor.visitTree(GdmlOptimizer(), this, it) //
} ?: CompletableDeferred(Unit) //@DFExperimental
} //suspend fun SolidGroup.optimizeGdml(): Job = coroutineScope {
// prototypes?.let {
// VisionVisitor.visitTree(GdmlOptimizer(), this, it)
// } ?: CompletableDeferred(Unit)
//}