[WIP] first commit
This commit is contained in:
parent
2525c3d0ec
commit
ddbd9bf3cd
9
.gitignore
vendored
9
.gitignore
vendored
@ -0,0 +1,9 @@
|
||||
|
||||
.idea/
|
||||
*.iws
|
||||
out/
|
||||
.gradle
|
||||
build/
|
||||
|
||||
|
||||
!gradle-wrapper.jar
|
14
build.gradle.kts
Normal file
14
build.gradle.kts
Normal file
@ -0,0 +1,14 @@
|
||||
plugins {
|
||||
id("ru.mipt.npm.project")
|
||||
}
|
||||
|
||||
group = "ru.inr.mass"
|
||||
version = "0.1.0-SHAPSHOT"
|
||||
|
||||
val dataforgeVersion by extra("0.3.0-dev")
|
||||
|
||||
val spaceRepo by extra("https://maven.pkg.jetbrains.space/mipt-npm/p/numass/maven")
|
||||
|
||||
apiValidation{
|
||||
validationDisabled = true
|
||||
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
185
gradlew
vendored
Normal file
185
gradlew
vendored
Normal file
@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
89
gradlew.bat
vendored
Normal file
89
gradlew.bat
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
10
numass-data-model/build.gradle.kts
Normal file
10
numass-data-model/build.gradle.kts
Normal file
@ -0,0 +1,10 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("ru.mipt.npm.kscience")
|
||||
}
|
||||
|
||||
val dataforgeVersion: String by rootProject.extra
|
||||
|
||||
dependencies {
|
||||
api("hep.dataforge:dataforge-context:$dataforgeVersion")
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package ru.inr.mass.data.api
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.flatMap
|
||||
import kotlinx.coroutines.flow.flatMapConcat
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.stream.Stream
|
||||
|
||||
public interface ParentBlock : NumassBlock {
|
||||
public val blocks: List<NumassBlock>
|
||||
|
||||
/**
|
||||
* If true, the sub-blocks a considered to be isSequential, if not, the sub-blocks are parallel
|
||||
*/
|
||||
public val isSequential: Boolean get() = true
|
||||
}
|
||||
|
||||
/**
|
||||
* A block constructed from a set of other blocks. Internal blocks are not necessary subsequent. Blocks are automatically sorted.
|
||||
* Created by darksnake on 16.07.2017.
|
||||
*/
|
||||
public class MetaBlock(override val blocks: List<NumassBlock>) : ParentBlock {
|
||||
|
||||
override val startTime: Instant
|
||||
get() = blocks.first().startTime
|
||||
|
||||
override val length: Duration
|
||||
get() = Duration.ofNanos(blocks.stream().mapToLong { block -> block.length.toNanos() }.sum())
|
||||
|
||||
override val events: Flow<NumassEvent>
|
||||
get() = blocks.sortedBy { it.startTime }.asFlow().flatMapConcat { it.events }
|
||||
|
||||
override val frames: Flow<NumassFrame>
|
||||
get() = blocks.sortedBy { it.startTime }.asFlow().flatMapConcat { it.frames }
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2018 Alexander Nozik.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ru.inr.mass.data.api
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
|
||||
public open class OrphanNumassEvent(public val amplitude: Short, public val timeOffset: Long) :
|
||||
Comparable<OrphanNumassEvent> {
|
||||
public operator fun component1(): Short = amplitude
|
||||
public operator fun component2(): Long = timeOffset
|
||||
|
||||
override fun compareTo(other: OrphanNumassEvent): Int {
|
||||
return this.timeOffset.compareTo(other.timeOffset)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A single numass event with given amplitude and time.
|
||||
*
|
||||
* @author Darksnake
|
||||
* @property amp the amplitude of the event
|
||||
* @property timeOffset time in nanoseconds relative to block start
|
||||
* @property owner an owner block for this event
|
||||
*
|
||||
*/
|
||||
public class NumassEvent(amplitude: Short, timeOffset: Long, public val owner: NumassBlock) :
|
||||
OrphanNumassEvent(amplitude, timeOffset) {
|
||||
|
||||
public val channel: Int get() = owner.channel
|
||||
|
||||
public val time: Instant get() = owner.startTime.plusNanos(timeOffset)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A single continuous measurement block. The block can contain both isolated events and signal frames
|
||||
*
|
||||
*
|
||||
* Created by darksnake on 06-Jul-17.
|
||||
*/
|
||||
public interface NumassBlock {
|
||||
|
||||
/**
|
||||
* The absolute start time of the block
|
||||
*/
|
||||
public val startTime: Instant
|
||||
|
||||
/**
|
||||
* The length of the block
|
||||
*/
|
||||
public val length: Duration
|
||||
|
||||
/**
|
||||
* Stream of isolated events. Could be empty
|
||||
*/
|
||||
public val events: Flow<NumassEvent>
|
||||
|
||||
/**
|
||||
* Stream of frames. Could be empty
|
||||
*/
|
||||
public val frames: Flow<NumassFrame>
|
||||
|
||||
public val channel: Int get() = 0
|
||||
}
|
||||
|
||||
public fun OrphanNumassEvent.adopt(parent: NumassBlock): NumassEvent {
|
||||
return NumassEvent(this.amplitude, this.timeOffset, parent)
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple in-memory implementation of block of events. No frames are allowed
|
||||
* Created by darksnake on 08.07.2017.
|
||||
*/
|
||||
public class SimpleBlock(
|
||||
override val startTime: Instant,
|
||||
override val length: Duration,
|
||||
rawEvents: Iterable<OrphanNumassEvent>,
|
||||
) : NumassBlock {
|
||||
|
||||
private val eventList by lazy { rawEvents.map { it.adopt(this) } }
|
||||
|
||||
override val frames: Flow<NumassFrame> get() = emptyFlow()
|
||||
|
||||
override val events: Flow<NumassEvent> get() = eventList.asFlow()
|
||||
|
||||
public companion object {
|
||||
public suspend fun produce(
|
||||
startTime: Instant,
|
||||
length: Duration,
|
||||
producer: suspend () -> Iterable<OrphanNumassEvent>,
|
||||
): SimpleBlock {
|
||||
return SimpleBlock(startTime, length, producer())
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package ru.inr.mass.data.api
|
||||
|
||||
import java.nio.ShortBuffer
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* The continuous frame of digital detector data
|
||||
* Created by darksnake on 06-Jul-17.
|
||||
*/
|
||||
public class NumassFrame(
|
||||
/**
|
||||
* The absolute start time of the frame
|
||||
*/
|
||||
public val time: Instant,
|
||||
/**
|
||||
* The time interval per tick
|
||||
*/
|
||||
public val tickSize: Duration,
|
||||
/**
|
||||
* The buffered signal shape in ticks
|
||||
*/
|
||||
public val signal: ShortBuffer) {
|
||||
|
||||
public val length: Duration
|
||||
get() = tickSize.multipliedBy(signal.capacity().toLong())
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2018 Alexander Nozik.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ru.inr.mass.data.api
|
||||
|
||||
import hep.dataforge.meta.*
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.provider.Provider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import kotlinx.coroutines.flow.flatMap
|
||||
import kotlinx.coroutines.flow.flatMapConcat
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.stream.Stream
|
||||
|
||||
/**
|
||||
* Created by darksnake on 06-Jul-17.
|
||||
*/
|
||||
public interface NumassPoint : ParentBlock, Provider {
|
||||
|
||||
public val meta: Meta
|
||||
|
||||
override val blocks: List<NumassBlock>
|
||||
|
||||
/**
|
||||
* Distinct map of channel number to corresponding grouping block
|
||||
*/
|
||||
public val channels: Map<Int, NumassBlock>
|
||||
get() = blocks.toList().groupBy { it.channel }.mapValues { entry ->
|
||||
if (entry.value.size == 1) {
|
||||
entry.value.first()
|
||||
} else {
|
||||
MetaBlock(entry.value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun content(target: String): Map<Name, Any> = when (target) {
|
||||
NUMASS_BLOCK_TARGET -> blocks.mapIndexed { index, numassBlock ->
|
||||
"block[$index]".toName() to numassBlock
|
||||
}.toMap()
|
||||
NUMASS_CHANNEL_TARGET -> channels.mapKeys { "channel[${it.key}]".toName() }
|
||||
else -> super.content(target)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the voltage setting for the point
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public val voltage: Double get() = meta[HV_KEY].double ?: 0.0
|
||||
|
||||
/**
|
||||
* Get the index for this point in the set
|
||||
* @return
|
||||
*/
|
||||
public val index: Int get() = meta[INDEX_KEY].int ?: -1
|
||||
|
||||
/**
|
||||
* Get the starting time from meta or from first block
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override val startTime: Instant
|
||||
get() = meta[START_TIME_KEY]?.long?.let { Instant.ofEpochMilli(it) } ?: firstBlock.startTime
|
||||
|
||||
/**
|
||||
* Get the length key of meta or calculate length as a sum of block lengths. The latter could be a bit slow
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override val length: Duration
|
||||
get() = Duration.ofNanos(blocks.stream().filter { it.channel == 0 }.mapToLong { it -> it.length.toNanos() }
|
||||
.sum())
|
||||
|
||||
/**
|
||||
* Get all events it all blocks as a single sequence
|
||||
*
|
||||
*
|
||||
* Some performance analysis of different stream concatenation approaches is given here: https://www.techempower.com/blog/2016/10/19/efficient-multiple-stream-concatenation-in-java/
|
||||
*
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override val events: Flow<NumassEvent>
|
||||
get() = blocks.asFlow().flatMapConcat { it.events }
|
||||
|
||||
/**
|
||||
* Get all frames in all blocks as a single sequence
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
override val frames: Flow<NumassFrame>
|
||||
get() = blocks.asFlow().flatMapConcat { it.frames }
|
||||
|
||||
|
||||
override val isSequential: Boolean
|
||||
get() = channels.size == 1
|
||||
|
||||
public companion object {
|
||||
public const val NUMASS_BLOCK_TARGET: String = "block"
|
||||
public const val NUMASS_CHANNEL_TARGET: String = "channel"
|
||||
|
||||
public const val START_TIME_KEY: String = "start"
|
||||
public const val LENGTH_KEY: String = "length"
|
||||
public const val HV_KEY: String = "voltage"
|
||||
public const val INDEX_KEY: String = "index"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first block if it exists. Throw runtime exception otherwise.
|
||||
*
|
||||
*/
|
||||
public val NumassPoint.firstBlock: NumassBlock
|
||||
get() = blocks.firstOrNull() ?: throw RuntimeException("The point is empty")
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package ru.inr.mass.data.api
|
||||
|
||||
import hep.dataforge.context.Named
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.get
|
||||
import hep.dataforge.meta.long
|
||||
import hep.dataforge.names.Name
|
||||
import hep.dataforge.names.toName
|
||||
import hep.dataforge.provider.Provider
|
||||
import java.time.Instant
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* A single set of numass points previously called file.
|
||||
*
|
||||
* @author [Alexander Nozik](mailto:altavir@gmail.com)
|
||||
*/
|
||||
public interface NumassSet : Named, Iterable<NumassPoint>, Provider {
|
||||
|
||||
public val meta: Meta
|
||||
|
||||
public val points: List<NumassPoint>
|
||||
|
||||
/**
|
||||
* Get the starting time from meta or from first point
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public val startTime: Instant
|
||||
get() = meta[NumassPoint.START_TIME_KEY].long?.let { Instant.ofEpochMilli(it) } ?: firstPoint.startTime
|
||||
|
||||
//suspend fun getHvData(): Table?
|
||||
|
||||
override fun iterator(): Iterator<NumassPoint> {
|
||||
return points.iterator()
|
||||
}
|
||||
|
||||
|
||||
override val defaultTarget: String get() = NUMASS_POINT_PROVIDER_KEY
|
||||
|
||||
override fun content(target: String): Map<Name, Any> {
|
||||
return if(target == NUMASS_POINT_PROVIDER_KEY){
|
||||
points.associate { "point[${it.voltage}]".toName() to it }
|
||||
}else {
|
||||
super.content(target)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DESCRIPTION_KEY = "info"
|
||||
const val NUMASS_POINT_PROVIDER_KEY = "point"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List all points with given voltage
|
||||
*
|
||||
* @param voltage
|
||||
* @return
|
||||
*/
|
||||
public fun NumassSet.getPoints(voltage: Double): List<NumassPoint> {
|
||||
return points.filter { it -> it.voltage == voltage }.toList()
|
||||
}
|
||||
|
||||
/**
|
||||
* Find first point with given voltage
|
||||
*
|
||||
* @param voltage
|
||||
* @return
|
||||
*/
|
||||
public fun NumassSet.pointOrNull(voltage: Double): NumassPoint? {
|
||||
return points.firstOrNull { it -> it.voltage == voltage }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first point if it exists. Throw runtime exception otherwise.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public val NumassSet.firstPoint: NumassPoint
|
||||
get() = points.firstOrNull() ?: throw RuntimeException("The set is empty")
|
@ -0,0 +1,11 @@
|
||||
package ru.inr.mass.data.api
|
||||
|
||||
import java.util.stream.Stream
|
||||
|
||||
/**
|
||||
* An ancestor to numass frame analyzers
|
||||
* Created by darksnake on 07.07.2017.
|
||||
*/
|
||||
public interface SignalProcessor {
|
||||
public fun analyze(frame: NumassFrame): Stream<NumassEvent>
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package ru.inr.mass.data.api
|
||||
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
|
||||
/**
|
||||
* A simple static implementation of NumassPoint
|
||||
* Created by darksnake on 08.07.2017.
|
||||
*/
|
||||
public class SimpleNumassPoint(
|
||||
override val blocks: List<NumassBlock>,
|
||||
override val meta: Meta,
|
||||
override val isSequential: Boolean = true,
|
||||
) : NumassPoint {
|
||||
|
||||
// /**
|
||||
// * Input blocks must be sorted
|
||||
// * @param voltage
|
||||
// * @param blocks
|
||||
// */
|
||||
// constructor(blocks: Collection<NumassBlock>, voltage: Double) :
|
||||
// this(blocks.sortedBy { it.startTime }, MetaBuilder("point").setValue(NumassPoint.HV_KEY, voltage))
|
||||
|
||||
init {
|
||||
if (blocks.isEmpty()) {
|
||||
throw IllegalArgumentException("No blocks in collection")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
53
numass-data-proto/build.gradle.kts
Normal file
53
numass-data-proto/build.gradle.kts
Normal file
@ -0,0 +1,53 @@
|
||||
import com.google.protobuf.gradle.*
|
||||
|
||||
plugins {
|
||||
java
|
||||
kotlin("jvm")
|
||||
id("ru.mipt.npm.kscience")
|
||||
id("com.google.protobuf") version "0.8.14"
|
||||
}
|
||||
|
||||
val dataforgeVersion: String by rootProject.extra
|
||||
|
||||
dependencies {
|
||||
api(project(":numass-data-model"))
|
||||
api("hep.dataforge:dataforge-workspace:$dataforgeVersion")
|
||||
implementation("com.google.protobuf:protobuf-java:3.14.0")
|
||||
implementation("javax.annotation:javax.annotation-api:1.3.1")
|
||||
}
|
||||
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
|
||||
dependsOn(":numass-data-proto:generateProto")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
create("proto") {
|
||||
proto {
|
||||
srcDir("src/main/proto")
|
||||
}
|
||||
}
|
||||
create("gen"){
|
||||
java{
|
||||
srcDir("gen/main/java")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//kotlin{
|
||||
// sourceSets{
|
||||
// main{
|
||||
// de
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
protobuf {
|
||||
// Configure the protoc executable
|
||||
protoc {
|
||||
// Download from repositories
|
||||
artifact = "com.google.protobuf:protoc:3.14.0"
|
||||
}
|
||||
|
||||
generatedFilesBaseDir = "$projectDir/gen"
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,139 @@
|
||||
///*
|
||||
// * Copyright 2018 Alexander Nozik.
|
||||
// *
|
||||
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// * you may not use this file except in compliance with the License.
|
||||
// * You may obtain a copy of the License at
|
||||
// *
|
||||
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||
// *
|
||||
// * Unless required by applicable law or agreed to in writing, software
|
||||
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// * See the License for the specific language governing permissions and
|
||||
// * limitations under the License.
|
||||
// */
|
||||
//
|
||||
//package ru.inr.mass.data.proto
|
||||
//
|
||||
//import hep.dataforge.io.envelopes.*
|
||||
//import hep.dataforge.values.Value
|
||||
//import org.slf4j.LoggerFactory
|
||||
//import java.io.IOException
|
||||
//import java.nio.ByteBuffer
|
||||
//import java.nio.channels.FileChannel
|
||||
//import java.nio.file.Path
|
||||
//import java.nio.file.StandardOpenOption
|
||||
//import java.util.*
|
||||
//
|
||||
///**
|
||||
// * An envelope type for legacy numass tags. Reads legacy tag and writes DF02 tags
|
||||
// */
|
||||
//class NumassEnvelopeType : EnvelopeType {
|
||||
//
|
||||
// override val code: Int = DefaultEnvelopeType.DEFAULT_ENVELOPE_CODE
|
||||
//
|
||||
// override val name: String = "numass"
|
||||
//
|
||||
// override fun description(): String = "Numass legacy envelope"
|
||||
//
|
||||
// /**
|
||||
// * Read as legacy
|
||||
// */
|
||||
// override fun getReader(properties: Map<String, String>): EnvelopeReader {
|
||||
// return NumassEnvelopeReader()
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Write as default
|
||||
// */
|
||||
// override fun getWriter(properties: Map<String, String>): EnvelopeWriter {
|
||||
// return DefaultEnvelopeWriter(this, MetaType.resolve(properties))
|
||||
// }
|
||||
//
|
||||
// class LegacyTag : EnvelopeTag() {
|
||||
// override val startSequence: ByteArray
|
||||
// get() = LEGACY_START_SEQUENCE
|
||||
//
|
||||
// override val endSequence: ByteArray
|
||||
// get() = LEGACY_END_SEQUENCE
|
||||
//
|
||||
// /**
|
||||
// * Get the length of tag in bytes. -1 means undefined size in case tag was modified
|
||||
// *
|
||||
// * @return
|
||||
// */
|
||||
// override val length: Int
|
||||
// get() = 30
|
||||
//
|
||||
// /**
|
||||
// * Read leagscy version 1 tag without leading tag head
|
||||
// *
|
||||
// * @param buffer
|
||||
// * @return
|
||||
// * @throws IOException
|
||||
// */
|
||||
// override fun readHeader(buffer: ByteBuffer): Map<String, Value> {
|
||||
// val res = HashMap<String, Value>()
|
||||
//
|
||||
// val type = buffer.getInt(2)
|
||||
// res[Envelope.TYPE_PROPERTY] = Value.of(type)
|
||||
//
|
||||
// val metaTypeCode = buffer.getShort(10)
|
||||
// val metaType = MetaType.resolve(metaTypeCode)
|
||||
//
|
||||
// if (metaType != null) {
|
||||
// res[Envelope.META_TYPE_PROPERTY] = metaType.name.parseValue()
|
||||
// } else {
|
||||
// LoggerFactory.getLogger(EnvelopeTag::class.java).warn("Could not resolve meta type. Using default")
|
||||
// }
|
||||
//
|
||||
// val metaLength = Integer.toUnsignedLong(buffer.getInt(14))
|
||||
// res[Envelope.META_LENGTH_PROPERTY] = Value.of(metaLength)
|
||||
// val dataLength = Integer.toUnsignedLong(buffer.getInt(22))
|
||||
// res[Envelope.DATA_LENGTH_PROPERTY] = Value.of(dataLength)
|
||||
// return res
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private class NumassEnvelopeReader : DefaultEnvelopeReader() {
|
||||
// override fun newTag(): EnvelopeTag {
|
||||
// return LegacyTag()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// companion object {
|
||||
// val INSTANCE = NumassEnvelopeType()
|
||||
//
|
||||
// val LEGACY_START_SEQUENCE = byteArrayOf('#'.toByte(), '!'.toByte())
|
||||
// val LEGACY_END_SEQUENCE = byteArrayOf('!'.toByte(), '#'.toByte(), '\r'.toByte(), '\n'.toByte())
|
||||
//
|
||||
// /**
|
||||
// * Replacement for standard type infer to include legacy type
|
||||
// *
|
||||
// * @param path
|
||||
// * @return
|
||||
// */
|
||||
// fun infer(path: Path): EnvelopeType? {
|
||||
// return try {
|
||||
// FileChannel.open(path, StandardOpenOption.READ).use {
|
||||
// val buffer = it.map(FileChannel.MapMode.READ_ONLY, 0, 6)
|
||||
// when {
|
||||
// //TODO use templates from appropriate types
|
||||
// buffer.get(0) == '#'.toByte() && buffer.get(1) == '!'.toByte() -> INSTANCE
|
||||
// buffer.get(0) == '#'.toByte() && buffer.get(1) == '!'.toByte() &&
|
||||
// buffer.get(4) == 'T'.toByte() && buffer.get(5) == 'L'.toByte() -> TaglessEnvelopeType.INSTANCE
|
||||
// buffer.get(0) == '#'.toByte() && buffer.get(1) == '~'.toByte() -> DefaultEnvelopeType.INSTANCE
|
||||
// else -> null
|
||||
// }
|
||||
// }
|
||||
// } catch (ex: Exception) {
|
||||
// LoggerFactory.getLogger(EnvelopeType::class.java).warn("Could not infer envelope type of file {} due to exception: {}", path, ex)
|
||||
// null
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
//}
|
@ -0,0 +1,52 @@
|
||||
///*
|
||||
// * Copyright 2018 Alexander Nozik.
|
||||
// *
|
||||
// * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// * you may not use this file except in compliance with the License.
|
||||
// * You may obtain a copy of the License at
|
||||
// *
|
||||
// * http://www.apache.org/licenses/LICENSE-2.0
|
||||
// *
|
||||
// * Unless required by applicable law or agreed to in writing, software
|
||||
// * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// * See the License for the specific language governing permissions and
|
||||
// * limitations under the License.
|
||||
// */
|
||||
//
|
||||
//package ru.inr.mass.data.proto
|
||||
//
|
||||
//import hep.dataforge.meta.Meta
|
||||
//import hep.dataforge.storage.files.MutableFileEnvelope
|
||||
//import java.nio.ByteBuffer
|
||||
//import java.nio.file.Files
|
||||
//import java.nio.file.Path
|
||||
//import java.nio.file.StandardOpenOption
|
||||
//
|
||||
//class NumassFileEnvelope(path: Path) : MutableFileEnvelope(path) {
|
||||
//
|
||||
// private val tag by lazy { Files.newByteChannel(path, StandardOpenOption.READ).use { NumassEnvelopeType.LegacyTag().read(it) } }
|
||||
//
|
||||
// override val dataOffset: Long by lazy { (tag.length + tag.metaSize).toLong() }
|
||||
//
|
||||
// override var dataLength: Int
|
||||
// get() = tag.dataSize
|
||||
// set(value) {
|
||||
// if (value > Int.MAX_VALUE) {
|
||||
// throw RuntimeException("Too large data block")
|
||||
// }
|
||||
// tag.dataSize = value
|
||||
// if (channel.write(tag.toBytes(), 0L) < tag.length) {
|
||||
// throw error("Tag is not overwritten.")
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// override val meta: Meta by lazy {
|
||||
// val buffer = ByteBuffer.allocate(tag.metaSize).also {
|
||||
// channel.read(it, tag.length.toLong())
|
||||
// }
|
||||
// tag.metaType.reader.readBuffer(buffer)
|
||||
// }
|
||||
//}
|
||||
//
|
@ -0,0 +1,20 @@
|
||||
package ru.inr.mass.data.proto
|
||||
|
||||
import hep.dataforge.context.AbstractPlugin
|
||||
import hep.dataforge.context.Context
|
||||
import hep.dataforge.context.PluginFactory
|
||||
import hep.dataforge.context.PluginTag
|
||||
import hep.dataforge.io.IOPlugin
|
||||
import hep.dataforge.meta.Meta
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
public class NumassProtoPlugin : AbstractPlugin() {
|
||||
val io by require(IOPlugin)
|
||||
override val tag: PluginTag get() = Companion.tag
|
||||
|
||||
public companion object : PluginFactory<NumassProtoPlugin> {
|
||||
override fun invoke(meta: Meta, context: Context): NumassProtoPlugin = NumassProtoPlugin()
|
||||
override val tag: PluginTag = PluginTag("numass-proto", group = "ru.inr.mass")
|
||||
override val type: KClass<out NumassProtoPlugin> = NumassProtoPlugin::class
|
||||
}
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2018 Alexander Nozik.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ru.inr.mass.data.proto
|
||||
|
||||
import hep.dataforge.context.Context
|
||||
import hep.dataforge.io.Envelope
|
||||
import hep.dataforge.io.io
|
||||
import hep.dataforge.io.readEnvelopeFile
|
||||
import hep.dataforge.meta.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.io.asInputStream
|
||||
import kotlinx.io.readByteArray
|
||||
import org.slf4j.LoggerFactory
|
||||
import ru.inr.mass.data.api.*
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.InputStream
|
||||
import java.nio.file.Path
|
||||
import java.time.Duration
|
||||
import java.time.Instant
|
||||
import java.util.zip.Inflater
|
||||
|
||||
/**
|
||||
* Protobuf based numass point
|
||||
* Created by Alexander Nozik on 09.07.2017.
|
||||
*/
|
||||
public class ProtoNumassPoint(
|
||||
override val meta: Meta,
|
||||
private val protoBuilder: () -> NumassProto.Point,
|
||||
) : NumassPoint {
|
||||
|
||||
private val proto: NumassProto.Point get() = protoBuilder()
|
||||
|
||||
override val blocks: List<NumassBlock>
|
||||
get() = proto.channelsList
|
||||
.flatMap { channel ->
|
||||
channel.blocksList
|
||||
.map { block -> ProtoBlock(channel.id.toInt(), block, this) }
|
||||
.sortedBy { it.startTime }
|
||||
}
|
||||
|
||||
override val channels: Map<Int, NumassBlock>
|
||||
get() = proto.channelsList.groupBy { it.id.toInt() }.mapValues { entry ->
|
||||
MetaBlock(entry.value.flatMap { it.blocksList }.map { ProtoBlock(entry.key, it, this) })
|
||||
}
|
||||
|
||||
override val voltage: Double get() = meta["external_meta.HV1_value"].double ?: super.voltage
|
||||
|
||||
override val index: Int get() = meta["external_meta.point_index"].int ?: super.index
|
||||
|
||||
override val startTime: Instant
|
||||
get() = meta["start_time"].long?.let {
|
||||
Instant.ofEpochMilli(it)
|
||||
} ?: super.startTime
|
||||
|
||||
override val length: Duration
|
||||
get() = meta["acquisition_time"].double?.let {
|
||||
Duration.ofMillis((it * 1000).toLong())
|
||||
} ?: super.length
|
||||
|
||||
|
||||
public companion object {
|
||||
|
||||
|
||||
/**
|
||||
* Get valid data stream utilizing compression if it is present
|
||||
*/
|
||||
private fun <R> Envelope.useData(block: (InputStream) -> R): R? = when {
|
||||
data == null -> null
|
||||
meta["compression"].string == "zlib" -> {
|
||||
//TODO move to new type of data
|
||||
val inflater = Inflater()
|
||||
|
||||
val array: ByteArray = data?.read {
|
||||
readByteArray()
|
||||
} ?: ByteArray(0)
|
||||
|
||||
inflater.setInput(array)
|
||||
val bos = ByteArrayOutputStream()
|
||||
val buffer = ByteArray(8192)
|
||||
while (!inflater.finished()) {
|
||||
val size = inflater.inflate(buffer)
|
||||
bos.write(buffer, 0, size)
|
||||
}
|
||||
val unzippeddata = bos.toByteArray()
|
||||
inflater.end()
|
||||
ByteArrayInputStream(unzippeddata).use(block)
|
||||
}
|
||||
else -> {
|
||||
data?.read {
|
||||
block(asInputStream())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun fromEnvelope(envelope: Envelope): ProtoNumassPoint? {
|
||||
val proto = envelope.useData {
|
||||
NumassProto.Point.parseFrom(it)
|
||||
}
|
||||
return proto?.let { ProtoNumassPoint(envelope.meta) { it } }
|
||||
}
|
||||
|
||||
public fun fromFile(context: Context, path: Path): ProtoNumassPoint? {
|
||||
val envelope = context.io.readEnvelopeFile(path) ?: error("Envelope could not be read from $path")
|
||||
return fromEnvelope(envelope)
|
||||
}
|
||||
|
||||
public fun fromFile(context: Context, path: String): ProtoNumassPoint? {
|
||||
return fromFile(context,Path.of(path))
|
||||
}
|
||||
|
||||
public fun ofEpochNanos(nanos: Long): Instant {
|
||||
val seconds = Math.floorDiv(nanos, 1e9.toInt().toLong())
|
||||
val reminder = (nanos % 1e9).toInt()
|
||||
return Instant.ofEpochSecond(seconds, reminder.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ProtoBlock(
|
||||
override val channel: Int,
|
||||
private val block: NumassProto.Point.Channel.Block,
|
||||
public val parent: NumassPoint? = null,
|
||||
) : NumassBlock {
|
||||
|
||||
override val startTime: Instant
|
||||
get() = ProtoNumassPoint.ofEpochNanos(block.time)
|
||||
|
||||
override val length: Duration = when {
|
||||
block.length > 0 -> Duration.ofNanos(block.length)
|
||||
parent?.meta["acquisition_time"] != null ->
|
||||
Duration.ofMillis((parent?.meta["acquisition_time"].double ?: 0.0 * 1000).toLong())
|
||||
else -> {
|
||||
LoggerFactory.getLogger(javaClass)
|
||||
.error("No length information on block. Trying to infer from first and last events")
|
||||
val times = runBlocking { events.map { it.timeOffset }.toList() }
|
||||
val nanos = (times.maxOrNull()!! - times.minOrNull()!!)
|
||||
Duration.ofNanos(nanos)
|
||||
}
|
||||
}
|
||||
|
||||
override val events: Flow<NumassEvent>
|
||||
get() = if (block.hasEvents()) {
|
||||
val events = block.events
|
||||
if (events.timesCount != events.amplitudesCount) {
|
||||
LoggerFactory.getLogger(javaClass)
|
||||
.error("The block is broken. Number of times is ${events.timesCount} and number of amplitudes is ${events.amplitudesCount}")
|
||||
}
|
||||
(0..events.timesCount).asFlow()
|
||||
.map { i -> NumassEvent(events.getAmplitudes(i).toShort(), events.getTimes(i), this) }
|
||||
} else {
|
||||
emptyFlow<NumassEvent>()
|
||||
}
|
||||
|
||||
|
||||
override val frames: Flow<NumassFrame>
|
||||
get() {
|
||||
val tickSize = Duration.ofNanos(block.binSize)
|
||||
return block.framesList.asFlow().map { frame ->
|
||||
val time = startTime.plusNanos(frame.time)
|
||||
val frameData = frame.data.asReadOnlyByteBuffer()
|
||||
NumassFrame(time, tickSize, frameData.asShortBuffer())
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package ru.inr.mass.data.proto;
|
||||
|
||||
message Point {
|
||||
// A single channel for multichannel detector readout
|
||||
message Channel {
|
||||
//A continuous measurement block
|
||||
message Block {
|
||||
// Raw data frame
|
||||
message Frame {
|
||||
uint64 time = 1; // Time in nanos from the beginning of the block
|
||||
bytes data = 2; // Frame data as an array of int16 mesured in arbitrary channels
|
||||
}
|
||||
// Event block obtained directly from device of from frame analysis
|
||||
// In order to save space, times and amplitudes are in separate arrays.
|
||||
// Amplitude and time with the same index correspond to the same event
|
||||
message Events {
|
||||
repeated uint64 times = 1; // Array of time in nanos from the beginning of the block
|
||||
repeated uint64 amplitudes = 2; // Array of amplitudes of events in channels
|
||||
}
|
||||
|
||||
uint64 time = 1; // Block start in epoch nanos
|
||||
repeated Frame frames = 2; // Frames array
|
||||
Events events = 3; // Events array
|
||||
uint64 length = 4; // block size in nanos. If missing, take from meta.
|
||||
uint64 bin_size = 5; // tick size in nanos. Obsolete, to be removed
|
||||
}
|
||||
uint64 id = 1; // The number of measuring channel
|
||||
repeated Block blocks = 2; // Blocks
|
||||
}
|
||||
repeated Channel channels = 1; // Array of measuring channels
|
||||
}
|
28
settings.gradle.kts
Normal file
28
settings.gradle.kts
Normal file
@ -0,0 +1,28 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
gradlePluginPortal()
|
||||
maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||
maven("https://dl.bintray.com/kotlin/kotlin-dev")
|
||||
maven("https://dl.bintray.com/mipt-npm/dataforge")
|
||||
maven("https://dl.bintray.com/mipt-npm/kscience")
|
||||
maven("https://dl.bintray.com/mipt-npm/dev")
|
||||
}
|
||||
|
||||
val toolsVersion = "0.7.1"
|
||||
val kotlinVersion = "1.4.21"
|
||||
|
||||
plugins {
|
||||
id("ru.mipt.npm.project") version toolsVersion
|
||||
id("ru.mipt.npm.mpp") version toolsVersion
|
||||
id("ru.mipt.npm.jvm") version toolsVersion
|
||||
id("ru.mipt.npm.js") version toolsVersion
|
||||
id("ru.mipt.npm.publish") version toolsVersion
|
||||
kotlin("jvm") version kotlinVersion
|
||||
kotlin("js") version kotlinVersion
|
||||
}
|
||||
}
|
||||
|
||||
include("numass-data-model")
|
||||
include("numass-data-proto")
|
Loading…
Reference in New Issue
Block a user