Initial commit for new gradle model
This commit is contained in:
commit
dc5a97c002
12
.hgignore
Normal file
12
.hgignore
Normal file
@ -0,0 +1,12 @@
|
||||
syntax: glob
|
||||
*.orig
|
||||
*.orig.*
|
||||
*.chg.*
|
||||
*.rej
|
||||
*.conflict
|
||||
build/*
|
||||
target/*
|
||||
.gradle/*
|
||||
.nb-gradle/*
|
||||
.idea/
|
||||
*.iml
|
42
build.gradle
Normal file
42
build.gradle
Normal file
@ -0,0 +1,42 @@
|
||||
apply plugin: 'base'
|
||||
apply plugin: 'project-report'
|
||||
apply plugin: 'build-dashboard'
|
||||
|
||||
|
||||
htmlDependencyReport {
|
||||
projects = project.allprojects
|
||||
}
|
||||
|
||||
File dataforgeDir = new File(rootDir,'../dataforge');
|
||||
|
||||
if(dataforgeDir.exists()){
|
||||
rootProject.ext.dataforgeLocal = true;
|
||||
}
|
||||
|
||||
subprojects{
|
||||
if(path.startsWith(':dataforge')){
|
||||
apply from: new File(dataforgeDir, 'dataforge.gradle')
|
||||
}
|
||||
if(path.startsWith(':numass')){
|
||||
apply from: rootProject.file('numass.gradle')
|
||||
}
|
||||
}
|
||||
|
||||
buildscript {
|
||||
repositories { jcenter() }
|
||||
dependencies {
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.+'
|
||||
}
|
||||
}
|
||||
//task mergedJavadoc(type: Javadoc, description: 'Creates Javadoc from all the projects.') {
|
||||
// title = 'All modules'
|
||||
// destinationDir = new File(project.buildDir, 'merged-javadoc')
|
||||
//
|
||||
// // Note: The closures below are executed lazily.
|
||||
// source {
|
||||
// subprojects*.sourceSets*.main*.allSource
|
||||
// }
|
||||
// classpath.from {
|
||||
// subprojects*.configurations*.compile*.copyRecursive({!(it instanceof ProjectDependency)})*.resolve()
|
||||
// }
|
||||
//}
|
2
numass-control/build.gradle
Normal file
2
numass-control/build.gradle
Normal file
@ -0,0 +1,2 @@
|
||||
apply plugin: 'base' // To add "clean" task to the root project.
|
||||
|
17
numass-control/cryotemp/build.gradle
Normal file
17
numass-control/cryotemp/build.gradle
Normal file
@ -0,0 +1,17 @@
|
||||
apply plugin: 'application'
|
||||
|
||||
if (!hasProperty('mainClass')) {
|
||||
ext.mainClass = 'inr.numass.cryotemp.PKT8App'
|
||||
}
|
||||
mainClassName = mainClass
|
||||
|
||||
|
||||
//mainClassName = "inr.numass.readvac.Main"
|
||||
|
||||
dependencies {
|
||||
compile 'commons-cli:commons-cli:1.3'
|
||||
compile 'de.jensd:shichimifx:1.0.5'
|
||||
compile project(':dataforge-control')
|
||||
compile project(':dataforge-storage')
|
||||
compile project(':dataforge-plots')
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.cryotemp;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.storage.commons.StoragePlugin;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
public class PKT8App extends Application {
|
||||
|
||||
PKT8MainViewController controller;
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws IOException, ControlException {
|
||||
Locale.setDefault(Locale.US);// чтобы отделение десятичных знаков было точкой
|
||||
ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
||||
rootLogger.setLevel(Level.INFO);
|
||||
new StoragePlugin().startGlobal();
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/PKT8MainView.fxml"));
|
||||
|
||||
Parent parent = loader.load();
|
||||
controller = loader.getController();
|
||||
|
||||
// Meta deviceMeta = XMLMetaConverter.fromStream(getClass().getResourceAsStream("/defaultConfig.xml"));
|
||||
|
||||
// controller.setupDevice(deviceMeta);
|
||||
|
||||
Scene scene = new Scene(parent, 600, 400);
|
||||
|
||||
|
||||
primaryStage.setTitle("PKT8 cryogenic temperature viewer");
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setMinHeight(400);
|
||||
primaryStage.setMinWidth(600);
|
||||
// primaryStage.setResizable(false);
|
||||
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
super.stop();
|
||||
if(controller!=null){
|
||||
controller.close();
|
||||
controller = null;
|
||||
}
|
||||
// System.exit(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,418 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.cryotemp;
|
||||
|
||||
import hep.dataforge.content.Named;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.control.collectors.RegularPointCollector;
|
||||
import hep.dataforge.control.devices.DataDevice;
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
import hep.dataforge.control.ports.TcpPortHandler;
|
||||
import hep.dataforge.data.DataFormatBuilder;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import hep.dataforge.exceptions.StorageException;
|
||||
import hep.dataforge.meta.Annotated;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaBuilder;
|
||||
import hep.dataforge.storage.api.PointLoader;
|
||||
import hep.dataforge.storage.api.Storage;
|
||||
import hep.dataforge.storage.commons.LoaderFactory;
|
||||
import hep.dataforge.values.Value;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A device controller for Dubna PKT 8 cryogenic thermometry device
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class PKT8Device extends DataDevice<PKT8Device.PKT8Measurement> implements PortHandler.PortController {
|
||||
|
||||
private static final String[] CHANNEL_DESIGNATIONS = {"a", "b", "c", "d", "e", "f", "g", "h"};
|
||||
|
||||
private PointLoader pointLoader;
|
||||
private RegularPointCollector collector;
|
||||
|
||||
private boolean isStarted = false;
|
||||
private PortHandler handler;
|
||||
private int sps = -1;
|
||||
private int pga = -1;
|
||||
private int abuf = -1;
|
||||
|
||||
/**
|
||||
* The key is the letter (a,b,c,d...) as in measurements
|
||||
*/
|
||||
private final Map<String, PKT8Channel> channels = new HashMap<>();
|
||||
|
||||
public PKT8Device(String name, Context context, Meta annotation) {
|
||||
super(name, context, annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start measurement
|
||||
*
|
||||
* @throws ControlException
|
||||
*/
|
||||
@Override
|
||||
public void doStart(Meta measurement) throws ControlException {
|
||||
|
||||
// Meta meta = new MetaChain("device", measurement.meta(),meta());
|
||||
if (!isStarted) {
|
||||
//setup storage
|
||||
|
||||
try {
|
||||
Storage storage = getPrimaryStorage(measurement);
|
||||
String suffix = Integer.toString((int) Instant.now().toEpochMilli());
|
||||
|
||||
// Building data format
|
||||
DataFormatBuilder formatBuilder = new DataFormatBuilder()
|
||||
.addTime("timestamp");
|
||||
List<String> names = new ArrayList<>();
|
||||
|
||||
for (PKT8Channel channel : this.channels.values()) {
|
||||
formatBuilder.addNumber(channel.getName());
|
||||
names.add(channel.getName());
|
||||
}
|
||||
|
||||
this.pointLoader = LoaderFactory.buildPointLoder(storage, "cryotemp_" + suffix, "", "timestamp", formatBuilder.build());
|
||||
|
||||
Duration duration = Duration.parse(meta().getString("averagingDuration", "PT30S"));
|
||||
|
||||
collector = new RegularPointCollector((dp) -> {
|
||||
if (pointLoader != null) {
|
||||
try {
|
||||
getLogger().debug("Point measurement complete. Pushing...");
|
||||
pointLoader.push(dp);
|
||||
} catch (StorageException ex) {
|
||||
getLogger().error("Error while pushing point to loader", ex);
|
||||
}
|
||||
}
|
||||
}, duration, names);
|
||||
} catch (StorageException ex) {
|
||||
getLogger().error("Can't setup storage", ex);
|
||||
}
|
||||
|
||||
handler.send("s");
|
||||
isStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws ControlException {
|
||||
|
||||
//read channel configuration
|
||||
if (meta().hasNode("channel")) {
|
||||
for (Meta node : meta().getNodes("channel")) {
|
||||
String designation = node.getString("designation", "default");
|
||||
this.channels.put(designation, new PKT8Channel(node));
|
||||
}
|
||||
} else {
|
||||
//set default channel configuration
|
||||
for (String designation : CHANNEL_DESIGNATIONS) {
|
||||
channels.put(designation, new PKT8Channel(designation));
|
||||
}
|
||||
getLogger().warn("No channels defined in configuration");
|
||||
}
|
||||
|
||||
//setup connection
|
||||
if (meta().hasNode("debug")) {
|
||||
handler = new PKT8VirtualPort("PKT8", meta().getNode("debug"));
|
||||
} else {
|
||||
String ip = this.meta().getString("connection.ip", "127.0.0.1");
|
||||
int port = this.meta().getInt("connection.port", 4001);
|
||||
handler = new TcpPortHandler(ip, port, getName());
|
||||
}
|
||||
handler.setDelimeter("\n");
|
||||
handler.holdBy(this);
|
||||
handler.open();
|
||||
handler.send("p");
|
||||
handler.sendAndWait("p", null, 1000);
|
||||
|
||||
//update parameters from meta
|
||||
if (meta().hasValue("pga")) {
|
||||
getLogger().info("Setting dynamic range to " + meta().getInt("pga"));
|
||||
String response = handler.sendAndWait("g" + meta().getInt("pga"), null, 400).trim();
|
||||
if (response.contains("=")) {
|
||||
this.pga = Integer.parseInt(response.substring(4));
|
||||
} else {
|
||||
getLogger().error("Setting pga failsed with message: " + response);
|
||||
}
|
||||
}
|
||||
|
||||
setSPS(meta().getInt("sps", 0));
|
||||
setBUF(meta().getInt("abuf", 100));
|
||||
|
||||
super.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() throws ControlException {
|
||||
stop();
|
||||
try {
|
||||
this.handler.unholdBy(this);
|
||||
this.handler.close();
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new ControlException(ex);
|
||||
}
|
||||
super.shutdown();
|
||||
}
|
||||
|
||||
private void setSPS(int sps) throws PortException {
|
||||
getLogger().info("Setting sampling rate to " + spsToStr(sps));
|
||||
String response = handler.sendAndWait("v" + sps, null, 400).trim();
|
||||
if (response.contains("=")) {
|
||||
this.sps = Integer.parseInt(response.substring(4));
|
||||
getLogger().info("successfully sampling rate to {}", spsToStr(this.sps));
|
||||
} else {
|
||||
getLogger().error("Setting sps failsed with message: " + response);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<PKT8Channel> getChanels() {
|
||||
return this.channels.values();
|
||||
}
|
||||
|
||||
private void setBUF(int buf) throws PortException {
|
||||
getLogger().info("Setting avaraging buffer size to " + buf);
|
||||
String response = handler.sendAndWait("b" + buf, null, 400).trim();
|
||||
if (response.contains("=")) {
|
||||
this.abuf = Integer.parseInt(response.substring(14));
|
||||
getLogger().info("successfully set buffer size to {}", this.abuf);
|
||||
} else {
|
||||
getLogger().error("Setting averaging buffer failsed with message: " + response);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doStop() throws ControlException {
|
||||
handler.send("p");
|
||||
isStarted = false;
|
||||
if (collector != null) {
|
||||
collector.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public void changeParameters(int sps, int abuf) {
|
||||
this.executor.submit(() -> {
|
||||
try {
|
||||
stop();
|
||||
//setting sps
|
||||
setSPS(sps);
|
||||
//setting buffer
|
||||
setBUF(abuf);
|
||||
start();
|
||||
} catch (ControlException ex) {
|
||||
getLogger().error("Control error", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(String message) {
|
||||
String trimmed = message.trim();
|
||||
|
||||
if (isStarted) {
|
||||
if (trimmed.equals("stopped")) {
|
||||
isStarted = false;
|
||||
getLogger().info("Measurement paused");
|
||||
} else {
|
||||
String designation = trimmed.substring(0, 1);
|
||||
double rawValue = Double.parseDouble(trimmed.substring(1)) / 100;
|
||||
|
||||
if (channels.containsKey(designation)) {
|
||||
PKT8Channel channel = channels.get(designation);
|
||||
notifyMeasurementComplete(channel.getName(), rawValue, channel.getTemperature(rawValue));
|
||||
collector.put(channel.getName(), channel.getTemperature(rawValue));
|
||||
} else {
|
||||
notifyMeasurementComplete(designation, rawValue, -1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyMeasurementComplete(String channel, double rawValue, double temperature) {
|
||||
measurementResult(null, new PKT8Measurement(channel, rawValue, temperature));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String errorMessage, Throwable error) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* '0' : 2,5 SPS '1' : 5 SPS '2' : 10 SPS '3' : 25 SPS '4' : 50 SPS '5' :
|
||||
* 100 SPS '6' : 500 SPS '7' : 1 kSPS '8' : 3,75 kSPS
|
||||
*
|
||||
* @param sps
|
||||
* @return
|
||||
*/
|
||||
private String spsToStr(int sps) {
|
||||
switch (sps) {
|
||||
case 0:
|
||||
return "2,5 SPS";
|
||||
case 1:
|
||||
return "5 SPS";
|
||||
case 2:
|
||||
return "10 SPS";
|
||||
case 3:
|
||||
return "25 SPS";
|
||||
case 4:
|
||||
return "50 SPS";
|
||||
case 5:
|
||||
return "100 SPS";
|
||||
case 6:
|
||||
return "500 SPS";
|
||||
case 7:
|
||||
return "1 kSPS";
|
||||
case 8:
|
||||
return "3.75 kSPS";
|
||||
default:
|
||||
return "unknown value";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* '0' : ± 5 В '1' : ± 2,5 В '2' : ± 1,25 В '3' : ± 0,625 В '4' : ± 312.5 мВ
|
||||
* '5' : ± 156,25 мВ '6' : ± 78,125 мВ
|
||||
*
|
||||
* @param sps
|
||||
* @return
|
||||
*/
|
||||
private String pgaToStr(int sps) {
|
||||
switch (sps) {
|
||||
case 0:
|
||||
return "± 5 V";
|
||||
case 1:
|
||||
return "± 2,5 V";
|
||||
case 2:
|
||||
return "± 1,25 V";
|
||||
case 3:
|
||||
return "± 0,625 V";
|
||||
case 4:
|
||||
return "± 312.5 mV";
|
||||
case 5:
|
||||
return "± 156,25 mV";
|
||||
case 6:
|
||||
return "± 78,125 mV";
|
||||
default:
|
||||
return "unknown value";
|
||||
}
|
||||
}
|
||||
|
||||
public String getSPS() {
|
||||
return spsToStr(sps);
|
||||
}
|
||||
|
||||
public String getPGA() {
|
||||
return pgaToStr(pga);
|
||||
}
|
||||
|
||||
public String getABUF() {
|
||||
return Integer.toString(abuf);
|
||||
}
|
||||
|
||||
public class PKT8Channel implements Named, Annotated {
|
||||
|
||||
private final Meta meta;
|
||||
private final Function<Double, Double> transformation;
|
||||
|
||||
public PKT8Channel(String name) {
|
||||
this.meta = new MetaBuilder("channel")
|
||||
.putValue("name", name);
|
||||
transformation = (d) -> d;
|
||||
}
|
||||
|
||||
public PKT8Channel(Meta meta) {
|
||||
this.meta = meta;
|
||||
|
||||
String transformationType = meta.getString("transformationType", "default");
|
||||
if (meta.hasValue("coefs")) {
|
||||
switch (transformationType) {
|
||||
case "default":
|
||||
case "hyperbolic":
|
||||
List<Value> coefs = meta.getValue("coefs").listValue();
|
||||
double r0 = meta.getDouble("r0", 1000);
|
||||
transformation = (r) -> {
|
||||
if (coefs == null) {
|
||||
return -1d;
|
||||
} else {
|
||||
double res = 0;
|
||||
for (int i = 0; i < coefs.size(); i++) {
|
||||
res += coefs.get(i).doubleValue() * Math.pow(r0 / r, i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Unknown transformation type");
|
||||
}
|
||||
} else {
|
||||
//identity transformation
|
||||
transformation = (d) -> d;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return meta().getString("name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Meta meta() {
|
||||
return meta;
|
||||
}
|
||||
|
||||
public String description() {
|
||||
return meta().getString("description", "");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param r negative if temperature transformation not defined
|
||||
* @return
|
||||
*/
|
||||
public double getTemperature(double r) {
|
||||
return transformation.apply(r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class PKT8Measurement {
|
||||
|
||||
public String channel;
|
||||
public double rawValue;
|
||||
public double temperature;
|
||||
|
||||
public PKT8Measurement(String channel, double rawValue, double temperature) {
|
||||
this.channel = channel;
|
||||
this.rawValue = rawValue;
|
||||
this.temperature = temperature;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.cryotemp;
|
||||
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.Appender;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
import de.jensd.shichimifx.utils.SplitPaneDividerSlider;
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import hep.dataforge.control.devices.Device;
|
||||
import hep.dataforge.control.devices.DeviceListener;
|
||||
import hep.dataforge.control.devices.MeasurementDevice;
|
||||
import hep.dataforge.control.devices.MeasurementListener;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.io.MetaFileReader;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaBuilder;
|
||||
import hep.dataforge.meta.MetaUtils;
|
||||
import hep.dataforge.plots.XYPlotFrame;
|
||||
import hep.dataforge.plots.data.DynamicPlottable;
|
||||
import hep.dataforge.plots.data.DynamicPlottableSet;
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||
import hep.dataforge.values.Value;
|
||||
import inr.numass.cryotemp.PKT8Device.PKT8Measurement;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.text.ParseException;
|
||||
import java.time.Instant;
|
||||
import java.util.Collection;
|
||||
import java.util.ResourceBundle;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.SplitPane;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.ToggleButton;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.stage.FileChooser;
|
||||
|
||||
/**
|
||||
* FXML Controller class
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
public class PKT8MainViewController implements Initializable, DeviceListener, MeasurementListener<PKT8Measurement>, AutoCloseable {
|
||||
|
||||
public static final String DEFAULT_CONFIG_LOCATION = "devices.xml";
|
||||
private PKT8Device device;
|
||||
private XYPlotFrame plotFrame;
|
||||
private DynamicPlottableSet plottables;
|
||||
private Meta currentPlotConfig;
|
||||
|
||||
@FXML
|
||||
private Button loadConfigButton;
|
||||
@FXML
|
||||
private SplitPane consoleSplitPane;
|
||||
@FXML
|
||||
private TextArea logArea;
|
||||
@FXML
|
||||
private ToggleButton startStopButton;
|
||||
@FXML
|
||||
private AnchorPane plotArea;
|
||||
|
||||
@FXML
|
||||
private ToggleButton consoleButton;
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if (device != null) {
|
||||
device.stop();
|
||||
device.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the controller class.
|
||||
*/
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
setupPlotFrame(null);
|
||||
SplitPaneDividerSlider slider = new SplitPaneDividerSlider(consoleSplitPane, 0, SplitPaneDividerSlider.Direction.DOWN);
|
||||
consoleButton.selectedProperty().addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) -> {
|
||||
slider.setAimContentVisible(newValue);
|
||||
});
|
||||
slider.setAimContentVisible(false);
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onLoadConfigClick(ActionEvent event) throws IOException, ParseException, ControlException {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("Open configuration file");
|
||||
fileChooser.setInitialFileName(DEFAULT_CONFIG_LOCATION);
|
||||
fileChooser.setInitialDirectory(GlobalContext.instance().io().getRootDirectory());
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("xml", "*.xml", "*.XML"));
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("json", "*.json", "*.JSON"));
|
||||
// fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("all", "*.*"));
|
||||
File cfgFile = fileChooser.showOpenDialog(loadConfigButton.getScene().getWindow());
|
||||
|
||||
if (cfgFile != null) {
|
||||
setConfig(MetaFileReader.read(cfgFile));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadTestConfig() throws ControlException {
|
||||
try {
|
||||
Meta testConfig = MetaFileReader
|
||||
.read(new File(getClass().getResource("/config/defaultConfig.xml").toURI()));
|
||||
setConfig(testConfig);
|
||||
} catch (URISyntaxException | IOException | ParseException ex) {
|
||||
throw new Error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return "PKT8";
|
||||
}
|
||||
|
||||
public void setConfig(Meta config) throws ControlException {
|
||||
if (config.hasNode("plotConfig")) {
|
||||
Meta plotConfig = MetaUtils.findNodeByValue(config, "plotConfig", "device", getDeviceName());
|
||||
if (plotConfig == null) {
|
||||
plotConfig = config.getNode("plotConfig");
|
||||
}
|
||||
|
||||
setupPlotFrame(plotConfig.getNode("plotFrame", null));
|
||||
currentPlotConfig = plotConfig;
|
||||
}
|
||||
|
||||
if (config.hasNode("device")) {
|
||||
Meta deviceMeta = MetaUtils.findNodeByValue(config, "device", "name", Value.of(getDeviceName()));
|
||||
setupDevice(deviceMeta);
|
||||
} else {
|
||||
setupDevice(config);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set o reset plot area
|
||||
*/
|
||||
private void setupPlotFrame(Meta plotFrameMeta) {
|
||||
plottables = new DynamicPlottableSet();
|
||||
plotArea.getChildren().clear();
|
||||
Meta plotConfig;
|
||||
if (plotFrameMeta != null) {
|
||||
plotConfig = new MetaBuilder(plotFrameMeta)
|
||||
.setValue("xAxis.timeAxis", true);
|
||||
} else {
|
||||
plotConfig = new MetaBuilder("plotFrame")
|
||||
.setValue("xAxis.timeAxis", true);
|
||||
}
|
||||
plotFrame = new JFreeChartFrame("plot", plotConfig, plotArea);
|
||||
}
|
||||
|
||||
public void setupDevice(Meta deviceMeta) throws ControlException {
|
||||
if (device != null) {
|
||||
device.stop();
|
||||
device.shutdown();
|
||||
}
|
||||
|
||||
this.device = new PKT8Device("PKT8", GlobalContext.instance(), deviceMeta);
|
||||
device.addDeviceListener(this);
|
||||
device.addMeasurementListener(this);
|
||||
|
||||
logArea.appendText("Starting log...\n");
|
||||
|
||||
Appender<ILoggingEvent> appender = new AppenderBase<ILoggingEvent>() {
|
||||
// private final DateTimeFormatter formatter = DateTimeFormatter.ISO_TIME;
|
||||
@Override
|
||||
protected void append(ILoggingEvent e) {
|
||||
logArea.appendText(String.format("%s > (%s) [%s] %s%n",
|
||||
e.getLoggerName(),
|
||||
Instant.now().toString(),
|
||||
e.getLevel(),
|
||||
e.getFormattedMessage()));
|
||||
}
|
||||
};
|
||||
|
||||
appender.start();
|
||||
|
||||
device.getLogger().addAppender(appender);
|
||||
|
||||
device.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDeviceInitialized(Device device) {
|
||||
Collection<PKT8Device.PKT8Channel> channels = this.device.getChanels();
|
||||
for (PKT8Device.PKT8Channel channel : channels) {
|
||||
if (!plottables.hasPlottable(channel.getName())) {
|
||||
|
||||
//plot config from device configuration
|
||||
Meta deviceLineMeta = channel.meta().getNode("plot", channel.meta());
|
||||
|
||||
//Do not use view config here, it is applyed separately
|
||||
DynamicPlottable plottable = new DynamicPlottable(channel.getName(), deviceLineMeta);
|
||||
plottables.addPlottable(plottable);
|
||||
plotFrame.add(plottable);
|
||||
}
|
||||
}
|
||||
startStopButton.setDisable(false);
|
||||
|
||||
if (currentPlotConfig != null) {
|
||||
applyViewConfig(currentPlotConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyViewConfig(Meta viewConfig) {
|
||||
plottables.applyConfig(viewConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDeviceShutdown(Device device) {
|
||||
startStopButton.setDisable(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDeviceStateChanged(Device device, String name, Value oldState, Value newState) {
|
||||
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void sendMessage(Device device, int priority, Meta message) {
|
||||
// String tag = message.getString("tag", "");
|
||||
// logArea.appendText(String.format("%s > (%s) [%s] %s%n", device.getName(), Instant.now().toString(), tag, message));
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void notifyMeasurementStarted(MeasurementDevice device, Meta measurement) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyMeasurementStopped(MeasurementDevice device) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyMeasurementResult(MeasurementDevice device, Meta measurement, PKT8Measurement measurementResult) {
|
||||
plottables.put(measurementResult.channel, measurementResult.temperature);
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onStartStopClick(ActionEvent event) {
|
||||
if (device != null) {
|
||||
try {
|
||||
if (startStopButton.isSelected()) {
|
||||
device.start();
|
||||
} else {
|
||||
//in case device started
|
||||
device.stop();
|
||||
}
|
||||
} catch (ControlException ex) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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 inr.numass.cryotemp;
|
||||
|
||||
import hep.dataforge.control.ports.VirtualPort;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import hep.dataforge.meta.Annotated;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaUtils;
|
||||
import hep.dataforge.values.Value;
|
||||
import java.time.Duration;
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class PKT8VirtualPort extends VirtualPort implements Annotated {
|
||||
|
||||
private final Meta meta;
|
||||
private final Random generator = new Random();
|
||||
|
||||
public PKT8VirtualPort(String portName, Meta meta) {
|
||||
super(portName);
|
||||
this.meta = meta;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Meta meta() {
|
||||
return meta;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void evaluateRequest(String request) {
|
||||
switch (request) {
|
||||
case "s":
|
||||
String[] letters = {"a", "b", "c", "d", "e", "f", "g", "h"};
|
||||
for (String letter : letters) {
|
||||
Meta channelMeta = MetaUtils.findNodeByValue(meta(), "channel", "letter", Value.of(letter));
|
||||
|
||||
double average;
|
||||
double sigma;
|
||||
if (channelMeta != null) {
|
||||
average = channelMeta.getDouble("av", 1200);
|
||||
sigma = channelMeta.getDouble("sigma", 50);
|
||||
} else {
|
||||
average = 1200d;
|
||||
sigma = 50d;
|
||||
}
|
||||
|
||||
this.planRegularResponse(
|
||||
() -> {
|
||||
double res = average + generator.nextGaussian() * sigma;
|
||||
//TODO convert double value to formatted string
|
||||
return letter + "000120000\n";
|
||||
},
|
||||
Duration.ZERO, Duration.ofSeconds(5), letter, "measurement"
|
||||
);
|
||||
}
|
||||
return;
|
||||
case "p":
|
||||
cancelByTag("measurement");
|
||||
this.recievePhrase("stopped\n\r");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws PortException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
cancelByTag("measurement");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<device>
|
||||
<storage path="D:\\temp\\cryo"/>
|
||||
<connection ip="192.168.111.137" port="4001"/>
|
||||
<abuf>120</abuf>
|
||||
<channel designation="a" name="a-channel" r0="1000" transformationType="hyperbolic" coefs="[1.0,1.0]" color="black"/>
|
||||
<channel designation="b" name="b-channel" r0="1000" transformationType="hyperbolic" coefs="[1.1,1.1]"/>
|
||||
<channel designation="c" name="c-channel" r0="1000" transformationType="hyperbolic" coefs="[1.2,1.0]" thickness="2"/>
|
||||
<channel designation="d" name="d-channel" r0="1000" transformationType="hyperbolic" coefs="[1.3,1.0]"/>
|
||||
<plotConfig>
|
||||
<eachPlot thickness="4"/>
|
||||
<plot name = "c-channel" color="magenta"/>
|
||||
</plotConfig>
|
||||
</device>
|
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Copyright 2015 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.
|
||||
-->
|
||||
|
||||
<?import java.lang.*?>
|
||||
<?import java.util.*?>
|
||||
<?import javafx.scene.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.cryotemp.PKT8MainViewController">
|
||||
<children>
|
||||
<SplitPane fx:id="consoleSplitPane" dividerPositions="0.8" layoutX="184.0" layoutY="62.0" orientation="VERTICAL" prefHeight="200.0" prefWidth="160.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="40.0">
|
||||
<items>
|
||||
<AnchorPane fx:id="plotArea" minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0" />
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="94.0" prefWidth="598.0">
|
||||
<children>
|
||||
<TextArea fx:id="logArea" editable="false" layoutX="38.0" layoutY="-75.0" prefHeight="200.0" prefWidth="200.0" wrapText="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</items>
|
||||
</SplitPane>
|
||||
<ToolBar prefHeight="40.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<items>
|
||||
<ToggleButton fx:id="startStopButton" disable="true" mnemonicParsing="false" onAction="#onStartStopClick" prefWidth="50.0" text="Start" />
|
||||
<Separator orientation="VERTICAL" />
|
||||
<Button fx:id="loadConfigButton" mnemonicParsing="false" onAction="#onLoadConfigClick" text="Load config" />
|
||||
<ToggleButton fx:id="consoleButton" contentDisplay="CENTER" mnemonicParsing="false" text="Console" />
|
||||
</items>
|
||||
</ToolBar>
|
||||
</children>
|
||||
</AnchorPane>
|
26
numass-control/magnet/build.gradle
Normal file
26
numass-control/magnet/build.gradle
Normal file
@ -0,0 +1,26 @@
|
||||
apply plugin: 'application'
|
||||
|
||||
version = "0.2.5"
|
||||
|
||||
if (!hasProperty('mainClass')) {
|
||||
ext.mainClass = 'inr.numass.control.magnet.fx.MagnetControllerApp'
|
||||
}
|
||||
mainClassName = mainClass
|
||||
|
||||
dependencies {
|
||||
compile 'ch.qos.logback:logback-classic:1.1.0+'
|
||||
compile 'org.scream3r:jssc:2.8.0'
|
||||
compile project(':dataforge-control')
|
||||
}
|
||||
|
||||
task talkToServer(type: JavaExec) {
|
||||
description 'Console talk to remote server'
|
||||
|
||||
// Set main property to name of Groovy script class.
|
||||
main = 'inr.numass.control.magnet.Talk'
|
||||
|
||||
// Set classpath for running the Groovy script.
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
standardInput = System.in
|
||||
standardOutput = System.out
|
||||
}
|
@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.magnet;
|
||||
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
import hep.dataforge.control.ports.PortTimeoutException;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Polina
|
||||
*/
|
||||
public class MagnetController implements PortHandler.PortController {
|
||||
|
||||
public static double CURRENT_PRECISION = 0.01;
|
||||
// public static double CURRENT_STEP = 0.05;
|
||||
public static int DEFAULT_DELAY = 1;
|
||||
public static int DEFAULT_MONITOR_DELAY = 2000;
|
||||
|
||||
public static double MAX_STEP_SIZE = 0.2;
|
||||
public static double MIN_UP_STEP_SIZE = 0.005;
|
||||
public static double MIN_DOWN_STEP_SIZE = 0.05;
|
||||
public static double MAX_SPEED = 5d; // 5 A per minute
|
||||
|
||||
private static final DecimalFormat LAMBDAformat = new DecimalFormat("###.##");
|
||||
|
||||
/**
|
||||
* Method converts double to LAMBDA string
|
||||
*
|
||||
* @param d double that should be converted to string
|
||||
* @return string
|
||||
*/
|
||||
private static String d2s(double d) {
|
||||
return LAMBDAformat.format(d);
|
||||
}
|
||||
|
||||
private final String name;
|
||||
|
||||
private final PortHandler port;
|
||||
private final int address;
|
||||
private volatile double current = 0;
|
||||
|
||||
private int timeout = 200;
|
||||
private Future monitorTask;
|
||||
private Future updateTask;
|
||||
|
||||
protected MagnetStateListener listener;
|
||||
|
||||
private Instant lastUpdate = null;
|
||||
|
||||
private double speed = MAX_SPEED;
|
||||
|
||||
private final ScheduledExecutorService scheduler = new ScheduledThreadPoolExecutor(1);
|
||||
|
||||
/**
|
||||
* This method creates an element of class MegnetController with exact
|
||||
* parameters. If you have two parameters for your method - the next
|
||||
* constructor will be used.
|
||||
*
|
||||
* @param name
|
||||
* @param port number of COM-port on your computer that you want to use
|
||||
* @param address number of TDK - Lambda
|
||||
* @param timeout waiting time for response
|
||||
*/
|
||||
public MagnetController(String name, PortHandler port, int address, int timeout) {
|
||||
this.name = name;
|
||||
this.port = port;
|
||||
this.port.setDelimeter("\r");//PENDING меняем состояние внешнего объекта?
|
||||
this.address = address;
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public MagnetController(PortHandler port, int address, int timeout) {
|
||||
this(null, port, address, timeout);
|
||||
}
|
||||
|
||||
public MagnetController(PortHandler port, int address) {
|
||||
this(null, port, address);
|
||||
}
|
||||
|
||||
public MagnetController(String name, PortHandler port, int address) {
|
||||
this(name, port, address, 300);
|
||||
}
|
||||
|
||||
public void setListener(MagnetStateListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public double getMeasuredI() {
|
||||
return current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(String message) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String errorMessage, Throwable error) {
|
||||
if (this.listener != null) {
|
||||
listener.error(getName(), errorMessage, error);
|
||||
} else {
|
||||
LoggerFactory.getLogger(getClass()).error(errorMessage, error);
|
||||
}
|
||||
}
|
||||
|
||||
private String talk(String request) throws PortException {
|
||||
try {
|
||||
return port.sendAndWait(request + "\r", null, timeout).trim();
|
||||
} catch (PortTimeoutException tex) {
|
||||
//Single retry on timeout
|
||||
LoggerFactory.getLogger(getClass()).warn("A timeout exception for request '" + request + "'. Making another atempt.");
|
||||
return port.sendAndWait(request + "\r", null, timeout).trim();
|
||||
}
|
||||
}
|
||||
|
||||
private String getState(String name) throws PortException {
|
||||
String res = talk(name + "?");
|
||||
return res;
|
||||
}
|
||||
|
||||
private boolean setState(String name, String state) throws PortException {
|
||||
String res = talk(name + " " + state);
|
||||
return "OK".equals(res);
|
||||
}
|
||||
|
||||
private boolean setState(String name, int state) throws PortException {
|
||||
String res = talk(name + " " + state);
|
||||
return "OK".equals(res);
|
||||
}
|
||||
|
||||
private boolean setState(String name, double state) throws PortException {
|
||||
String res = talk(name + " " + d2s(state));
|
||||
return "OK".equals(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract number from LAMBDA response
|
||||
*
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
private double s2d(String str) {
|
||||
return Double.valueOf(str);
|
||||
}
|
||||
|
||||
private double getCurrent() throws PortException {
|
||||
if (!setADR()) {
|
||||
if (listener != null) {
|
||||
listener.error(getName(), "Can't set address", null);
|
||||
}
|
||||
throw new PortException("Can't set address");
|
||||
}
|
||||
return s2d(getState("MC"));
|
||||
}
|
||||
|
||||
protected void setCurrent(double current) throws PortException {
|
||||
if (!setState("PC", current)) {
|
||||
error("Can't set the current", null);
|
||||
} else {
|
||||
lastUpdate = Instant.now();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean setADR() throws PortException {
|
||||
if (setState("ADR", getAddress())) {
|
||||
if (listener != null) {
|
||||
listener.addressChanged(getName(), address);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets status of magnet for current moment
|
||||
*
|
||||
* @return status of magnet
|
||||
* @throws inr.numass.control.magnet.PortException
|
||||
*/
|
||||
private MagnetStatus getStatus() throws PortException {
|
||||
try {
|
||||
port.holdBy(MagnetController.this);
|
||||
|
||||
if (!setADR()) {
|
||||
return MagnetStatus.off();
|
||||
}
|
||||
|
||||
boolean out;
|
||||
|
||||
out = "ON".equals(talk("OUT?"));
|
||||
|
||||
double measuredCurrent = s2d(getState("MC"));
|
||||
this.current = measuredCurrent;
|
||||
double setCurrent = s2d(getState("PC"));
|
||||
double measuredVoltage = s2d(getState("MV"));
|
||||
double setVoltage = s2d(getState("PV"));
|
||||
|
||||
MagnetStatus monitor = new MagnetStatus(out, measuredCurrent, setCurrent, measuredVoltage, setVoltage);
|
||||
|
||||
if (listener != null) {
|
||||
listener.acceptStatus(getName(), monitor);
|
||||
}
|
||||
return monitor;
|
||||
} finally {
|
||||
port.unholdBy(MagnetController.this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel current update task
|
||||
*/
|
||||
public void stopUpdateTask() {
|
||||
if (updateTask != null) {
|
||||
updateTask.cancel(false);
|
||||
lastUpdate = null;
|
||||
if (listener != null) {
|
||||
listener.updateTaskStateChanged(getName(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startUpdateTask(double targetI) {
|
||||
startUpdateTask(targetI, DEFAULT_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start recursive updates of current with given delays between updates. If
|
||||
* delay is 0 then updates are made immediately.
|
||||
*
|
||||
* @param targetI
|
||||
* @param delay
|
||||
*/
|
||||
public void startUpdateTask(double targetI, int delay) {
|
||||
assert delay > 0;
|
||||
stopUpdateTask();
|
||||
Runnable call = () -> {
|
||||
try {
|
||||
port.holdBy(MagnetController.this);
|
||||
double measuredI = getCurrent();
|
||||
this.current = measuredI;
|
||||
|
||||
if (listener != null) {
|
||||
listener.acceptMeasuredI(getName(), measuredI);
|
||||
|
||||
}
|
||||
|
||||
if (Math.abs(measuredI - targetI) > CURRENT_PRECISION) {
|
||||
double nextI = nextI(measuredI, targetI);
|
||||
|
||||
if (listener != null) {
|
||||
listener.acceptNextI(getName(), nextI);
|
||||
}
|
||||
setCurrent(nextI);
|
||||
} else {
|
||||
stopUpdateTask();
|
||||
}
|
||||
|
||||
} catch (PortException ex) {
|
||||
error("Error in update task", ex);
|
||||
stopUpdateTask();
|
||||
} finally {
|
||||
port.unholdBy(MagnetController.this);
|
||||
}
|
||||
};
|
||||
|
||||
updateTask = scheduler.scheduleWithFixedDelay(call, 0, delay, TimeUnit.MILLISECONDS);
|
||||
if (listener != null) {
|
||||
listener.updateTaskStateChanged(getName(), true);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOutputMode(boolean out) throws PortException {
|
||||
try {
|
||||
port.holdBy(MagnetController.this);
|
||||
if (!setADR()) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
int outState;
|
||||
if (out) {
|
||||
outState = 1;
|
||||
} else {
|
||||
outState = 0;
|
||||
}
|
||||
if (!setState("OUT", outState)) {
|
||||
if (listener != null) {
|
||||
listener.error(getName(), "Can't set output mode", null);
|
||||
}
|
||||
} else if (listener != null) {
|
||||
listener.outputModeChanged(getName(), out);
|
||||
}
|
||||
} finally {
|
||||
port.unholdBy(MagnetController.this);
|
||||
}
|
||||
}
|
||||
|
||||
private double nextI(double measuredI, double targetI) {
|
||||
assert measuredI != targetI;
|
||||
|
||||
double step;
|
||||
if (lastUpdate == null) {
|
||||
step = MIN_UP_STEP_SIZE;
|
||||
} else {
|
||||
//Choose optimal speed but do not exceed maximum speed
|
||||
step = Math.min(MAX_STEP_SIZE,
|
||||
(double) lastUpdate.until(Instant.now(), ChronoUnit.MILLIS) / 60000d * getSpeed());
|
||||
}
|
||||
|
||||
double res;
|
||||
if (targetI > measuredI) {
|
||||
step = Math.max(MIN_UP_STEP_SIZE, step);
|
||||
res = Math.min(targetI, measuredI + step);
|
||||
} else {
|
||||
step = Math.max(MIN_DOWN_STEP_SIZE, step);
|
||||
res = Math.max(targetI, measuredI - step);
|
||||
}
|
||||
|
||||
// не вводится ток меньше 0.5
|
||||
if (res < 0.5 && targetI > CURRENT_PRECISION) {
|
||||
return 0.5;
|
||||
} else if (res < 0.5 && targetI < CURRENT_PRECISION) {
|
||||
return 0;
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel current monitoring task
|
||||
*/
|
||||
public void stopMonitorTask() {
|
||||
if (monitorTask != null) {
|
||||
monitorTask.cancel(false);
|
||||
if (listener != null) {
|
||||
listener.monitorTaskStateChanged(getName(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
if (this.name == null || this.name.isEmpty()) {
|
||||
return "LAMBDA " + getAddress();
|
||||
} else {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
public void startMonitorTask() {
|
||||
startMonitorTask(DEFAULT_MONITOR_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start monitoring task which checks for magnet status and then waits for
|
||||
* fixed time.
|
||||
*
|
||||
* @param delay an interval between scans in milliseconds
|
||||
*/
|
||||
public void startMonitorTask(int delay) {
|
||||
assert delay >= 1000;
|
||||
stopMonitorTask();
|
||||
|
||||
Runnable call = () -> {
|
||||
try {
|
||||
getStatus();
|
||||
} catch (PortException ex) {
|
||||
error("Port connection exception during status measurement", ex);
|
||||
stopMonitorTask();
|
||||
}
|
||||
};
|
||||
|
||||
monitorTask = scheduler.scheduleWithFixedDelay(call, 0, delay, TimeUnit.MILLISECONDS);
|
||||
|
||||
if (listener != null) {
|
||||
listener.monitorTaskStateChanged(getName(), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String request(String message) {
|
||||
try {
|
||||
port.holdBy(this);
|
||||
try {
|
||||
if (!setADR()) {
|
||||
throw new Error();
|
||||
}
|
||||
return talk(message);
|
||||
} finally {
|
||||
port.unholdBy(this);
|
||||
}
|
||||
} catch (PortException ex) {
|
||||
error("Can not send message to the port", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the address
|
||||
*/
|
||||
public int getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current change speed in Amper per minute
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public double getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set current change speed in Amper per minute
|
||||
*
|
||||
* @param speed
|
||||
*/
|
||||
public void setSpeed(double speed) {
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.magnet;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public interface MagnetStateListener {
|
||||
|
||||
void acceptStatus(String name, MagnetStatus state);
|
||||
|
||||
void acceptNextI(String name, double nextI);
|
||||
|
||||
void acceptMeasuredI(String name, double measuredI);
|
||||
|
||||
default void displayState(String state){
|
||||
|
||||
}
|
||||
|
||||
default void error(String name, String errorMessage, Throwable throwable){
|
||||
throw new RuntimeException(errorMessage, throwable);
|
||||
}
|
||||
|
||||
default void monitorTaskStateChanged(String name, boolean monitorTaskRunning) {
|
||||
|
||||
}
|
||||
|
||||
default void updateTaskStateChanged(String name, boolean updateTaskRunning) {
|
||||
|
||||
}
|
||||
|
||||
default void outputModeChanged(String name, boolean out) {
|
||||
|
||||
}
|
||||
|
||||
default void addressChanged(String name, int address) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.magnet;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Polina
|
||||
*/
|
||||
public class MagnetStatus {
|
||||
|
||||
private boolean on;
|
||||
private final boolean out;
|
||||
private final double measuredCurrent;
|
||||
private final double setCurrent;
|
||||
private final double measuredVoltage;
|
||||
private final double setVoltage;
|
||||
|
||||
public MagnetStatus(boolean isOut, double measuredCurrent, double setCurrent, double measuredVoltage, double setVoltage) {
|
||||
this.on = true;
|
||||
this.out = isOut;
|
||||
this.measuredCurrent = measuredCurrent;
|
||||
this.setCurrent = setCurrent;
|
||||
this.measuredVoltage = measuredVoltage;
|
||||
this.setVoltage = setVoltage;
|
||||
}
|
||||
|
||||
public static MagnetStatus off() {
|
||||
MagnetStatus res = new MagnetStatus(false, 0, 0, 0, 0);
|
||||
res.on = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the isOn
|
||||
*/
|
||||
public boolean isOn() {
|
||||
return on;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the isOut
|
||||
*/
|
||||
public boolean isOutputOn() {
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the measuredCurrent
|
||||
*/
|
||||
public double getMeasuredCurrent() {
|
||||
return measuredCurrent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the setCurrent
|
||||
*/
|
||||
public double getSetCurrent() {
|
||||
return setCurrent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the measuredVoltage
|
||||
*/
|
||||
public double getMeasuredVoltage() {
|
||||
return measuredVoltage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the setVoltage
|
||||
*/
|
||||
public double getSetVoltage() {
|
||||
return setVoltage;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.magnet;
|
||||
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Polina
|
||||
*/
|
||||
public class SafeMagnetController extends MagnetController {
|
||||
|
||||
private final Set<SafeMagnetCondition> safeConditions = new HashSet<>();
|
||||
|
||||
public SafeMagnetController(String name, PortHandler port, int address, int timeout, SafeMagnetCondition... safeConditions) {
|
||||
super(name, port, address, timeout);
|
||||
this.safeConditions.addAll(Arrays.asList(safeConditions));
|
||||
}
|
||||
|
||||
public SafeMagnetController(String name, PortHandler port, int address, SafeMagnetCondition... safeConditions) {
|
||||
super(name, port, address);
|
||||
this.safeConditions.addAll(Arrays.asList(safeConditions));
|
||||
}
|
||||
|
||||
public void addSafeCondition(Predicate<Double> condition, boolean isBlocking){
|
||||
this.safeConditions.add(new SafeMagnetCondition() {
|
||||
|
||||
@Override
|
||||
public boolean isSafe(int address, double current) {
|
||||
return condition.test(current);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBloking() {
|
||||
return isBlocking;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add symmetric non-blocking conditions to ensure currents in two magnets have difference within given tolerance.
|
||||
* @param controller
|
||||
* @param tolerance
|
||||
*/
|
||||
public void bindTo(SafeMagnetController controller, double tolerance){
|
||||
this.addSafeCondition((I)->Math.abs(controller.getMeasuredI() - I) <= tolerance, false);
|
||||
controller.addSafeCondition((I)->Math.abs(this.getMeasuredI() - I) <= tolerance, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setCurrent(double current) throws PortException {
|
||||
for (SafeMagnetCondition condition : safeConditions) {
|
||||
if (!condition.isSafe(getAddress(), current)) {
|
||||
if (condition.isBloking()) {
|
||||
condition.onFail();
|
||||
throw new RuntimeException("Can't set current. Condition not satisfied.");
|
||||
} else {
|
||||
if(listener!= null){
|
||||
listener.displayState("BOUND");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.setCurrent(current);
|
||||
}
|
||||
|
||||
public static interface SafeMagnetCondition {
|
||||
|
||||
boolean isSafe(int address, double current);
|
||||
|
||||
default boolean isBloking() {
|
||||
return true;
|
||||
}
|
||||
|
||||
default void onFail() {
|
||||
LoggerFactory.getLogger(getClass()).error("Can't set current. Condition not satisfied.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.magnet;
|
||||
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
import hep.dataforge.control.ports.ComPortHandler;
|
||||
import jssc.SerialPortException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class SetCurrent {
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) throws SerialPortException {
|
||||
if (args.length < 3) {
|
||||
throw new IllegalArgumentException("Wrong number of parameters");
|
||||
}
|
||||
String comName = args[0];
|
||||
int lambdaaddress = Integer.valueOf(args[1]);
|
||||
double current = Double.valueOf(args[2]);
|
||||
|
||||
PortHandler handler = new ComPortHandler(comName);
|
||||
|
||||
MagnetController controller = new MagnetController(handler, lambdaaddress);
|
||||
|
||||
controller.startUpdateTask(current, 500);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.magnet;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import hep.dataforge.control.ports.PortFactory;
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Locale;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class Talk {
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
Locale.setDefault(Locale.US);
|
||||
ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
||||
rootLogger.setLevel(Level.INFO);
|
||||
|
||||
String portName = "/dev/ttyr00";
|
||||
|
||||
if (args.length > 0) {
|
||||
portName = args[0];
|
||||
}
|
||||
PortHandler handler;
|
||||
handler = PortFactory.buildPort(portName);
|
||||
handler.setPhraseCondition((String str) -> str.endsWith("\r"));
|
||||
|
||||
// MagnetController controller = new MagnetController(handler, 1);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
||||
|
||||
System.out.printf("INPUT > ");
|
||||
String nextString = reader.readLine();
|
||||
|
||||
while (!"exit".equals(nextString)) {
|
||||
try {
|
||||
Instant start = Instant.now();
|
||||
String answer = handler.sendAndWait(nextString + "\r", null, 1000);
|
||||
//String answer = controller.request(nextString);
|
||||
System.out.printf("ANSWER (latency = %s): %s;%n", Duration.between(start, Instant.now()), answer.trim());
|
||||
} catch (PortException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
System.out.printf("INPUT > ");
|
||||
nextString = reader.readLine();
|
||||
}
|
||||
|
||||
handler.close();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.magnet;
|
||||
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class TestController {
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
Locale.setDefault(Locale.US);// чтобы отделение десятичных знаков было точкой
|
||||
// ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
||||
// rootLogger.setLevel(Level.INFO);
|
||||
|
||||
PortHandler handler;
|
||||
MagnetController firstController;
|
||||
MagnetController secondController;
|
||||
|
||||
// String comName = "COM12";
|
||||
// handler = new ComPortHandler(comName);
|
||||
handler = new VirtualLambdaPort("COM12", 1, 2, 3, 4);
|
||||
|
||||
firstController = new MagnetController(handler, 1);
|
||||
// secondController = new MagnetController(handler, 4);
|
||||
secondController = new SafeMagnetController("TEST", handler, 4, (int address, double current) -> current < 1.0);
|
||||
|
||||
MagnetStateListener listener = new MagnetStateListener() {
|
||||
|
||||
@Override
|
||||
public void acceptStatus(String name, MagnetStatus state) {
|
||||
System.out.printf("%s (%s): Im = %f, Um = %f, Is = %f, Us = %f;%n",
|
||||
name,
|
||||
state.isOutputOn(),
|
||||
state.getMeasuredCurrent(),
|
||||
state.getMeasuredVoltage(),
|
||||
state.getSetCurrent(),
|
||||
state.getSetVoltage()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptNextI(String name, double nextI) {
|
||||
System.out.printf("%s: nextI = %f;%n", name, nextI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptMeasuredI(String name, double measuredI) {
|
||||
System.out.printf("%s: measuredI = %f;%n", name, measuredI);
|
||||
}
|
||||
};
|
||||
|
||||
firstController.setListener(listener);
|
||||
secondController.setListener(listener);
|
||||
|
||||
try {
|
||||
firstController.startMonitorTask(2000);
|
||||
secondController.startMonitorTask(2000);
|
||||
secondController.setOutputMode(true);
|
||||
secondController.startUpdateTask(2.0, 1000);
|
||||
System.in.read();
|
||||
firstController.stopMonitorTask();
|
||||
secondController.stopMonitorTask();
|
||||
secondController.stopUpdateTask();
|
||||
secondController.setOutputMode(false);
|
||||
} finally {
|
||||
// handler.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.magnet;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
import java.util.Locale;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class TestSynch {
|
||||
|
||||
private static double firstCurrent = 0;
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
Locale.setDefault(Locale.US);// чтобы отделение десятичных знаков было точкой
|
||||
ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
||||
rootLogger.setLevel(Level.INFO);
|
||||
|
||||
PortHandler handler;
|
||||
MagnetController firstController;
|
||||
MagnetController secondController;
|
||||
|
||||
// String comName = "COM12";
|
||||
// handler = new ComPortHandler(comName);
|
||||
handler = new VirtualLambdaPort("COM12", 1, 2, 3, 4);
|
||||
|
||||
firstController = new MagnetController(handler, 1);
|
||||
// secondController = new MagnetController(handler, 2);
|
||||
secondController = new SafeMagnetController("TEST", handler, 2,
|
||||
new SafeMagnetController.SafeMagnetCondition() {
|
||||
|
||||
// @Override
|
||||
// public boolean isBloking() {
|
||||
// return false;
|
||||
// }
|
||||
@Override
|
||||
public void onFail() {
|
||||
java.awt.Toolkit.getDefaultToolkit().beep();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSafe(int address, double current) {
|
||||
return Math.abs(current - firstCurrent) <= 0.2;
|
||||
}
|
||||
});
|
||||
|
||||
MagnetStateListener listener = new MagnetStateListener() {
|
||||
|
||||
@Override
|
||||
public void acceptStatus(String name, MagnetStatus state) {
|
||||
System.out.printf("%s (%s): Im = %f, Um = %f, Is = %f, Us = %f;%n",
|
||||
name,
|
||||
state.isOutputOn(),
|
||||
state.getMeasuredCurrent(),
|
||||
state.getMeasuredVoltage(),
|
||||
state.getSetCurrent(),
|
||||
state.getSetVoltage()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptNextI(String name, double nextI) {
|
||||
System.out.printf("%s: nextI = %f;%n", name, nextI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptMeasuredI(String name, double measuredI) {
|
||||
System.out.printf("%s: measuredI = %f;%n", name, measuredI);
|
||||
}
|
||||
};
|
||||
|
||||
firstController.setListener(listener);
|
||||
secondController.setListener(listener);
|
||||
|
||||
try {
|
||||
firstController.startMonitorTask(2000);
|
||||
secondController.startMonitorTask(2000);
|
||||
secondController.setOutputMode(true);
|
||||
firstController.setOutputMode(true);
|
||||
firstController.startUpdateTask(1.0, 10);
|
||||
secondController.startUpdateTask(2.0, 10);
|
||||
System.in.read();
|
||||
firstController.stopMonitorTask();
|
||||
secondController.stopMonitorTask();
|
||||
secondController.stopUpdateTask();
|
||||
firstController.stopUpdateTask();
|
||||
secondController.setOutputMode(false);
|
||||
firstController.setOutputMode(false);
|
||||
System.exit(0);
|
||||
} finally {
|
||||
// handler.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.magnet;
|
||||
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.control.ports.VirtualPort;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class VirtualLambdaPort extends VirtualPort {
|
||||
|
||||
private static final Duration latency = Duration.ofMillis(50);
|
||||
|
||||
private volatile int currentAddress = -1;
|
||||
private Map<Integer, VirtualMagnetStatus> magnets = new HashMap<>();
|
||||
|
||||
public VirtualLambdaPort(String portName, Map<Integer, Double> magnets) {
|
||||
super(portName);
|
||||
magnets.entrySet().stream().forEach((entry) -> {
|
||||
this.magnets.put(entry.getKey(), new VirtualMagnetStatus(entry.getValue()));
|
||||
});
|
||||
}
|
||||
|
||||
public VirtualLambdaPort(String portName, int... magnets) {
|
||||
super(portName);
|
||||
for (int magnet : magnets) {
|
||||
this.magnets.put(magnet, new VirtualMagnetStatus(0.01));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void evaluateRequest(String request) {
|
||||
String comand;
|
||||
String value = "";
|
||||
String[] split = request.split(" ");
|
||||
if (split.length == 1) {
|
||||
comand = request;
|
||||
} else {
|
||||
comand = split[0];
|
||||
value = split[1];
|
||||
}
|
||||
try {
|
||||
evaluateRequest(comand.trim(), value.trim());
|
||||
} catch (RuntimeException ex) {
|
||||
|
||||
recievePhrase("FAIL");//TODO какая команда правильная?
|
||||
LoggerFactory.getLogger(getClass()).error("Request evaluation failure", ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void sendOK() {
|
||||
planResponse("OK", latency);
|
||||
}
|
||||
|
||||
private void evaluateRequest(String comand, String value) {
|
||||
switch (comand) {
|
||||
case "ADR":
|
||||
int address = Integer.parseInt(value);
|
||||
if (magnets.containsKey(address)) {
|
||||
currentAddress = address;
|
||||
sendOK();
|
||||
}
|
||||
return;
|
||||
case "ADR?":
|
||||
planResponse(Integer.toString(currentAddress), latency);
|
||||
return;
|
||||
case "OUT":
|
||||
int state = Integer.parseInt(value);
|
||||
currentMagnet().out = (state == 1);
|
||||
sendOK();
|
||||
return;
|
||||
case "OUT?":
|
||||
boolean out = currentMagnet().out;
|
||||
if (out) {
|
||||
planResponse("ON", latency);
|
||||
} else {
|
||||
planResponse("OFF", latency);
|
||||
}
|
||||
return;
|
||||
case "PC":
|
||||
double current = Double.parseDouble(value);
|
||||
if (current < 0.5) {
|
||||
current = 0;
|
||||
}
|
||||
currentMagnet().current = current;
|
||||
sendOK();
|
||||
return;
|
||||
case "PC?":
|
||||
planResponse(Double.toString(currentMagnet().current), latency);
|
||||
return;
|
||||
case "MC?":
|
||||
planResponse(Double.toString(currentMagnet().current), latency);
|
||||
return;
|
||||
case "PV?":
|
||||
planResponse(Double.toString(currentMagnet().voltage()), latency);
|
||||
return;
|
||||
case "MV?":
|
||||
planResponse(Double.toString(currentMagnet().voltage()), latency);
|
||||
return;
|
||||
default:
|
||||
LoggerFactory.getLogger(getClass()).warn("Unknown comand {}", comand);
|
||||
}
|
||||
}
|
||||
|
||||
private VirtualMagnetStatus currentMagnet() {
|
||||
if (currentAddress < 0) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
return magnets.get(currentAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() throws PortException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Meta meta() {
|
||||
return Meta.buildEmpty("virtualPort");
|
||||
|
||||
}
|
||||
|
||||
private class VirtualMagnetStatus {
|
||||
|
||||
public VirtualMagnetStatus(double resistance) {
|
||||
this.resistance = resistance;
|
||||
this.on = true;
|
||||
this.out = false;
|
||||
this.current = 0;
|
||||
}
|
||||
|
||||
public VirtualMagnetStatus(double resistance, boolean on, boolean out, double current) {
|
||||
this.resistance = resistance;
|
||||
this.on = on;
|
||||
this.out = out;
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
private final double resistance;
|
||||
private boolean on;
|
||||
private boolean out;
|
||||
private double current;
|
||||
|
||||
public double voltage() {
|
||||
return current * resistance;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.magnet.fx;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.FileAppender;
|
||||
import hep.dataforge.control.ports.PortFactory;
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import inr.numass.control.magnet.MagnetController;
|
||||
import inr.numass.control.magnet.SafeMagnetController;
|
||||
import inr.numass.control.magnet.VirtualLambdaPort;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import javafx.application.Application;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Stage;
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class MagnetControllerApp extends Application {
|
||||
|
||||
PortHandler handler;
|
||||
SafeMagnetController sourceController;
|
||||
SafeMagnetController pinchController;
|
||||
SafeMagnetController conusController;
|
||||
SafeMagnetController detectorController;
|
||||
List<SafeMagnetController> controllers = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws IOException, ControlException {
|
||||
Locale.setDefault(Locale.US);// чтобы отделение десятичных знаков было точкой
|
||||
ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
||||
|
||||
String logLevel = getParameters().getNamed().getOrDefault("logLevel","INFO");
|
||||
|
||||
rootLogger.setLevel(Level.valueOf(logLevel));
|
||||
|
||||
String logFile = getParameters().getNamed().get("logFile");
|
||||
|
||||
if(logFile!=null){
|
||||
FileAppender<ILoggingEvent> appender = new FileAppender<>();
|
||||
appender.setFile(logFile);
|
||||
appender.setContext(rootLogger.getLoggerContext());
|
||||
appender.start();
|
||||
rootLogger.addAppender(appender);
|
||||
}
|
||||
|
||||
String portName = getParameters().getNamed().getOrDefault("port","virtual");
|
||||
|
||||
if(portName.equals("virtual")){
|
||||
handler = new VirtualLambdaPort("COM12", 1, 2, 3, 4);
|
||||
} else {
|
||||
handler = PortFactory.buildPort(portName);
|
||||
//TODO add meta reader here
|
||||
}
|
||||
|
||||
sourceController = new SafeMagnetController("SOURCE", handler, 1);
|
||||
pinchController = new SafeMagnetController("PINCH", handler, 2);
|
||||
conusController = new SafeMagnetController("CONUS", handler, 3);
|
||||
detectorController = new SafeMagnetController("DETECTOR", handler, 4);
|
||||
|
||||
conusController.bindTo(pinchController, 30.0);
|
||||
|
||||
controllers.add(sourceController);
|
||||
sourceController.setSpeed(4d);
|
||||
controllers.add(pinchController);
|
||||
controllers.add(conusController);
|
||||
controllers.add(detectorController);
|
||||
|
||||
|
||||
boolean showConfirmation = Boolean.parseBoolean(getParameters().getNamed().getOrDefault("confirmOut","false"));
|
||||
|
||||
VBox vbox = new VBox(5);
|
||||
double height = 0;
|
||||
double width = 0;
|
||||
for (MagnetController controller : controllers) {
|
||||
MagnetControllerComponent comp = MagnetControllerComponent.build(controller);
|
||||
width = Math.max(width, comp.getPrefWidth());
|
||||
height += comp.getPrefHeight()+5;
|
||||
if(!showConfirmation){
|
||||
comp.setShowConfirmation(showConfirmation);
|
||||
}
|
||||
vbox.getChildren().add(comp);
|
||||
}
|
||||
|
||||
Scene scene = new Scene(vbox, width, height);
|
||||
|
||||
|
||||
primaryStage.setTitle("Numass magnet view");
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setResizable(false);
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
super.stop(); //To change body of generated methods, choose Tools | Templates.
|
||||
for (MagnetController magnet : controllers) {
|
||||
magnet.stopMonitorTask();
|
||||
magnet.stopUpdateTask();
|
||||
}
|
||||
if(handler.isOpen()){
|
||||
handler.close();
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.magnet.fx;
|
||||
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import inr.numass.control.magnet.MagnetController;
|
||||
import inr.numass.control.magnet.MagnetStateListener;
|
||||
import inr.numass.control.magnet.MagnetStatus;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.ButtonType;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.ToggleButton;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.paint.Color;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* FXML Controller class
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class MagnetControllerComponent extends AnchorPane implements Initializable, MagnetStateListener {
|
||||
|
||||
private MagnetController magnetController;
|
||||
private Logger logger;
|
||||
|
||||
private boolean showConfirmation = true;
|
||||
|
||||
public static MagnetControllerComponent build(MagnetController magnetController) {
|
||||
MagnetControllerComponent component = new MagnetControllerComponent();
|
||||
FXMLLoader loader = new FXMLLoader(magnetController.getClass().getResource("/fxml/SingleMagnet.fxml"));
|
||||
|
||||
loader.setRoot(component);
|
||||
loader.setController(component);
|
||||
|
||||
try {
|
||||
loader.load();
|
||||
} catch (Exception ex) {
|
||||
LoggerFactory.getLogger("FX").error("Error during fxml initialization", ex);
|
||||
throw new Error(ex);
|
||||
}
|
||||
component.setMagnetController(magnetController);
|
||||
return component;
|
||||
}
|
||||
|
||||
@FXML
|
||||
private Label labelI;
|
||||
@FXML
|
||||
private Label labelU;
|
||||
@FXML
|
||||
private TextField targetIField;
|
||||
@FXML
|
||||
private Label magnetName;
|
||||
@FXML
|
||||
private ToggleButton monitorButton;
|
||||
@FXML
|
||||
private Label statusLabel;
|
||||
@FXML
|
||||
private ToggleButton setButton;
|
||||
@FXML
|
||||
private TextField magnetSpeedField;
|
||||
|
||||
// public MagnetControllerComponent(MagnetController magnetController) {
|
||||
// FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/SingleMagnet.fxml"));
|
||||
//
|
||||
// loader.setRoot(this);
|
||||
// loader.setController(this);
|
||||
//
|
||||
// try {
|
||||
// loader.load();
|
||||
// } catch (IOException ex) {
|
||||
// throw new RuntimeException(ex);
|
||||
// }
|
||||
// setMagnetController(magnetController);
|
||||
// }
|
||||
/**
|
||||
* Initializes the controller class.
|
||||
*
|
||||
* @param url
|
||||
* @param rb
|
||||
*/
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
|
||||
targetIField.textProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
|
||||
if (!newValue.matches("\\d*(\\.)?\\d*")) {
|
||||
targetIField.setText(oldValue);
|
||||
}
|
||||
});
|
||||
|
||||
magnetSpeedField.textProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue) -> {
|
||||
if (!newValue.matches("\\d*(\\.)?\\d*")) {
|
||||
magnetSpeedField.setText(oldValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setShowConfirmation(boolean showConfirmation) {
|
||||
this.showConfirmation = showConfirmation;
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onOutToggle(ActionEvent event) {
|
||||
try {
|
||||
setOutput(setButton.isSelected());
|
||||
} catch (PortException ex) {
|
||||
error(this.magnetController.getName(), null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private double getTargetI() {
|
||||
return Double.parseDouble(targetIField.getText());
|
||||
}
|
||||
|
||||
private void setOutput(boolean outputOn) throws PortException {
|
||||
if (outputOn) {
|
||||
if (showConfirmation) {
|
||||
Alert alert = new Alert(Alert.AlertType.WARNING);
|
||||
alert.setContentText("Изменение токов в сверхпроводящих магнитах можно производить только при выключенном напряжении на спектрометре."
|
||||
+ "\nВы уверены что напряжение выключено?");
|
||||
alert.setHeaderText("Проверьте напряжение на спектрометре!");
|
||||
alert.setHeight(150);
|
||||
alert.setTitle("Внимание!");
|
||||
alert.getButtonTypes().clear();
|
||||
alert.getButtonTypes().addAll(ButtonType.YES, ButtonType.CANCEL);
|
||||
|
||||
if (alert.showAndWait().orElse(ButtonType.CANCEL).equals(ButtonType.YES)) {
|
||||
startCurrentChange();
|
||||
} else {
|
||||
setButton.setSelected(false);
|
||||
}
|
||||
} else {
|
||||
startCurrentChange();
|
||||
}
|
||||
} else {
|
||||
getMagnetController().stopUpdateTask();
|
||||
targetIField.setDisable(false);
|
||||
magnetSpeedField.setDisable(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void startCurrentChange() throws PortException {
|
||||
double speed = Double.parseDouble(magnetSpeedField.getText());
|
||||
if (speed > 0 && speed <= 7) {
|
||||
magnetController.setSpeed(speed);
|
||||
magnetSpeedField.setDisable(true);
|
||||
getMagnetController().setOutputMode(true);
|
||||
getMagnetController().startUpdateTask(getTargetI());
|
||||
} else {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setContentText(null);
|
||||
alert.setHeaderText("Недопустимое значение скорости изменения тока");
|
||||
alert.setTitle("Ошибка!");
|
||||
alert.show();
|
||||
setButton.setSelected(false);
|
||||
magnetSpeedField.setText(Double.toString(magnetController.getSpeed()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onMonitorToggle(ActionEvent event) {
|
||||
if (monitorButton.isSelected()) {
|
||||
getMagnetController().startMonitorTask();
|
||||
} else {
|
||||
getMagnetController().stopMonitorTask();
|
||||
this.labelU.setText("----");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String name, String errorMessage, Throwable throwable) {
|
||||
Platform.runLater(() -> {
|
||||
this.statusLabel.setText("ERROR");
|
||||
this.statusLabel.setTextFill(Color.RED);
|
||||
});
|
||||
this.logger.error("ERROR: {}", errorMessage, throwable);
|
||||
// MagnetStateListener.super.error(address, errorMessage, throwable); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the magnetController
|
||||
*/
|
||||
public MagnetController getMagnetController() {
|
||||
if (magnetController == null) {
|
||||
throw new RuntimeException("Magnet controller not defined");
|
||||
}
|
||||
return magnetController;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param magnetController the magnetController to set
|
||||
*/
|
||||
private void setMagnetController(MagnetController magnetController) {
|
||||
this.magnetController = magnetController;
|
||||
logger = LoggerFactory.getLogger("lambda." + magnetController.getName());
|
||||
magnetController.setListener(this);
|
||||
magnetName.setText(magnetController.getName());
|
||||
|
||||
magnetSpeedField.setText(Double.toString(this.magnetController.getSpeed()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptStatus(String name, MagnetStatus state) {
|
||||
Platform.runLater(() -> {
|
||||
this.labelI.setText(Double.toString(state.getMeasuredCurrent()));
|
||||
this.labelU.setText(Double.toString(state.getMeasuredVoltage()));
|
||||
outputModeChanged(name, state.isOutputOn());
|
||||
|
||||
getLogger().info(String.format("%s (%s): Im = %f, Um = %f, Is = %f, Us = %f;",
|
||||
name,
|
||||
state.isOutputOn(),
|
||||
state.getMeasuredCurrent(),
|
||||
state.getMeasuredVoltage(),
|
||||
state.getSetCurrent(),
|
||||
state.getSetVoltage()
|
||||
));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptNextI(String name, double nextI) {
|
||||
getLogger().debug("{}: nextI = {};", name, nextI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptMeasuredI(String name, double measuredI) {
|
||||
getLogger().debug("{}: measuredI = {};", name, measuredI);
|
||||
Platform.runLater(() -> {
|
||||
this.labelI.setText(Double.toString(measuredI));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outputModeChanged(String name, boolean out) {
|
||||
Platform.runLater(() -> {
|
||||
if (out) {
|
||||
this.statusLabel.setText("OK");
|
||||
this.statusLabel.setTextFill(Color.BLUE);
|
||||
} else {
|
||||
this.statusLabel.setText("OFF");
|
||||
this.statusLabel.setTextFill(Color.BLACK);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTaskStateChanged(String name, boolean updateTaskRunning) {
|
||||
this.setButton.setSelected(updateTaskRunning);
|
||||
targetIField.setDisable(updateTaskRunning);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void monitorTaskStateChanged(String name, boolean monitorTaskRunning) {
|
||||
this.monitorButton.setScaleShape(monitorTaskRunning);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the logger
|
||||
*/
|
||||
public Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @param logger the logger to set
|
||||
// */
|
||||
// public void setLogger(PrintStream logger) {
|
||||
// this.logger = logger;
|
||||
// }
|
||||
@Override
|
||||
public void displayState(String state) {
|
||||
Platform.runLater(() -> this.statusLabel.setText(state));
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 inr.numass.control.magnet.fx;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
public class TestApp {
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
MagnetControllerApp.main(new String[]{"--port=192.168.111.31:4001"});
|
||||
//MagnetControllerApp.main(new String[]{"--port=192.168.111.31:4001", "--logLevel=DEBUG"});
|
||||
}
|
||||
|
||||
}
|
125
numass-control/magnet/src/main/resources/fxml/SingleMagnet.fxml
Normal file
125
numass-control/magnet/src/main/resources/fxml/SingleMagnet.fxml
Normal file
@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Copyright 2015 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.
|
||||
-->
|
||||
|
||||
<?import javafx.scene.text.*?>
|
||||
<?import javafx.scene.shape.*?>
|
||||
<?import javafx.geometry.*?>
|
||||
<?import java.lang.*?>
|
||||
<?import java.util.*?>
|
||||
<?import javafx.scene.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<fx:root id="SingleMagnetPanel" minHeight="-Infinity" minWidth="-Infinity" prefHeight="175.0" prefWidth="280.0" type="AnchorPane" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<children>
|
||||
<VBox prefHeight="175.0" prefWidth="270.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<children>
|
||||
<HBox alignment="CENTER" style="-fx-background-color: LIGHTGREEN;">
|
||||
<children>
|
||||
<Label fx:id="magnetName" alignment="CENTER" contentDisplay="CENTER" layoutX="74.0" prefHeight="28.0" prefWidth="167.0" text="Name">
|
||||
<font>
|
||||
<Font name="System Bold" size="18.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
</HBox>
|
||||
<Separator prefWidth="200.0" />
|
||||
<Pane prefHeight="35.0" prefWidth="250.0">
|
||||
<children>
|
||||
<Label layoutX="14.0" layoutY="8.0" text="Status:">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label fx:id="statusLabel" alignment="CENTER" layoutX="67.0" layoutY="4.0" prefHeight="27.0" prefWidth="80.0" text="INIT" textFill="GRAY">
|
||||
<font>
|
||||
<Font name="System Bold" size="18.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<TextField fx:id="magnetSpeedField" layoutX="173.0" layoutY="4.0" prefHeight="26.0" prefWidth="49.0" />
|
||||
<Label layoutX="230.0" layoutY="9.0" text="A/min" />
|
||||
</children>
|
||||
</Pane>
|
||||
<Separator prefWidth="200.0" />
|
||||
<HBox prefHeight="50.0" prefWidth="250.0">
|
||||
<children>
|
||||
<Pane prefHeight="50.0" prefWidth="135.0" style="-fx-border-color: RED; -fx-border-radius: 6;">
|
||||
<children>
|
||||
<Label layoutX="14.0" layoutY="13.0" text="I">
|
||||
<font>
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label fx:id="labelI" alignment="CENTER_RIGHT" layoutX="40.0" layoutY="13.0" prefHeight="25.0" prefWidth="80.0" text="?" textFill="RED">
|
||||
<font>
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
<HBox.margin>
|
||||
<Insets />
|
||||
</HBox.margin>
|
||||
</Pane>
|
||||
<Separator orientation="VERTICAL" prefHeight="200.0">
|
||||
<padding>
|
||||
<Insets right="1.0" />
|
||||
</padding>
|
||||
</Separator>
|
||||
<Pane layoutX="10.0" layoutY="10.0" prefHeight="50.0" prefWidth="135.0" style="-fx-border-color: BLUE; -fx-border-radius: 6;">
|
||||
<children>
|
||||
<Label layoutX="14.0" layoutY="13.0" text="U">
|
||||
<font>
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label fx:id="labelU" alignment="CENTER_RIGHT" layoutX="40.0" layoutY="13.0" prefHeight="25.0" prefWidth="80.0" text="?" textAlignment="JUSTIFY" textFill="BLUE">
|
||||
<font>
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
<HBox.margin>
|
||||
<Insets />
|
||||
</HBox.margin>
|
||||
</Pane>
|
||||
</children>
|
||||
</HBox>
|
||||
<Separator prefWidth="200.0" />
|
||||
<Pane prefHeight="50.0" prefWidth="250.0" style="-fx-border-color: GREEN; -fx-border-radius: 6;">
|
||||
<children>
|
||||
<Label layoutX="9.0" layoutY="15.0" text="I target">
|
||||
<font>
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<TextField fx:id="targetIField" layoutX="83.0" layoutY="13.0" prefHeight="25.0" prefWidth="55.0" text="0.0" />
|
||||
<ToggleButton fx:id="setButton" layoutX="160.0" layoutY="13.0" mnemonicParsing="false" onAction="#onOutToggle" text="Set" />
|
||||
<ToggleButton fx:id="monitorButton" contentDisplay="RIGHT" layoutX="199.0" layoutY="13.0" mnemonicParsing="false" onAction="#onMonitorToggle" prefHeight="26.0" prefWidth="70.0" text="Monitor" />
|
||||
</children>
|
||||
<VBox.margin>
|
||||
<Insets />
|
||||
</VBox.margin>
|
||||
</Pane>
|
||||
<Separator prefWidth="250.0" />
|
||||
</children>
|
||||
<padding>
|
||||
<Insets bottom="1.0" left="1.0" right="1.0" top="1.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
</children>
|
||||
</fx:root>
|
23
numass-control/magnet/src/main/resources/logback.xml
Normal file
23
numass-control/magnet/src/main/resources/logback.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="LAMBDA" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="lambda" level="INFO" additivity="false">
|
||||
<appender-ref ref="LAMBDA" />
|
||||
</logger>
|
||||
|
||||
<root level="debug">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
17
numass-control/msp/build.gradle
Normal file
17
numass-control/msp/build.gradle
Normal file
@ -0,0 +1,17 @@
|
||||
apply plugin: 'application'
|
||||
|
||||
version = "0.2.2"
|
||||
|
||||
if (!hasProperty('mainClass')) {
|
||||
ext.mainClass = 'inr.numass.control.msp.fx.MspApp'
|
||||
}
|
||||
mainClassName = mainClass
|
||||
|
||||
|
||||
dependencies {
|
||||
compile 'ch.qos.logback:logback-classic:1.1.0+'
|
||||
compile 'org.scream3r:jssc:2.8.0'
|
||||
compile project(':dataforge-plots')
|
||||
compile project(':dataforge-storage')
|
||||
compile project(':dataforge-control')
|
||||
}
|
@ -0,0 +1,446 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.msp;
|
||||
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import hep.dataforge.control.devices.DataDevice;
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
import hep.dataforge.control.ports.TcpPortHandler;
|
||||
import hep.dataforge.data.DataFormat;
|
||||
import hep.dataforge.data.DataFormatBuilder;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import hep.dataforge.exceptions.StorageException;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.storage.api.PointLoader;
|
||||
import hep.dataforge.storage.api.Storage;
|
||||
import hep.dataforge.storage.commons.LoaderFactory;
|
||||
import hep.dataforge.storage.commons.StoragePlugin;
|
||||
import hep.dataforge.storage.loaders.ChainPointLoader;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class MspDevice extends DataDevice implements PortHandler.PortController {
|
||||
|
||||
// private static final String PEAK_SET_PATH = "peakJump.peak";
|
||||
private static final int TIMEOUT = 200;
|
||||
|
||||
//storage
|
||||
// /**
|
||||
// * Separate storage configuration for backup storage.
|
||||
// */
|
||||
// private Meta backupStorage;
|
||||
private PointLoader peakJumpLoader;
|
||||
|
||||
//port handler
|
||||
private TcpPortHandler handler;
|
||||
|
||||
//listener
|
||||
private MspListener mspListener;
|
||||
|
||||
private String sensorName = null;
|
||||
private boolean isSelected = false;
|
||||
private boolean isControlled = false;
|
||||
private boolean isFilamentOn = false;
|
||||
// private boolean isScanning = false;
|
||||
|
||||
private final Map<Integer, Double> measurement = new ConcurrentSkipListMap<>();
|
||||
private Map<Integer, String> peakMap;
|
||||
|
||||
public MspDevice(String name, Meta annotation) {
|
||||
super(name, GlobalContext.instance(), annotation);
|
||||
}
|
||||
|
||||
public MspDevice(String name, Context context, Meta config) {
|
||||
super(name, context, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws ControlException {
|
||||
super.init();
|
||||
String ip = meta().getString("connection.ip", "127.0.0.1");
|
||||
int port = meta().getInt("connection.port", 10014);
|
||||
getLogger().info("Connection to MKS mass-spectrometer on {}:{}...", ip, port);
|
||||
handler = new TcpPortHandler(ip, port, "msp");
|
||||
handler.setDelimeter("\r\r");
|
||||
}
|
||||
|
||||
/**
|
||||
* Startup MSP: get available sensors, select sensor and control.
|
||||
*
|
||||
* @param measurement
|
||||
* @throws hep.dataforge.exceptions.PortException
|
||||
*/
|
||||
@Override
|
||||
public void doStart(Meta measurement) throws ControlException {
|
||||
if (!isControlled) {
|
||||
if (handler.isLocked()) {
|
||||
LoggerFactory.getLogger(getClass()).error("Trying to init MSP controller on locked port. Breaking the lock.");
|
||||
handler.breakHold();
|
||||
}
|
||||
handler.holdBy(this);
|
||||
MspResponse response = sendAndWait("Sensors");
|
||||
if (response.isOK()) {
|
||||
this.sensorName = response.get(2, 1);
|
||||
} else {
|
||||
error(response.errorDescription(), null);
|
||||
return;
|
||||
}
|
||||
//PENDING определеить в конфиге номер прибора
|
||||
|
||||
response = sendAndWait("Select", sensorName);
|
||||
if (response.isOK()) {
|
||||
this.isSelected = true;
|
||||
} else {
|
||||
error(response.errorDescription(), null);
|
||||
return;
|
||||
}
|
||||
|
||||
response = sendAndWait("Control", "inr.numass.msp", "1.0");
|
||||
if (response.isOK()) {
|
||||
this.isControlled = true;
|
||||
} else {
|
||||
error(response.errorDescription(), null);
|
||||
}
|
||||
}
|
||||
createPeakJumpMeasurement(buildMeasurementLaminate(measurement).getNode("peakJump"));
|
||||
this.peakJumpLoader = getPeakJumpLoader(measurement);
|
||||
}
|
||||
|
||||
// public void setStorageConfig(Meta storageConfig, List<String> peaks) throws StorageException {
|
||||
// Storage storage = getContext().provide("storage", StoragePlugin.class).buildStorage(storageConfig);
|
||||
// String suffix = Integer.toString((int) Instant.now().toEpochMilli());
|
||||
//
|
||||
// this.peakJumpLoader = LoaderFactory.buildPointLoder(storage, "msp" + suffix, "", "timestamp", DataFormat.forNames(10, peaks));
|
||||
// }
|
||||
|
||||
private PointLoader getPeakJumpLoader(Meta measurement) {
|
||||
if (peakJumpLoader == null) {
|
||||
try {
|
||||
// StoragePlugin plugin = getContext().provide("storage", StoragePlugin.class);
|
||||
|
||||
Storage primaryStorage = getPrimaryStorage(measurement);
|
||||
|
||||
if (peakMap == null) {
|
||||
throw new IllegalStateException("Peak map is not initialized");
|
||||
}
|
||||
|
||||
DataFormatBuilder builder = new DataFormatBuilder().addTime("timestamp");
|
||||
for (String peakName : this.peakMap.values()) {
|
||||
builder.addNumber(peakName);
|
||||
}
|
||||
|
||||
DataFormat format = builder.build();
|
||||
|
||||
//TODO Переделать!!!
|
||||
String run = meta().getString("numass.run","");
|
||||
|
||||
String suffix = Integer.toString((int) Instant.now().toEpochMilli());
|
||||
peakJumpLoader = LoaderFactory
|
||||
.buildPointLoder(primaryStorage, "msp" + suffix, run, "timestamp", format);
|
||||
|
||||
|
||||
|
||||
try {
|
||||
Storage secondaryStorage = getSecondaryStorage(measurement);
|
||||
if (secondaryStorage != null) {
|
||||
PointLoader backupLoader = LoaderFactory
|
||||
.buildPointLoder(secondaryStorage, "msp" + suffix, run, "timestamp", format);
|
||||
peakJumpLoader = new ChainPointLoader(peakJumpLoader, backupLoader);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
getLogger().error("Failed to initialize backup peak jump loader", ex);
|
||||
}
|
||||
|
||||
} catch (StorageException ex) {
|
||||
getLogger().error("Failed to initialize primary peak jump loader", ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
return peakJumpLoader;
|
||||
}
|
||||
|
||||
public void setListener(MspListener listener) {
|
||||
this.mspListener = listener;
|
||||
}
|
||||
|
||||
private void send(String command, Object... parameters) throws PortException {
|
||||
String request = buildCommand(command, parameters);
|
||||
if (mspListener != null) {
|
||||
mspListener.acceptRequest(request);
|
||||
}
|
||||
handler.send(request);
|
||||
}
|
||||
|
||||
private String buildCommand(String command, Object... parameters) {
|
||||
StringBuilder builder = new StringBuilder(command);
|
||||
for (Object par : parameters) {
|
||||
builder.append(String.format(" \"%s\"", par.toString()));
|
||||
}
|
||||
builder.append("\n");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send specific command and wait for its results (the result must begin
|
||||
* with command name)
|
||||
*
|
||||
* @param commandName
|
||||
* @param paremeters
|
||||
* @return
|
||||
* @throws PortException
|
||||
*/
|
||||
public MspResponse sendAndWait(String commandName, Object... paremeters) throws PortException {
|
||||
|
||||
String request = buildCommand(commandName, paremeters);
|
||||
if (mspListener != null) {
|
||||
mspListener.acceptRequest(request);
|
||||
}
|
||||
|
||||
String response = handler.sendAndWait(
|
||||
request,
|
||||
(String str) -> str.trim().startsWith(commandName),
|
||||
TIMEOUT
|
||||
);
|
||||
return new MspResponse(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void accept(String message) {
|
||||
if (mspListener != null) {
|
||||
mspListener.acceptMessage(message.trim());
|
||||
}
|
||||
|
||||
MspResponse response = new MspResponse(message);
|
||||
switch (response.getCommandName()) {
|
||||
// all possible async messages
|
||||
case "FilamentStatus":
|
||||
String status = response.get(0, 2);
|
||||
isFilamentOn = status.equals("ON");
|
||||
if (this.mspListener != null) {
|
||||
this.mspListener.acceptFillamentStateChange(status);
|
||||
}
|
||||
break;
|
||||
case "MassReading":
|
||||
double mass = Double.parseDouble(response.get(0, 1));
|
||||
double value = Double.parseDouble(response.get(0, 2));
|
||||
this.measurement.put((int) Math.floor(mass + 0.5), value);
|
||||
break;
|
||||
case "StartingScan":
|
||||
if (this.mspListener != null && !measurement.isEmpty() && isFilamentOn) {
|
||||
|
||||
if (peakMap == null) {
|
||||
throw new IllegalStateException("Peal map is not initialized");
|
||||
}
|
||||
|
||||
mspListener.acceptMeasurement(measurement);
|
||||
|
||||
Instant time = Instant.now();
|
||||
|
||||
MapDataPoint point = new MapDataPoint();
|
||||
point.putValue("timestamp", time);
|
||||
|
||||
for (Map.Entry<Integer, Double> entry : measurement.entrySet()) {
|
||||
double val = entry.getValue();
|
||||
point.putValue(peakMap.get(entry.getKey()), val);
|
||||
}
|
||||
|
||||
if (peakJumpLoader != null) {
|
||||
try {
|
||||
peakJumpLoader.push(point);
|
||||
} catch (StorageException ex) {
|
||||
getLogger().error("Push to repo failed", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
measurement.clear();
|
||||
|
||||
int numScans = Integer.parseInt(response.get(0, 3));
|
||||
|
||||
if (numScans == 0) {
|
||||
try {
|
||||
send("ScanResume", 2);
|
||||
//FIXME обработать ошибку связи
|
||||
} catch (PortException ex) {
|
||||
error(null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return isSelected;
|
||||
}
|
||||
|
||||
public boolean isControlled() {
|
||||
return isControlled;
|
||||
}
|
||||
|
||||
public boolean isFilamentOn() {
|
||||
return isFilamentOn;
|
||||
}
|
||||
|
||||
// public boolean isIsScanning() {
|
||||
// return isScanning;
|
||||
// }
|
||||
/**
|
||||
* Turn filament on or off
|
||||
*
|
||||
* @return
|
||||
*
|
||||
* @param filamentOn
|
||||
* @throws hep.dataforge.exceptions.PortException
|
||||
*/
|
||||
public boolean setFileamentOn(boolean filamentOn) throws PortException {
|
||||
if (filamentOn) {
|
||||
return sendAndWait("FilamentControl", "On").isOK();
|
||||
} else {
|
||||
return sendAndWait("FilamentControl", "Off").isOK();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create measurement with parameters and return its name
|
||||
*
|
||||
* @param an
|
||||
* @return
|
||||
* @throws hep.dataforge.exceptions.PortException
|
||||
*/
|
||||
private void createPeakJumpMeasurement(Meta an) throws ControlException {
|
||||
String name = "peakJump";//an.getString("measurementNAmname", "default");
|
||||
String filterMode = an.getString("filterMode", "PeakAverage");
|
||||
int accuracy = an.getInt("accuracy", 5);
|
||||
//PENDING вставить остальные параметры?
|
||||
sendAndWait("MeasurementRemove", name);
|
||||
if (sendAndWait("AddPeakJump", name, filterMode, accuracy, 0, 0, 0).isOK()) {
|
||||
peakMap = new LinkedHashMap<>();
|
||||
for (Meta peak : an.getNodes("peak")) {
|
||||
peakMap.put(peak.getInt("mass"), peak.getString("name", peak.getString("mass")));
|
||||
if (!sendAndWait("MeasurementAddMass", peak.getString("mass")).isOK()) {
|
||||
throw new ControlException("Can't add mass to measurement measurement for msp");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new ControlException("Can't create measurement for msp");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean startPeakJumpMeasurement() throws PortException {
|
||||
if (!isFilamentOn()) {
|
||||
error("Can't start measurement. Filament is not turned on.", null);
|
||||
}
|
||||
|
||||
if (!sendAndWait("ScanAdd", "peakJump").isOK()) {
|
||||
return false;
|
||||
}
|
||||
return sendAndWait("ScanStart", 2).isOK();
|
||||
}
|
||||
|
||||
|
||||
public boolean stopMeasurement() throws PortException {
|
||||
return sendAndWait("ScanStop").isOK();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doStop() throws PortException {
|
||||
stopMeasurement();
|
||||
setFileamentOn(false);
|
||||
sendAndWait("Release");
|
||||
handler.unholdBy(this);
|
||||
handler.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String errorMessage, Throwable error) {
|
||||
if (mspListener != null) {
|
||||
mspListener.error(errorMessage, error);
|
||||
} else {
|
||||
if (error != null) {
|
||||
throw new RuntimeException(error);
|
||||
} else {
|
||||
throw new RuntimeException(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The MKS response as two-dimensional array of strings
|
||||
*/
|
||||
public static class MspResponse {
|
||||
|
||||
private final List<List<String>> data = new ArrayList<>();
|
||||
|
||||
public MspResponse(String response) {
|
||||
String rx = "[^\"\\s]+|\"(\\\\.|[^\\\\\"])*\"";
|
||||
Scanner scanner = new Scanner(response.trim());
|
||||
|
||||
while (scanner.hasNextLine()) {
|
||||
List<String> line = new ArrayList<>();
|
||||
String next = scanner.findWithinHorizon(rx, 0);
|
||||
while (next != null) {
|
||||
line.add(next);
|
||||
next = scanner.findInLine(rx);
|
||||
}
|
||||
data.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
public String getCommandName() {
|
||||
return this.get(0, 0);
|
||||
}
|
||||
|
||||
public boolean isOK() {
|
||||
return "OK".equals(this.get(0, 1));
|
||||
}
|
||||
|
||||
public int errorCode() {
|
||||
if (isOK()) {
|
||||
return -1;
|
||||
} else {
|
||||
return Integer.parseInt(get(1, 1));
|
||||
}
|
||||
}
|
||||
|
||||
public String errorDescription() {
|
||||
if (isOK()) {
|
||||
return null;
|
||||
} else {
|
||||
return get(2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public String get(int lineNo, int columnNo) {
|
||||
return data.get(lineNo).get(columnNo);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.msp;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
public interface MspListener {
|
||||
void error(String errorMessage, Throwable error);
|
||||
void acceptMeasurement(Map<Integer, Double> point);
|
||||
void acceptMessage(String message);
|
||||
void acceptRequest(String message);
|
||||
default void acceptFillamentStateChange(String fillamentState){
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.msp;
|
||||
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
public class MspTest {
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
* @throws hep.dataforge.exceptions.PortException
|
||||
*/
|
||||
public static void main(String[] args) throws PortException, IOException, InterruptedException {
|
||||
// Locale.setDefault(Locale.US);// чтобы отделение десятичных знаков было точкой
|
||||
// ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
||||
// rootLogger.setLevel(Level.INFO);
|
||||
//
|
||||
// MspListener listener = new MspListener() {
|
||||
//
|
||||
// @Override
|
||||
// public void acceptMeasurement(Map<Double, Double> measurement) {
|
||||
// final StringBuilder mesString = new StringBuilder("[");
|
||||
// measurement.forEach((Double key, Double value) -> mesString.append(String.format("%g:%g,", key, value)));
|
||||
// mesString.deleteCharAt(mesString.length() - 1);
|
||||
// mesString.append("]");
|
||||
// System.out.println("MEASUREMENT: " + mesString);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void acceptMessage(String message) {
|
||||
// System.out.println("RECIEVE: " + message);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void acceptRequest(String message) {
|
||||
// System.out.println("SEND: " + message);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void error(String errorMessage, Throwable error) {
|
||||
// System.out.println("ERROR: " + errorMessage);
|
||||
// if (error != null) {
|
||||
// error.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// MspDevice controller = new MspDevice("127.0.0.1", 10014, listener);
|
||||
// try {
|
||||
// controller.init();
|
||||
// String name = controller.createMeasurement("default", 2, 4, 18, 28);
|
||||
// controller.setFileamentOn(true);
|
||||
//
|
||||
// controller.startMeasurement(name);
|
||||
// BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
|
||||
// reader.readLine();
|
||||
// } finally {
|
||||
// controller.stop();
|
||||
// System.exit(0);
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.msp.fx;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import hep.dataforge.storage.commons.StoragePlugin;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
public class MspApp extends Application {
|
||||
|
||||
MspViewController controller;
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws IOException {
|
||||
Locale.setDefault(Locale.US);// чтобы отделение десятичных знаков было точкой
|
||||
ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
|
||||
rootLogger.setLevel(Level.INFO);
|
||||
new StoragePlugin().startGlobal();
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/MspView.fxml"));
|
||||
|
||||
Parent parent = loader.load();
|
||||
controller = loader.getController();
|
||||
|
||||
try {
|
||||
String configPath = getParameters().getNamed().get("config");
|
||||
if (configPath != null) {
|
||||
File configFile = new File(configPath);
|
||||
controller.setDeviceConfig(GlobalContext.instance(), configFile);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LoggerFactory.getLogger(getClass()).error("Failed to load predefined configuration", ex);
|
||||
}
|
||||
|
||||
Scene scene = new Scene(parent, 600, 400);
|
||||
|
||||
primaryStage.setTitle("Numass mass-spectrometer view");
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.setMinHeight(400);
|
||||
primaryStage.setMinWidth(600);
|
||||
// primaryStage.setResizable(false);
|
||||
|
||||
primaryStage.show();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
super.stop(); //To change body of generated methods, choose Tools | Templates.
|
||||
controller.disconnect();
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.msp.fx;
|
||||
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaBuilder;
|
||||
import hep.dataforge.meta.ConfigChangeListener;
|
||||
import hep.dataforge.meta.Configuration;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import hep.dataforge.io.MetaFileReader;
|
||||
import hep.dataforge.plots.data.DynamicPlottable;
|
||||
import hep.dataforge.plots.data.DynamicPlottableSet;
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||
import hep.dataforge.values.Value;
|
||||
import inr.numass.control.msp.MspDevice;
|
||||
import inr.numass.control.msp.MspListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.text.ParseException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Slider;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.ToggleButton;
|
||||
import javafx.scene.input.DragEvent;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.shape.Circle;
|
||||
import javafx.stage.FileChooser;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* FXML Controller class
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
public class MspViewController implements Initializable, MspListener {
|
||||
|
||||
public static final String MSP_DEVICE_TYPE = "msp";
|
||||
|
||||
public static final String DEFAULT_CONFIG_LOCATION = "msp-config.xml";
|
||||
|
||||
private MspDevice device;
|
||||
|
||||
private Configuration viewConfig;
|
||||
|
||||
private JFreeChartFrame plotFrame;
|
||||
|
||||
private final DynamicPlottableSet plottables = new DynamicPlottableSet();
|
||||
|
||||
private final String mspName = "msp";
|
||||
|
||||
@FXML
|
||||
private Slider autoRangeSlider;
|
||||
@FXML
|
||||
private ToggleButton fillamentButton;
|
||||
@FXML
|
||||
private Circle fillamentIndicator;
|
||||
@FXML
|
||||
private TextArea logArea;
|
||||
@FXML
|
||||
private ToggleButton plotButton;
|
||||
@FXML
|
||||
private AnchorPane plotPane;
|
||||
@FXML
|
||||
private Button loadConfigButton;
|
||||
|
||||
private final ConfigChangeListener viewConfigObserver = new ConfigChangeListener() {
|
||||
|
||||
@Override
|
||||
public void notifyElementChanged(String name, List<? extends Meta> oldItem, List<? extends Meta> newItem) {
|
||||
updatePlot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyValueChanged(String name, Value oldItem, Value newItem) {
|
||||
updatePlot();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
public MspViewController() {
|
||||
}
|
||||
|
||||
public Configuration getViewConfig() {
|
||||
if (viewConfig == null) {
|
||||
viewConfig = new Configuration(getDevice().meta().getNode("peakJump"));
|
||||
viewConfig.addObserver(viewConfigObserver);
|
||||
LoggerFactory.getLogger(getClass()).warn("Could not find view configuration. Using default view configuration instead.");
|
||||
}
|
||||
return viewConfig;
|
||||
}
|
||||
|
||||
public void setViewConfig(Meta viewConfig) {
|
||||
this.viewConfig = new Configuration(viewConfig);
|
||||
this.viewConfig.addObserver(viewConfigObserver);
|
||||
}
|
||||
|
||||
private MspDevice getDevice() {
|
||||
if (this.device == null) {
|
||||
showError("Device configuration not found. Using default configuration.");
|
||||
Meta defaultDeviceConfig;
|
||||
try {
|
||||
defaultDeviceConfig = MetaFileReader
|
||||
.read(new File(getClass().getResource("/config/msp-config.xml").toURI()));
|
||||
} catch (IOException | URISyntaxException | ParseException ex) {
|
||||
throw new Error(ex);
|
||||
}
|
||||
setDeviceConfig(GlobalContext.instance(), defaultDeviceConfig);
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
public void setDeviceConfig(Context context, Meta config) {
|
||||
Meta mspConfig = null;
|
||||
if (config.hasNode("device")) {
|
||||
for (Meta d : config.getNodes("device")) {
|
||||
if (d.getString("type", "unknown").equals(MSP_DEVICE_TYPE)
|
||||
&& d.getString("name", "msp").equals(this.mspName)) {
|
||||
mspConfig = d;
|
||||
}
|
||||
}
|
||||
} else if (config.hasNode("peakJump")) {
|
||||
mspConfig = config;
|
||||
}
|
||||
|
||||
if (mspConfig != null) {
|
||||
this.device = new MspDevice(mspName, context, mspConfig);
|
||||
try {
|
||||
getDevice().setListener(this);
|
||||
getDevice().init();
|
||||
getDevice().start();
|
||||
} catch (ControlException ex) {
|
||||
showError(String.format("Can't connect to %s:%d. The port is either busy or not the MKS mass-spectrometer port",
|
||||
config.getString("connection.ip", "127.0.0.1"),
|
||||
config.getInt("connection.port", 10014)));
|
||||
throw new RuntimeException("Can't connect to device");
|
||||
}
|
||||
} else {
|
||||
showError("Can't find device description in given confgiuration");
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
if (config.hasNode("plots.msp")) {
|
||||
setViewConfig(config.getNode("plots.msp"));
|
||||
}
|
||||
|
||||
updatePlot();
|
||||
}
|
||||
|
||||
public void setDeviceConfig(Context context, File cfgFile) {
|
||||
try {
|
||||
Meta deviceConfig = MetaFileReader.instance().read(context, cfgFile, null);
|
||||
setDeviceConfig(context, deviceConfig);
|
||||
} catch (IOException | ParseException ex) {
|
||||
showError("Can't load configuration file");
|
||||
}
|
||||
}
|
||||
|
||||
public void initPlot() {
|
||||
Meta plotConfig = new MetaBuilder("plotFrame")
|
||||
.setNode(new MetaBuilder("yAxis")
|
||||
.setValue("logAxis", true)
|
||||
.setValue("axisTitle", "partial pressure")
|
||||
.setValue("axisUnits", "mbar")
|
||||
)
|
||||
.setValue("xAxis.timeAxis", true);
|
||||
this.plotFrame = new JFreeChartFrame(mspName, plotConfig, plotPane);
|
||||
updatePlot();
|
||||
// this.plot = DynamicPlot.attachToFX(plotPane, new AnnotationBuilder("plot-config").putValue("logY", true).build());
|
||||
// plot.setAutoRange(30 * 60);
|
||||
}
|
||||
|
||||
public void updatePlot() {
|
||||
if (plotFrame == null) {
|
||||
initPlot();
|
||||
}
|
||||
Meta config = getViewConfig();
|
||||
if (config.hasNode("plotFrame")) {
|
||||
this.plotFrame.updateConfig(config.getNode("plotFrame"));
|
||||
}
|
||||
if (config.hasNode("peakJump.line")) {
|
||||
for (Meta an : config.getNodes("peakJump.line")) {
|
||||
String mass = an.getString("mass");
|
||||
|
||||
if (!this.plottables.hasPlottable(mass)) {
|
||||
DynamicPlottable newPlottable = new DynamicPlottable(mass, an, mass);
|
||||
this.plottables.addPlottable(newPlottable);
|
||||
plotFrame.add(newPlottable);
|
||||
} else {
|
||||
plottables.getPlottable(mass).updateConfig(an);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
showError("No peaks defined in config");
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptMeasurement(Map<Integer, Double> measurement) {
|
||||
MapDataPoint point = new MapDataPoint();
|
||||
for (Map.Entry<Integer, Double> entry : measurement.entrySet()) {
|
||||
Double val = entry.getValue();
|
||||
if (val <= 0) {
|
||||
val = Double.NaN;
|
||||
}
|
||||
point.putValue(Integer.toString(entry.getKey()), val);
|
||||
}
|
||||
plottables.put(point);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptMessage(String message) {
|
||||
Platform.runLater(() -> {
|
||||
logArea.appendText("RECIEVE: " + message + "\r\n");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptRequest(String message) {
|
||||
Platform.runLater(() -> {
|
||||
logArea.appendText("SEND: " + message + "\r\n");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String errorMessage, Throwable error) {
|
||||
Platform.runLater(() -> {
|
||||
logArea.appendText("ERROR: " + errorMessage + "\r\n");
|
||||
showError(errorMessage);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the controller class.
|
||||
*
|
||||
* @param url
|
||||
* @param rb
|
||||
*/
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onAutoRangeChange(DragEvent event) {
|
||||
plottables.setMaxAge((int) (this.autoRangeSlider.getValue() * 60 * 1000));
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onFillamentToggle(ActionEvent event) throws PortException {
|
||||
getDevice().setFileamentOn(fillamentButton.isSelected());
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onLoadConfig(ActionEvent event) {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("Open Resource File");
|
||||
fileChooser.setInitialFileName(DEFAULT_CONFIG_LOCATION);
|
||||
fileChooser.setInitialDirectory(GlobalContext.instance().io().getRootDirectory());
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("xml", "*.xml", "*.XML"));
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("all", "*.*"));
|
||||
File cfgFile = fileChooser.showOpenDialog(loadConfigButton.getScene().getWindow());
|
||||
if (cfgFile != null) {
|
||||
setDeviceConfig(GlobalContext.instance(), cfgFile);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void onPlotToggle(ActionEvent event) throws PortException {
|
||||
if (plotButton.isSelected()) {
|
||||
getDevice().startPeakJumpMeasurement();
|
||||
} else {
|
||||
getDevice().stopMeasurement();
|
||||
}
|
||||
}
|
||||
|
||||
private void showError(String message) {
|
||||
Alert alert = new Alert(Alert.AlertType.ERROR);
|
||||
alert.setTitle("Error!");
|
||||
alert.setHeaderText(null);
|
||||
alert.setContentText(message);
|
||||
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
private void showInfo(String message) {
|
||||
|
||||
}
|
||||
|
||||
public void disconnect() throws IOException, PortException, ControlException {
|
||||
getDevice().stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptFillamentStateChange(String fillamentState) {
|
||||
Platform.runLater(() -> {
|
||||
switch (fillamentState) {
|
||||
case "ON":
|
||||
this.fillamentIndicator.setFill(Paint.valueOf("red"));
|
||||
break;
|
||||
case "OFF":
|
||||
this.fillamentIndicator.setFill(Paint.valueOf("blue"));
|
||||
break;
|
||||
case "WARM-UP":
|
||||
case "COOL-DOWN":
|
||||
this.fillamentIndicator.setFill(Paint.valueOf("yellow"));
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
44
numass-control/msp/src/main/resources/config/msp-config.xml
Normal file
44
numass-control/msp/src/main/resources/config/msp-config.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2015 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.
|
||||
-->
|
||||
|
||||
<config>
|
||||
<device type="msp" name="msp">
|
||||
<storage path="D:/temp/test" />
|
||||
<connection ip="127.0.0.1" port="10014"/>
|
||||
<peakJump>
|
||||
<peak mass="2"/>
|
||||
<peak mass="3"/>
|
||||
<peak mass="4"/>
|
||||
<peak mass="6"/>
|
||||
<peak mass="12"/>
|
||||
<peak mass="14"/>
|
||||
<peak mass="18"/>
|
||||
<peak mass="28"/>
|
||||
<peak mass="32"/>
|
||||
</peakJump>
|
||||
</device>
|
||||
<plots>
|
||||
<msp>
|
||||
<peakJump>
|
||||
<line mass="2" title="hydrogen" color="black" thickness="6"/>
|
||||
<line mass="6" title="tritium" thickness="4"/>
|
||||
<line mass="18" title="water" />
|
||||
<line mass="32" title="oxygen"/>
|
||||
</peakJump>
|
||||
</msp>
|
||||
</plots>
|
||||
</config>
|
58
numass-control/msp/src/main/resources/fxml/MspView.fxml
Normal file
58
numass-control/msp/src/main/resources/fxml/MspView.fxml
Normal file
@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2015 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.
|
||||
-->
|
||||
|
||||
<?import javafx.scene.effect.*?>
|
||||
<?import javafx.scene.paint.*?>
|
||||
<?import javafx.scene.shape.*?>
|
||||
<?import javafx.scene.chart.*?>
|
||||
<?import java.lang.*?>
|
||||
<?import java.util.*?>
|
||||
<?import javafx.scene.*?>
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="400.0" minWidth="600.0" prefHeight="480.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="inr.numass.control.msp.fx.MspViewController">
|
||||
<children>
|
||||
<SplitPane dividerPositions="0.8" minHeight="400.0" minWidth="600.0" orientation="VERTICAL" prefHeight="200.0" prefWidth="160.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<items>
|
||||
<AnchorPane minHeight="300.0" minWidth="300.0" prefHeight="100.0" prefWidth="160.0">
|
||||
<children>
|
||||
<ToolBar layoutX="130.0" prefHeight="50.0" prefWidth="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
|
||||
<items>
|
||||
<ToggleButton fx:id="fillamentButton" mnemonicParsing="false" onAction="#onFillamentToggle" text="Fillament" />
|
||||
<Circle fx:id="fillamentIndicator" fill="GRAY" radius="10.0" stroke="BLACK" strokeType="INSIDE" />
|
||||
<Separator orientation="VERTICAL" prefHeight="20.0" />
|
||||
<ToggleButton fx:id="plotButton" mnemonicParsing="false" onAction="#onPlotToggle" text="Aquire" />
|
||||
<Button fx:id="loadConfigButton" mnemonicParsing="false" onAction="#onLoadConfig" text="Load config" />
|
||||
<Separator orientation="VERTICAL" prefHeight="20.0" />
|
||||
<Label text="Autorange (min):" />
|
||||
<Slider fx:id="autoRangeSlider" max="210.0" min="10.0" onDragDone="#onAutoRangeChange" showTickLabels="true" showTickMarks="true" snapToTicks="true" value="30.0" />
|
||||
<Separator orientation="VERTICAL" prefHeight="20.0" />
|
||||
</items>
|
||||
</ToolBar>
|
||||
<AnchorPane fx:id="plotPane" layoutX="144.0" layoutY="82.0" minHeight="400.0" minWidth="600.0" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="50.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
<AnchorPane maxHeight="200.0" minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
|
||||
<children>
|
||||
<TextArea fx:id="logArea" editable="false" maxHeight="200.0" minHeight="0.0" prefHeight="200.0" prefWidth="200.0" wrapText="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
|
||||
</children>
|
||||
</AnchorPane>
|
||||
</items>
|
||||
</SplitPane>
|
||||
</children>
|
||||
</AnchorPane>
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.control.msp;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
public class TestScanner {
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
MspDevice.MspResponse response = new MspDevice.MspResponse(
|
||||
"FilamentStatus 1 ON\n"
|
||||
+ "Trip None \n"
|
||||
+ "Drive Off\n"
|
||||
+ "EmissionTripState OK\n"
|
||||
+ "ExternalTripState OK \n"
|
||||
+ "RVCTripState OK");
|
||||
System.out.println(response.get(2, 1));
|
||||
}
|
||||
|
||||
}
|
18
numass-control/vac/build.gradle
Normal file
18
numass-control/vac/build.gradle
Normal file
@ -0,0 +1,18 @@
|
||||
apply plugin: 'application'
|
||||
|
||||
version = "0.3.1"
|
||||
|
||||
if (!hasProperty('mainClass')) {
|
||||
ext.mainClass = 'inr.numass.readvac.Main'
|
||||
}
|
||||
mainClassName = mainClass
|
||||
|
||||
|
||||
dependencies {
|
||||
compile 'ch.qos.logback:logback-classic:1.1.0+'
|
||||
compile 'org.scream3r:jssc:2.8.0'
|
||||
compile 'commons-cli:commons-cli:1.3'
|
||||
compile project(':dataforge-plots')
|
||||
compile project(':dataforge-storage')
|
||||
compile project(':dataforge-control')
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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 inr.numass.readvac;
|
||||
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.control.devices.AbstractMeasurementDevice;
|
||||
import hep.dataforge.control.ports.ComPortHandler;
|
||||
import hep.dataforge.control.ports.PortHandler;
|
||||
import hep.dataforge.description.NodeDef;
|
||||
import hep.dataforge.description.ValueDef;
|
||||
import hep.dataforge.exceptions.ControlException;
|
||||
import hep.dataforge.exceptions.PortException;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import jssc.SerialPortException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@NodeDef(name = "mks", target = "metod::inr.numass.readvac.getQuery")
|
||||
@ValueDef(name = "port")
|
||||
@ValueDef(name = "delay")
|
||||
public class MKSVacuumeterDevice extends AbstractMeasurementDevice<Double> implements PortHandler.PortController {
|
||||
|
||||
// private static final String QUERY = "@253PR5?;FF";
|
||||
private static final String DELIMETER = ";FF";
|
||||
|
||||
PortHandler handler;
|
||||
|
||||
public MKSVacuumeterDevice(String name, Context context, Meta annotation) {
|
||||
super(name, context, annotation);
|
||||
}
|
||||
|
||||
private int timeout() {
|
||||
return meta().getInt("timeout", 400);
|
||||
}
|
||||
|
||||
private void initHandler() throws PortException {
|
||||
try {
|
||||
String com = meta().getString("port");
|
||||
handler = new ComPortHandler(com);
|
||||
handler.setDelimeter(DELIMETER);
|
||||
} catch (SerialPortException ex) {
|
||||
throw new PortException("Can't init port");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pressure query string. The default is "@253PR5?;FF"
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@ValueDef(name = "address")
|
||||
@ValueDef(name = "channel")
|
||||
protected String getQuery() {
|
||||
String deviceAddres = meta().getString("mks.address", "253");
|
||||
String channelNumber = meta().getString("mks.channel", "5");
|
||||
return String.format("@%sPR%s?;FF", deviceAddres, channelNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStart(Meta measurement) throws ControlException {
|
||||
Meta meta = buildMeasurementLaminate(measurement);
|
||||
initHandler();
|
||||
setState("connection", checkConnection());
|
||||
if (isConnected()) {
|
||||
setState("power", getPowerState());
|
||||
int delay = meta.getInt("delay", 5000);
|
||||
executor.scheduleWithFixedDelay(() -> {
|
||||
Double val = read();
|
||||
measurementResult(null, val);
|
||||
}, 0, delay, TimeUnit.MILLISECONDS);
|
||||
} else {
|
||||
getLogger().warn("No connection for " + getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doStop() throws ControlException {
|
||||
setPowerState(false);
|
||||
try {
|
||||
handler.close();
|
||||
} catch (Exception ex) {
|
||||
getLogger().error("Can not close the port", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Double read() {
|
||||
if (handler == null) {
|
||||
setState("connection", false);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String answer = talk(getQuery());
|
||||
if (answer == null || answer.isEmpty()) {
|
||||
setState("connection", false);
|
||||
return null;
|
||||
}
|
||||
double res = Double.parseDouble(answer);
|
||||
if (res <= 0) {
|
||||
return null;
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
} catch (ControlException ex) {
|
||||
setState("connection", false);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String talk(String request) throws ControlException {
|
||||
|
||||
String answer = handler.sendAndWait(request, timeout());
|
||||
|
||||
// if (answer.isEmpty()) {
|
||||
// throw new ControlException("No answer from " + getName());
|
||||
// }
|
||||
Matcher match = Pattern.compile("@253ACK(.*);FF").matcher(answer);
|
||||
if (match.matches()) {
|
||||
return match.group(1);
|
||||
} else {
|
||||
throw new ControlException(answer);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getPowerState() throws ControlException {
|
||||
String answer = talk("@253FP?;FF");
|
||||
return answer.equals("ON");
|
||||
}
|
||||
|
||||
private boolean checkConnection() {
|
||||
try {
|
||||
return !talk("@253T?;FF").isEmpty();
|
||||
} catch (ControlException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return getState("connection").booleanValue();
|
||||
}
|
||||
|
||||
public boolean isPowerOn() {
|
||||
return getState("power").booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cathode power state and return result
|
||||
*
|
||||
* @param state
|
||||
* @return
|
||||
* @throws ControlException
|
||||
*/
|
||||
public void setPowerState(boolean state) throws ControlException {
|
||||
boolean powerState = getPowerState();
|
||||
|
||||
if (state != powerState) {
|
||||
if (state == true) {
|
||||
String ans = talk("@253ENC!OFF;FF");
|
||||
if (!ans.equals("OFF")) {
|
||||
getLogger().warn("The @253ENC!OFF;FF command is not working");
|
||||
}
|
||||
ans = talk("@253FP!ON;FF");
|
||||
if (!ans.equals("ON")) {
|
||||
throw new ControlException("Can't set cathod power state");
|
||||
}
|
||||
} else {
|
||||
String ans = talk("@253FP!OFF;FF");
|
||||
if (!ans.equals("OFF")) {
|
||||
throw new ControlException("Can't set cathod power state");
|
||||
}
|
||||
}
|
||||
setState("power", getPowerState());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(String message) {
|
||||
//ignore async responses
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String errorMessage, Throwable error) {
|
||||
getLogger().error(errorMessage, error);
|
||||
}
|
||||
|
||||
}
|
131
numass-control/vac/src/main/java/inr/numass/readvac/Main.java
Normal file
131
numass-control/vac/src/main/java/inr/numass/readvac/Main.java
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.readvac;
|
||||
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import static hep.dataforge.context.GlobalContext.out;
|
||||
import hep.dataforge.io.MetaFileReader;
|
||||
import hep.dataforge.storage.api.Storage;
|
||||
import hep.dataforge.storage.commons.StoragePlugin;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
static String name;
|
||||
// static volatile boolean stopFlag = false;
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
Locale.setDefault(Locale.US);
|
||||
new StoragePlugin().startGlobal();
|
||||
Meta config = getAnnotation(args);
|
||||
runConfig(config);
|
||||
// System.exit(0);//на всякий случай, чтобы закрыть все боковые потоки
|
||||
}
|
||||
|
||||
public static void runConfig(Meta config) throws Exception {
|
||||
|
||||
// VACManager daemon;
|
||||
// //Определяем, является считывает ли сервер из файла или из com порта
|
||||
// boolean direct = config.getBoolean("direct", true);
|
||||
//Префикс сеанса
|
||||
String prefix = config.getString("run", name);
|
||||
|
||||
Storage server = setupServer(GlobalContext.instance(), config);
|
||||
|
||||
// if (direct) {
|
||||
// daemon = VACManager.fromSerial(server, getSerialConfig(config), prefix);
|
||||
// } else {
|
||||
// daemon = VACManager.fromDirectory(server, getDataPath(config), prefix);
|
||||
// }
|
||||
VACManager daemon = VACManager.fromSerial(server, prefix, getSerialConfig(config));
|
||||
daemon.start();
|
||||
}
|
||||
|
||||
private static Meta getSerialConfig(Meta config) {
|
||||
return config.getNode("serialconfig", config);
|
||||
}
|
||||
|
||||
private static Storage setupServer(Context context, Meta config) {
|
||||
Meta storageConfig = config.getNode("storage");
|
||||
|
||||
return context.provide("storage", StoragePlugin.class).buildStorage(storageConfig);
|
||||
}
|
||||
|
||||
// private static String getDataPath(Meta config) {
|
||||
// return config.getString("datapath", "D:\\temp\\test");
|
||||
// }
|
||||
private static Options prepareOptions() {
|
||||
Options options = new Options();
|
||||
|
||||
options.addOption("c", "config", true, "Configuration file path");
|
||||
// options.addOption("d", "dir", true, "Directory with data files");
|
||||
options.addOption("n", "name", true, "Run name");
|
||||
options.addOption("h", "home", true, "Working directory");
|
||||
// options.addOption("t", "target", true, "Target data file");
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private static Meta getAnnotation(String[] cli) throws IOException, ParseException, java.text.ParseException {
|
||||
String configPath;
|
||||
Options options = prepareOptions();
|
||||
if (cli.length == 0) {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("java -jar readVAC.jar [OPTIONS]", options);
|
||||
out().println("Trying to use default config location...");
|
||||
configPath = "vac-config.xml";
|
||||
} else {
|
||||
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
CommandLine line;
|
||||
// parse the command line arguments
|
||||
line = parser.parse(options, cli);
|
||||
|
||||
if (line.hasOption("h")) {
|
||||
System.setProperty("user.dir", line.getOptionValue("h"));
|
||||
}
|
||||
|
||||
if (line.hasOption("n")) {
|
||||
name = line.getOptionValue("n");
|
||||
}
|
||||
configPath = line.getOptionValue("c", "config.xml");
|
||||
|
||||
}
|
||||
File configFile = new File(configPath);
|
||||
|
||||
return MetaFileReader.read(configFile);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.readvac;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
class P1ControlException extends Exception {
|
||||
|
||||
/**
|
||||
* Creates a new instance of <code>p1ControlException</code> without detail
|
||||
* message.
|
||||
*/
|
||||
public P1ControlException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of <code>p1ControlException</code> with the
|
||||
* specified detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public P1ControlException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.readvac;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class ResponseParseException extends Exception {
|
||||
|
||||
String response;
|
||||
|
||||
public ResponseParseException(String response) {
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
public ResponseParseException(String response, String message) {
|
||||
super(message);
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.readvac;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Utilities;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class TextAreaOutputStream extends OutputStream {
|
||||
|
||||
private static final int MAXLINES = 500;
|
||||
|
||||
private final JTextArea textArea;
|
||||
private final StringBuilder sb = new StringBuilder();
|
||||
private final String title;
|
||||
|
||||
// public static IOManager getTextAreaIO(Context context, JTextArea area){
|
||||
// return new BasicIOManager(context, new TextAreaOutputStream(area, "system"));
|
||||
// }
|
||||
|
||||
public TextAreaOutputStream(final JTextArea textArea, String title) {
|
||||
this.textArea = textArea;
|
||||
this.title = title;
|
||||
sb.append(title).append("> ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
if (b == '\r') {
|
||||
return;
|
||||
}
|
||||
if (b == '\n') {
|
||||
final String text = sb.toString() + "\n";
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
textArea.append(text);
|
||||
while (textArea.getLineCount() >= MAXLINES) {
|
||||
try {
|
||||
textArea.getDocument().remove(0, Utilities.getRowEnd(textArea, 1));
|
||||
} catch (BadLocationException ex) {
|
||||
LoggerFactory.getLogger(getClass()).error(null, ex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
sb.setLength(0);
|
||||
sb.append(title).append("> ");
|
||||
return;
|
||||
}
|
||||
sb.append((char) b);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,412 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.readvac;
|
||||
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.data.DataPoint;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.values.Value;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import jssc.SerialPort;
|
||||
import jssc.SerialPortException;
|
||||
import jssc.SerialPortTimeoutException;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class VACDeviceReader implements Iterator<DataPoint>, AutoCloseable {
|
||||
|
||||
// private int timeout = 100;
|
||||
private final int maxChars = 50;
|
||||
private static final String CM32Query = "MES R PM 1\r\n";
|
||||
private static final String MQuery = ":010300000002FA\r\n";
|
||||
private static final String P1Query = "@253PR5?;FF";
|
||||
|
||||
SerialPort p2Port;
|
||||
SerialPort p3Port;
|
||||
SerialPort p1Port;
|
||||
SerialPort pxPort;
|
||||
|
||||
Lock p1Lock;
|
||||
Lock p2Lock;
|
||||
Lock p3Lock;
|
||||
Lock pxLock;
|
||||
|
||||
Meta p1Config;
|
||||
Meta p2Config;
|
||||
Meta p3Config;
|
||||
Meta pxConfig;
|
||||
|
||||
private boolean p1PowerOn = false;
|
||||
|
||||
public VACDeviceReader(String p2, String p3, String p1, String px) throws SerialPortException {
|
||||
setupPorts(p2, p3, p1, px);
|
||||
}
|
||||
|
||||
public VACDeviceReader(Meta serialConfig) throws SerialPortException {
|
||||
String p2 = serialConfig.getString("P2", null);
|
||||
String p3 = serialConfig.getString("P3", null);
|
||||
String p1 = serialConfig.getString("P1", null);
|
||||
String px = serialConfig.getString("Px", p1);
|
||||
// this.timeout = serialConfig.getInt("timeout", timeout);
|
||||
setupPorts(p2, p3, p1, px);
|
||||
}
|
||||
|
||||
public boolean setP1PowerStateOn(boolean state) throws SerialPortException, ResponseParseException, P1ControlException {
|
||||
|
||||
p1PowerOn = getP1PowerState();
|
||||
if (state == p1PowerOn) {
|
||||
//Возвращаем то, что есть
|
||||
return p1PowerOn;
|
||||
} else {
|
||||
|
||||
if (state == true) {
|
||||
// String ans = talkMKS(p1Port, "@253ENC!OFF;FF");
|
||||
// if (!ans.equals("OFF")) {
|
||||
// LoggerFactory.getLogger(getClass()).warn("The @253ENC!OFF;FF command is not working");
|
||||
// }
|
||||
String ans = talkMKS(p1Port, "@253FP!ON;FF");
|
||||
if (!ans.equals("ON")) {
|
||||
throw new P1ControlException("Can't set P1 cathod power state");
|
||||
}
|
||||
} else {
|
||||
String ans = talkMKS(p1Port, "@253FP!OFF;FF");
|
||||
if (!ans.equals("OFF")) {
|
||||
throw new P1ControlException("Can't set P1 cathod power state");
|
||||
}
|
||||
}
|
||||
|
||||
p1PowerOn = getP1PowerState();
|
||||
return p1PowerOn;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isP1Available() {
|
||||
try {
|
||||
return !talkMKS(p1Port, "@253T?;FF").isEmpty();
|
||||
} catch (SerialPortException | ResponseParseException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private String talkMKS(SerialPort port, String request) throws SerialPortException, ResponseParseException {
|
||||
try {
|
||||
p1Lock.lock();
|
||||
if (!port.isOpened()) {
|
||||
port.openPort();
|
||||
}
|
||||
port.purgePort(SerialPort.PURGE_RXCLEAR | SerialPort.PURGE_TXCLEAR);
|
||||
port.writeString(request);
|
||||
LoggerFactory.getLogger(port.getPortName()).info("send> " + request.trim());
|
||||
String answer = readPort(p1Port, ";FF", 100);
|
||||
|
||||
LoggerFactory.getLogger(port.getPortName()).info("recieve> " + answer.trim());
|
||||
if (answer.isEmpty()) {
|
||||
throw new ResponseParseException(answer);
|
||||
}
|
||||
Matcher match = Pattern.compile("@253ACK(.*);FF").matcher(answer);
|
||||
if (match.matches()) {
|
||||
return match.group(1);
|
||||
} else {
|
||||
throw new ResponseParseException(answer);
|
||||
}
|
||||
} finally {
|
||||
p1Lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getP1PowerState() throws SerialPortException, ResponseParseException {
|
||||
String answer = talkMKS(p1Port, "@253FP?;FF");
|
||||
return answer.equals("ON");
|
||||
}
|
||||
|
||||
/**
|
||||
* Считываем строку из порта пока не найдем delimeter или не потратим
|
||||
* timeout времени. Если случается таймаут, то возвращается null
|
||||
*
|
||||
* @param port
|
||||
* @param delimeter
|
||||
* @return
|
||||
* @throws SerialPortException
|
||||
*/
|
||||
private String readPort(SerialPort port, String delimeter, int timeout) throws SerialPortException {
|
||||
|
||||
String res = new String();
|
||||
Instant start = Instant.now();
|
||||
port.purgePort(SerialPort.PURGE_RXCLEAR | SerialPort.PURGE_TXCLEAR);
|
||||
while (res.length() < maxChars) {
|
||||
|
||||
try {
|
||||
res += port.readString(1, timeout);
|
||||
} catch (SerialPortTimeoutException ex) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (start.until(Instant.now(), ChronoUnit.MILLIS) > timeout) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (res.endsWith(delimeter)) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
if (p1Port.isOpened()) {
|
||||
p1Port.closePort();
|
||||
}
|
||||
if (pxPort.isOpened()) {
|
||||
pxPort.closePort();
|
||||
}
|
||||
if (p2Port.isOpened()) {
|
||||
p2Port.closePort();
|
||||
}
|
||||
if (p3Port.isOpened()) {
|
||||
p3Port.closePort();
|
||||
}
|
||||
try {
|
||||
this.setP1PowerStateOn(false);
|
||||
} catch (P1ControlException ex) {
|
||||
LoggerFactory.getLogger(getClass()).warn("Can't turn of the power on P1");
|
||||
}
|
||||
}
|
||||
|
||||
private void setupPorts(String p2, String p3, String p1, String px) {
|
||||
try {
|
||||
if (p2 == null) {
|
||||
p2Port = null;
|
||||
} else {
|
||||
p2Port = new SerialPort(p2);
|
||||
p2Port.openPort();
|
||||
p2Port.setParams(2400, 8, 1, 0);
|
||||
p2Lock = new ReentrantLock();
|
||||
}
|
||||
} catch (SerialPortException ex) {
|
||||
p2Port = null;
|
||||
LoggerFactory.getLogger(getClass()).error("Can't open " + p2, ex);
|
||||
}
|
||||
|
||||
try {
|
||||
if (p3 == null) {
|
||||
p3Port = null;
|
||||
} else {
|
||||
p3Port = new SerialPort(p3);
|
||||
p3Port.openPort();
|
||||
p3Port.setParams(2400, 8, 1, 0);
|
||||
p3Lock = new ReentrantLock();
|
||||
}
|
||||
} catch (SerialPortException ex) {
|
||||
p2Port = null;
|
||||
LoggerFactory.getLogger(getClass()).error("Can't open " + p3, ex);
|
||||
}
|
||||
|
||||
try {
|
||||
if (p1 == null) {
|
||||
p1Port = null;
|
||||
} else {
|
||||
p1Port = new SerialPort(p1);
|
||||
p1Port.openPort();
|
||||
p1Port.setParams(9600, 8, 1, 0);
|
||||
p1Lock = new ReentrantLock();
|
||||
}
|
||||
} catch (SerialPortException ex) {
|
||||
p2Port = null;
|
||||
LoggerFactory.getLogger(getClass()).error("Can't open " + p1, ex);
|
||||
}
|
||||
if (px == null) {
|
||||
pxPort = null;
|
||||
} else {
|
||||
if (px.equals(p1)) {
|
||||
pxPort = p1Port;
|
||||
pxLock = p1Lock;
|
||||
} else {
|
||||
try {
|
||||
|
||||
pxPort = new SerialPort(px);
|
||||
pxPort.openPort();
|
||||
pxPort.setParams(9600, 8, 1, 0);
|
||||
pxLock = new ReentrantLock();
|
||||
|
||||
} catch (SerialPortException ex) {
|
||||
p2Port = null;
|
||||
LoggerFactory.getLogger(getClass()).error("Can't open " + px, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Value readCM(SerialPort port) {
|
||||
try {
|
||||
if (!port.isOpened()) {
|
||||
port.openPort();
|
||||
}
|
||||
port.purgePort(SerialPort.PURGE_RXCLEAR | SerialPort.PURGE_TXCLEAR);
|
||||
port.writeString(CM32Query);
|
||||
LoggerFactory.getLogger(port.getPortName()).info("send> " + CM32Query.trim());
|
||||
// try {
|
||||
// Thread.sleep(200);
|
||||
// } catch (InterruptedException ex) {
|
||||
// Logger.getLogger(VACDeviceReader.class.getName()).log(Level.SEVERE, null, ex);
|
||||
// }
|
||||
String answer = readPort(port, "T--", 400);
|
||||
LoggerFactory.getLogger(port.getPortName()).info("recieve> " + answer.trim());
|
||||
if (answer.isEmpty()) {
|
||||
return Value.of("EMPTY");
|
||||
}
|
||||
|
||||
if (answer.indexOf("PM1:mbar") < -1) {
|
||||
return Value.of("PARSE");
|
||||
}
|
||||
|
||||
if (answer.substring(14, 17).equals("OFF")) {
|
||||
return Value.of("OFF");
|
||||
}
|
||||
return Value.of(Double.parseDouble(answer.substring(14, 17) + answer.substring(19, 23)));
|
||||
} catch (SerialPortException ex) {
|
||||
return Value.of("COM_ERR");
|
||||
}/* catch (SerialPortTimeoutException ex) {
|
||||
return Value.of("COM_TIMEOUT");
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
private Value readP1() {
|
||||
if (p1Port == null) {
|
||||
return Value.of("NO_CON");
|
||||
}
|
||||
try {
|
||||
String answer = talkMKS(p1Port, P1Query);
|
||||
if (answer == null || answer.isEmpty()) {
|
||||
return Value.of("EMPTY");
|
||||
}
|
||||
double res = Double.parseDouble(answer);
|
||||
if (res <= 0) {
|
||||
return Value.of("OFF");
|
||||
} else {
|
||||
return Value.of(res);
|
||||
}
|
||||
} catch (SerialPortException ex) {
|
||||
return Value.of("COM_ERR");
|
||||
} catch (ResponseParseException ex) {
|
||||
return Value.of("PARSE");
|
||||
}
|
||||
}
|
||||
|
||||
private Value readPx() {
|
||||
if (pxPort == null) {
|
||||
return Value.of("NO_CON");
|
||||
}
|
||||
try {
|
||||
if (!pxPort.isOpened()) {
|
||||
pxPort.openPort();
|
||||
}
|
||||
pxPort.purgePort(SerialPort.PURGE_RXCLEAR | SerialPort.PURGE_TXCLEAR);
|
||||
pxPort.writeString(MQuery);
|
||||
LoggerFactory.getLogger(pxPort.getPortName()).info("send> " + MQuery.trim());
|
||||
|
||||
String answer = readPort(pxPort, "\r\n", 100);
|
||||
LoggerFactory.getLogger(pxPort.getPortName()).info("recieve> " + answer.trim());
|
||||
|
||||
if (answer.isEmpty()) {
|
||||
return Value.of("EMPTY");
|
||||
}
|
||||
Matcher match = Pattern.compile(":010304(\\w{4})(\\w{4})..\r\n").matcher(answer);
|
||||
|
||||
if (match.matches()) {
|
||||
double base = (double) (Integer.parseInt(match.group(1), 16)) / 10d;
|
||||
int exp = Integer.parseInt(match.group(2), 16);
|
||||
if (exp > 32766) {
|
||||
exp = exp - 65536;
|
||||
}
|
||||
BigDecimal res = BigDecimal.valueOf(base * Math.pow(10, exp));
|
||||
res = res.setScale(4, RoundingMode.CEILING);
|
||||
return Value.of(res);
|
||||
} else {
|
||||
return Value.of("PARSE");
|
||||
}
|
||||
} catch (SerialPortException ex) {
|
||||
return Value.of("COM_ERR");
|
||||
}
|
||||
}
|
||||
|
||||
private Value readP2() {
|
||||
if (p2Port == null) {
|
||||
return Value.of("NO_CON");
|
||||
}
|
||||
try {
|
||||
p2Lock.lock();
|
||||
return readCM(p2Port);
|
||||
} finally {
|
||||
p2Lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private Value readP3() {
|
||||
if (p3Port == null) {
|
||||
return Value.of("NO_CON");
|
||||
}
|
||||
try {
|
||||
p3Lock.lock();
|
||||
return readCM(p3Port);
|
||||
} finally {
|
||||
p3Lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataPoint next() {
|
||||
Value p1 = readP1();
|
||||
Value p2 = readP2();
|
||||
Value p3 = readP3();
|
||||
Value px = readPx();
|
||||
Value time = Value.of(Instant.now().truncatedTo(ChronoUnit.SECONDS));
|
||||
return new MapDataPoint(VACManager.names, time, p1, p2, p3, px);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//P2, P3:
|
||||
//Q:"MES R PM 1\r\n"
|
||||
//A:"PM1:mbar : 2.3 E-03:T--
|
||||
//"
|
||||
//
|
||||
//P1:
|
||||
//Q:"@253PR4?;FF"
|
||||
//A:"@253ACK3.891E+1;FF"
|
||||
//
|
||||
//Px:
|
||||
//Q:":010300000002FA\r\n"
|
||||
//A:":0103040014FFFEE7"
|
||||
//нужно брать символы с 8 по 12
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.readvac;
|
||||
|
||||
import hep.dataforge.data.DataParser;
|
||||
import hep.dataforge.data.DataPoint;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.io.LineIterator;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class VACFileReader implements Iterator<DataPoint> {
|
||||
|
||||
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");//14.04.2014 21:30:10
|
||||
|
||||
public static VACFileReader fromDirectory(String dir) throws FileNotFoundException {
|
||||
File directory = new File(dir);
|
||||
String[] list = directory.list((File dir1, String name) -> name.startsWith("VacTMS") && name.endsWith(".txt"));
|
||||
if(list.length == 0){
|
||||
throw new FileNotFoundException("Data files not found in the given directory");
|
||||
}
|
||||
Arrays.sort(list);
|
||||
return new VACFileReader(new File(directory,list[list.length-1]));
|
||||
}
|
||||
|
||||
public static VACFileReader fromFile(String file) throws FileNotFoundException {
|
||||
return new VACFileReader(new File(file));
|
||||
}
|
||||
|
||||
private final LineIterator iterator;
|
||||
private final DataParser parser;
|
||||
|
||||
private VACFileReader(File vacFile) throws FileNotFoundException {
|
||||
this.iterator = new LineIterator(vacFile);
|
||||
iterator.next();
|
||||
parser = new LikhovidVACParser();
|
||||
}
|
||||
|
||||
public VACFileReader(File vacFile, DataParser parser) throws FileNotFoundException {
|
||||
this.iterator = new LineIterator(vacFile);
|
||||
iterator.next();
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
public DataPoint get(Instant time) {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
public DataPoint getLast() {
|
||||
DataPoint point = null;
|
||||
while (hasNext()) {
|
||||
point = next();
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataPoint next() {
|
||||
if (iterator.hasNext()) {
|
||||
return parser.parse(iterator.next());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<DataPoint> updateFrom(Instant from) {
|
||||
List<DataPoint> res = new ArrayList<>();
|
||||
while (iterator.hasNext()) {
|
||||
DataPoint point = next();
|
||||
if (point != null && point.getValue("timestamp").timeValue().isAfter(from)) {
|
||||
res.add(point);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public List<DataPoint> updateFrom() {
|
||||
List<DataPoint> res = new ArrayList<>();
|
||||
while (iterator.hasNext()) {
|
||||
DataPoint point = next();
|
||||
if (point != null) {
|
||||
res.add(point);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static class LikhovidVACParser implements DataParser {
|
||||
static final Pattern pattern = Pattern.compile("(\\S* \\S*)\\s*(\\S*);\\s*(\\S*)\\s*(\\S*)\\s*(\\S*)");
|
||||
@Override
|
||||
public DataPoint parse(String str) {
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
if(!matcher.matches()){
|
||||
return null;
|
||||
}
|
||||
|
||||
LocalDateTime dt = LocalDateTime.parse(matcher.group(1), formatter);
|
||||
Instant time = dt.toInstant(ZoneOffset.ofHours(0));
|
||||
String p1 = matcher.group(2);
|
||||
String p2 = matcher.group(3);
|
||||
String p3 = matcher.group(4);
|
||||
String px = matcher.group(5);
|
||||
|
||||
|
||||
return new MapDataPoint(VACManager.names, new Object[]{time, p1, p2, p3, px});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,395 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.9" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
|
||||
<Properties>
|
||||
<Property name="defaultCloseOperation" type="int" value="2"/>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[800, 180]"/>
|
||||
</Property>
|
||||
<Property name="name" type="java.lang.String" value="mainFrame" noResource="true"/>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[1052, 600]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AccessibilityProperties>
|
||||
<Property name="AccessibleContext.accessibleParent" type="javax.accessibility.Accessible" editor="org.netbeans.modules.form.ComponentChooserEditor">
|
||||
<ComponentRef name="Form"/>
|
||||
</Property>
|
||||
</AccessibilityProperties>
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
|
||||
</SyntheticProperties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,-33,0,0,4,28"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout">
|
||||
<Property name="axis" type="int" value="1"/>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="valuesPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.BevelBorderInfo">
|
||||
<BevelBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 90]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="15" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="jLabel5" max="32767" attributes="0"/>
|
||||
<Component id="timeLabel" pref="180" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="122" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="p1Label" max="32767" attributes="0"/>
|
||||
<Component id="jLabel1" min="-2" pref="81" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="104" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="p2Label" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="jLabel2" alignment="0" min="-2" pref="81" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="104" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="p3Label" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="jLabel3" alignment="0" min="-2" pref="81" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="106" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="pxLabel" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="jLabel4" alignment="0" min="-2" pref="81" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="53" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="jLabel4" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="pxLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="jLabel3" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="p3Label" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="p2Label" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jLabel5" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="p1Label" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="timeLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="jLabel1">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="24" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="P1"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="p1Label">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="24" style="1"/>
|
||||
</Property>
|
||||
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="0" green="0" id="red" palette="1" red="ff" type="palette"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="EMPTY"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel2">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="24" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="P2"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="p2Label">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="24" style="1"/>
|
||||
</Property>
|
||||
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="0" id="blue" palette="1" red="0" type="palette"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="EMPTY"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel3">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="24" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="P3"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="p3Label">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="24" style="1"/>
|
||||
</Property>
|
||||
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="0" green="ff" id="green" palette="1" red="0" type="palette"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="EMPTY"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel4">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="24" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="Px"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="pxLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="24" style="1"/>
|
||||
</Property>
|
||||
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="0" id="magenta" palette="1" red="ff" type="palette"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="EMPTY"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="timeLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="24" style="1"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="EMPTY"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel5">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="24" style="0"/>
|
||||
</Property>
|
||||
<Property name="horizontalAlignment" type="int" value="0"/>
|
||||
<Property name="text" type="java.lang.String" value="time"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="optionsPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.BevelBorderInfo">
|
||||
<BevelBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 50]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[0, 50]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[1052, 50]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="4" max="-2" attributes="0"/>
|
||||
<Component id="jLabel6" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="delayBox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="32" max="-2" attributes="0"/>
|
||||
<Component id="jLabel7" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="rangeBox" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="427" max="32767" attributes="0"/>
|
||||
<Component id="p1Power" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="60" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="jLabel7" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="rangeBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="delayBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jLabel6" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="p1Power" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="40" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="jLabel6">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Частота обновления (с):"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="delayBox">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="5">
|
||||
<StringItem index="0" value="1"/>
|
||||
<StringItem index="1" value="5"/>
|
||||
<StringItem index="2" value="10"/>
|
||||
<StringItem index="3" value="30"/>
|
||||
<StringItem index="4" value="60"/>
|
||||
</StringArray>
|
||||
</Property>
|
||||
<Property name="selectedIndex" type="int" value="1"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="delayBoxItemStateChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JComboBox" name="rangeBox">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||
<StringArray count="5">
|
||||
<StringItem index="0" value="10"/>
|
||||
<StringItem index="1" value="30"/>
|
||||
<StringItem index="2" value="60"/>
|
||||
<StringItem index="3" value="180"/>
|
||||
<StringItem index="4" value="300"/>
|
||||
</StringArray>
|
||||
</Property>
|
||||
<Property name="selectedIndex" type="int" value="2"/>
|
||||
<Property name="toolTipText" type="java.lang.String" value=""/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="rangeBoxItemStateChanged"/>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="rangeBoxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jLabel7">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Максимальный диапазон (мин):"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JToggleButton" name="p1Power">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" value="Холодный катод на P1"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="p1PowerActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JSplitPane" name="split">
|
||||
<Properties>
|
||||
<Property name="orientation" type="int" value="0"/>
|
||||
<Property name="resizeWeight" type="double" value="1.0"/>
|
||||
<Property name="alignmentX" type="float" value="0.5"/>
|
||||
<Property name="alignmentY" type="float" value="0.5"/>
|
||||
<Property name="oneTouchExpandable" type="boolean" value="true"/>
|
||||
</Properties>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="chartPannel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.BevelBorderInfo">
|
||||
<BevelBorder/>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="autoscrolls" type="boolean" value="true"/>
|
||||
</Properties>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||
<JSplitPaneConstraints position="top"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
</Container>
|
||||
<Container class="javax.swing.JScrollPane" name="scroll">
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
|
||||
<JSplitPaneConstraints position="bottom"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JTextArea" name="consoleBox">
|
||||
<Properties>
|
||||
<Property name="editable" type="boolean" value="false"/>
|
||||
<Property name="columns" type="int" value="20"/>
|
||||
<Property name="lineWrap" type="boolean" value="true"/>
|
||||
<Property name="rows" type="int" value="5"/>
|
||||
</Properties>
|
||||
<AccessibilityProperties>
|
||||
<Property name="AccessibleContext.accessibleParent" type="javax.accessibility.Accessible" editor="org.netbeans.modules.form.ComponentChooserEditor">
|
||||
<ComponentRef name="split"/>
|
||||
</Property>
|
||||
</AccessibilityProperties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -0,0 +1,542 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.readvac;
|
||||
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
import ch.qos.logback.core.encoder.EchoEncoder;
|
||||
import ch.qos.logback.core.encoder.Encoder;
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import hep.dataforge.data.DataPoint;
|
||||
import hep.dataforge.io.BasicIOManager;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaBuilder;
|
||||
import hep.dataforge.plots.data.DynamicPlottable;
|
||||
import hep.dataforge.plots.data.DynamicPlottableSet;
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||
import hep.dataforge.values.Value;
|
||||
import hep.dataforge.values.ValueType;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import javax.swing.AbstractButton;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.jfree.chart.axis.LogarithmicAxis;
|
||||
import org.jfree.chart.plot.XYPlot;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class VACFrame extends javax.swing.JFrame {
|
||||
|
||||
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
|
||||
|
||||
public static VACFrame display(VACManager daemon) {
|
||||
/* Set the Nimbus look and feel */
|
||||
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
|
||||
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
|
||||
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
|
||||
*/
|
||||
try {
|
||||
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
|
||||
if ("Nimbus".equals(info.getName())) {
|
||||
javax.swing.UIManager.setLookAndFeel(info.getClassName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
|
||||
java.util.logging.Logger.getLogger(VACFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
}
|
||||
//</editor-fold>
|
||||
VACFrame frame = new VACFrame();
|
||||
frame.daemon = daemon;
|
||||
boolean p1Available = daemon.p1Available();
|
||||
frame.p1Power.setEnabled(p1Available);
|
||||
if (p1Available) {
|
||||
try {
|
||||
frame.updateP1PowerState(daemon.getP1PowerState());
|
||||
} catch (P1ControlException ex) {
|
||||
LoggerFactory.getLogger("COM-P1").error(ex.getMessage());
|
||||
}
|
||||
} else {
|
||||
frame.p1Power.setText("P1 недоступен");
|
||||
}
|
||||
|
||||
frame.addWindowListener(new java.awt.event.WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent winEvt) {
|
||||
try {
|
||||
daemon.close();
|
||||
} catch (Exception ex) {
|
||||
LoggerFactory.getLogger(VACFrame.class).error(null, ex);
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
// /* Create and displayPoint the form */
|
||||
// SwingUtilities.invokeLater(() -> {
|
||||
// frame.setVisible(true);
|
||||
//// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
// });
|
||||
frame.setVisible(true);
|
||||
return frame;
|
||||
}
|
||||
|
||||
private VACManager daemon;
|
||||
|
||||
private JFreeChartFrame plotFrame;
|
||||
private DynamicPlottableSet plottables;
|
||||
// private int savedSplitHeight = 600;
|
||||
|
||||
/**
|
||||
* Creates new form VACFrame
|
||||
*/
|
||||
private VACFrame() {
|
||||
setTitle("Numass vacuum measurement view");
|
||||
initComponents();
|
||||
split.getRightComponent().setMinimumSize(new Dimension());
|
||||
split.setDividerLocation(1.0);
|
||||
GlobalContext.instance().attachIoManager(new BasicIOManager(new TextAreaOutputStream(consoleBox, "CONSOLE")));
|
||||
|
||||
JTextAreaAppender app = new JTextAreaAppender(consoleBox);
|
||||
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
|
||||
app.setContext(lc);
|
||||
app.start();
|
||||
lc.getLogger("ROOT").addAppender(app);
|
||||
|
||||
plottables = setupPlot();
|
||||
displayChart();
|
||||
}
|
||||
|
||||
private DynamicPlottableSet setupPlot() {
|
||||
DynamicPlottable p1 = DynamicPlottable.build("P1", "timestamp", "pressure", "RED", 2.5);
|
||||
DynamicPlottable p2 = DynamicPlottable.build("P2", "timestamp", "pressure", "BLUE", 2.5);
|
||||
DynamicPlottable p3 = DynamicPlottable.build("P3", "timestamp", "pressure", "GREEN", 2.5);
|
||||
DynamicPlottable px = DynamicPlottable.build("Px", "timestamp", "pressure", "MAGENTA", 2.5);
|
||||
return new DynamicPlottableSet(p1, p2, p3, px);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
valuesPanel = new javax.swing.JPanel();
|
||||
jLabel1 = new javax.swing.JLabel();
|
||||
p1Label = new javax.swing.JLabel();
|
||||
jLabel2 = new javax.swing.JLabel();
|
||||
p2Label = new javax.swing.JLabel();
|
||||
jLabel3 = new javax.swing.JLabel();
|
||||
p3Label = new javax.swing.JLabel();
|
||||
jLabel4 = new javax.swing.JLabel();
|
||||
pxLabel = new javax.swing.JLabel();
|
||||
timeLabel = new javax.swing.JLabel();
|
||||
jLabel5 = new javax.swing.JLabel();
|
||||
optionsPanel = new javax.swing.JPanel();
|
||||
jLabel6 = new javax.swing.JLabel();
|
||||
delayBox = new javax.swing.JComboBox();
|
||||
rangeBox = new javax.swing.JComboBox();
|
||||
jLabel7 = new javax.swing.JLabel();
|
||||
p1Power = new javax.swing.JToggleButton();
|
||||
split = new javax.swing.JSplitPane();
|
||||
chartPannel = new javax.swing.JPanel();
|
||||
scroll = new javax.swing.JScrollPane();
|
||||
consoleBox = new javax.swing.JTextArea();
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
|
||||
setMinimumSize(new java.awt.Dimension(800, 180));
|
||||
setName("mainFrame"); // NOI18N
|
||||
setPreferredSize(new java.awt.Dimension(1052, 600));
|
||||
getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.Y_AXIS));
|
||||
|
||||
valuesPanel.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
|
||||
valuesPanel.setMinimumSize(new java.awt.Dimension(0, 90));
|
||||
|
||||
jLabel1.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
|
||||
jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
jLabel1.setText("P1");
|
||||
|
||||
p1Label.setFont(new java.awt.Font("Tahoma", 1, 24)); // NOI18N
|
||||
p1Label.setForeground(java.awt.Color.red);
|
||||
p1Label.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
p1Label.setText("EMPTY");
|
||||
|
||||
jLabel2.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
|
||||
jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
jLabel2.setText("P2");
|
||||
|
||||
p2Label.setFont(new java.awt.Font("Tahoma", 1, 24)); // NOI18N
|
||||
p2Label.setForeground(java.awt.Color.blue);
|
||||
p2Label.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
p2Label.setText("EMPTY");
|
||||
|
||||
jLabel3.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
|
||||
jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
jLabel3.setText("P3");
|
||||
|
||||
p3Label.setFont(new java.awt.Font("Tahoma", 1, 24)); // NOI18N
|
||||
p3Label.setForeground(java.awt.Color.green);
|
||||
p3Label.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
p3Label.setText("EMPTY");
|
||||
|
||||
jLabel4.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
|
||||
jLabel4.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
jLabel4.setText("Px");
|
||||
|
||||
pxLabel.setFont(new java.awt.Font("Tahoma", 1, 24)); // NOI18N
|
||||
pxLabel.setForeground(java.awt.Color.magenta);
|
||||
pxLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
pxLabel.setText("EMPTY");
|
||||
|
||||
timeLabel.setFont(new java.awt.Font("Tahoma", 1, 24)); // NOI18N
|
||||
timeLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
timeLabel.setText("EMPTY");
|
||||
|
||||
jLabel5.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
|
||||
jLabel5.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
jLabel5.setText("time");
|
||||
|
||||
javax.swing.GroupLayout valuesPanelLayout = new javax.swing.GroupLayout(valuesPanel);
|
||||
valuesPanel.setLayout(valuesPanelLayout);
|
||||
valuesPanelLayout.setHorizontalGroup(
|
||||
valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(valuesPanelLayout.createSequentialGroup()
|
||||
.addGap(15, 15, 15)
|
||||
.addGroup(valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(jLabel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(timeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 180, Short.MAX_VALUE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 122, Short.MAX_VALUE)
|
||||
.addGroup(valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(p1Label, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 104, Short.MAX_VALUE)
|
||||
.addGroup(valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(p2Label, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 104, Short.MAX_VALUE)
|
||||
.addGroup(valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(p3Label, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 106, Short.MAX_VALUE)
|
||||
.addGroup(valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addComponent(pxLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addContainerGap(53, Short.MAX_VALUE))
|
||||
);
|
||||
valuesPanelLayout.setVerticalGroup(
|
||||
valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(valuesPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(valuesPanelLayout.createSequentialGroup()
|
||||
.addComponent(jLabel4)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(pxLabel))
|
||||
.addGroup(valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(valuesPanelLayout.createSequentialGroup()
|
||||
.addComponent(jLabel3)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(p3Label))
|
||||
.addGroup(valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(valuesPanelLayout.createSequentialGroup()
|
||||
.addComponent(jLabel2)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(p2Label))
|
||||
.addGroup(valuesPanelLayout.createSequentialGroup()
|
||||
.addGroup(valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jLabel1)
|
||||
.addComponent(jLabel5))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(valuesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(p1Label)
|
||||
.addComponent(timeLabel))))))
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
getContentPane().add(valuesPanel);
|
||||
|
||||
optionsPanel.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
|
||||
optionsPanel.setMaximumSize(new java.awt.Dimension(32767, 50));
|
||||
optionsPanel.setMinimumSize(new java.awt.Dimension(0, 50));
|
||||
optionsPanel.setPreferredSize(new java.awt.Dimension(1052, 50));
|
||||
|
||||
jLabel6.setText("Частота обновления (с):");
|
||||
|
||||
delayBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "1", "5", "10", "30", "60" }));
|
||||
delayBox.setSelectedIndex(1);
|
||||
delayBox.addItemListener(new java.awt.event.ItemListener() {
|
||||
public void itemStateChanged(java.awt.event.ItemEvent evt) {
|
||||
delayBoxItemStateChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
rangeBox.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "10", "30", "60", "180", "300" }));
|
||||
rangeBox.setSelectedIndex(2);
|
||||
rangeBox.setToolTipText("");
|
||||
rangeBox.addItemListener(new java.awt.event.ItemListener() {
|
||||
public void itemStateChanged(java.awt.event.ItemEvent evt) {
|
||||
rangeBoxItemStateChanged(evt);
|
||||
}
|
||||
});
|
||||
rangeBox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
rangeBoxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
jLabel7.setText("Максимальный диапазон (мин):");
|
||||
|
||||
p1Power.setText("Холодный катод на P1");
|
||||
p1Power.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
p1PowerActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout optionsPanelLayout = new javax.swing.GroupLayout(optionsPanel);
|
||||
optionsPanel.setLayout(optionsPanelLayout);
|
||||
optionsPanelLayout.setHorizontalGroup(
|
||||
optionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(optionsPanelLayout.createSequentialGroup()
|
||||
.addGap(4, 4, 4)
|
||||
.addComponent(jLabel6)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(delayBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(32, 32, 32)
|
||||
.addComponent(jLabel7)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(rangeBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 427, Short.MAX_VALUE)
|
||||
.addComponent(p1Power)
|
||||
.addGap(60, 60, 60))
|
||||
);
|
||||
optionsPanelLayout.setVerticalGroup(
|
||||
optionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(optionsPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(optionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jLabel7)
|
||||
.addComponent(rangeBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(delayBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jLabel6)
|
||||
.addComponent(p1Power))
|
||||
.addGap(40, 40, 40))
|
||||
);
|
||||
|
||||
getContentPane().add(optionsPanel);
|
||||
|
||||
split.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
||||
split.setResizeWeight(1.0);
|
||||
split.setAlignmentX(0.5F);
|
||||
split.setAlignmentY(0.5F);
|
||||
split.setOneTouchExpandable(true);
|
||||
|
||||
chartPannel.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
|
||||
chartPannel.setAutoscrolls(true);
|
||||
chartPannel.setLayout(new java.awt.BorderLayout());
|
||||
split.setTopComponent(chartPannel);
|
||||
|
||||
consoleBox.setEditable(false);
|
||||
consoleBox.setColumns(20);
|
||||
consoleBox.setLineWrap(true);
|
||||
consoleBox.setRows(5);
|
||||
scroll.setViewportView(consoleBox);
|
||||
consoleBox.getAccessibleContext().setAccessibleParent(split);
|
||||
|
||||
split.setBottomComponent(scroll);
|
||||
|
||||
getContentPane().add(split);
|
||||
|
||||
getAccessibleContext().setAccessibleParent(this);
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void delayBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_delayBoxItemStateChanged
|
||||
setTimerInterval(Integer.parseInt((String) evt.getItem()));
|
||||
}//GEN-LAST:event_delayBoxItemStateChanged
|
||||
|
||||
private void rangeBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_rangeBoxItemStateChanged
|
||||
setAutoRange(Integer.parseInt((String) evt.getItem()) * 60);
|
||||
}//GEN-LAST:event_rangeBoxItemStateChanged
|
||||
|
||||
private void p1PowerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_p1PowerActionPerformed
|
||||
AbstractButton abstractButton = (AbstractButton) evt.getSource();
|
||||
daemon.stop();
|
||||
boolean selected = abstractButton.getModel().isSelected();
|
||||
try {
|
||||
updateP1PowerState(daemon.setP1PowerStateOn(selected));
|
||||
} catch (P1ControlException ex) {
|
||||
LoggerFactory.getLogger(getClass()).error(ex.getMessage());
|
||||
try {
|
||||
updateP1PowerState(daemon.getP1PowerState());
|
||||
} catch (P1ControlException ex1) {
|
||||
LoggerFactory.getLogger(getClass()).error(ex1.getMessage());
|
||||
}
|
||||
}
|
||||
daemon.start();
|
||||
}//GEN-LAST:event_p1PowerActionPerformed
|
||||
|
||||
private void rangeBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rangeBoxActionPerformed
|
||||
// TODO add your handling code here:
|
||||
}//GEN-LAST:event_rangeBoxActionPerformed
|
||||
|
||||
private void updateP1PowerState(boolean state) {
|
||||
p1Power.setSelected(state);
|
||||
if (state) {
|
||||
p1Power.setText("P1 включен");
|
||||
} else {
|
||||
p1Power.setText("P1 выключен");
|
||||
}
|
||||
}
|
||||
|
||||
public void setTimerInterval(int seconds) {
|
||||
daemon.setTimerInterval(seconds * 1000);
|
||||
}
|
||||
|
||||
public void setAutoRange(int seconds) {
|
||||
plottables.setMaxAge(seconds * 1000);
|
||||
}
|
||||
|
||||
private void displayChart() {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
Meta plotConfig = new MetaBuilder("plotFrame")
|
||||
.setNode(new MetaBuilder("yAxis")
|
||||
.setValue("logAxis", true)
|
||||
.setValue("axisTitle", "pressure")
|
||||
.setValue("axisUnits", "mbar")
|
||||
)
|
||||
.setValue("xAxis.timeAxis", true);
|
||||
this.plotFrame = new JFreeChartFrame("pressures", plotConfig, chartPannel);
|
||||
XYPlot xyPlot = plotFrame.getChart().getXYPlot();
|
||||
|
||||
LogarithmicAxis logAxis = new LogarithmicAxis("Pressure (mbar)");
|
||||
// logAxis.setTickUnit(new NumberTickUnit(2));
|
||||
logAxis.setMinorTickCount(10);
|
||||
logAxis.setExpTickLabelsFlag(true);
|
||||
logAxis.setMinorTickMarksVisible(true);
|
||||
xyPlot.setRangeAxis(logAxis);
|
||||
// xyPlot.getRenderer().setBaseStroke(new BasicStroke(3));
|
||||
// xyPlot.setBackgroundPaint(Color.WHITE);
|
||||
// xyPlot.setRangeGridlinesVisible(true);
|
||||
// xyPlot.setRangeGridlinePaint(Color.BLACK);
|
||||
//
|
||||
// xyPlot.setRangeMinorGridlinesVisible(true);
|
||||
// xyPlot.setRangeMinorGridlinePaint(Color.BLACK);
|
||||
|
||||
//adding data to the frame
|
||||
plotFrame.addAll(plottables);
|
||||
});
|
||||
validate();
|
||||
// pack();
|
||||
}
|
||||
|
||||
private void setMaxAge(int seconds) {
|
||||
plottables.setMaxAge(seconds * 1000);
|
||||
}
|
||||
|
||||
public void displayPoint(DataPoint point) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
plottables.put(point);
|
||||
timeLabel.setText(formatter
|
||||
.format(LocalDateTime
|
||||
.ofInstant(point.getValue("timestamp").timeValue(), ZoneId.of("UTC"))));
|
||||
p1Label.setText(normalize(point.getValue("P1")));
|
||||
p2Label.setText(normalize(point.getValue("P2")));
|
||||
p3Label.setText(normalize(point.getValue("P3")));
|
||||
pxLabel.setText(normalize(point.getValue("Px")));
|
||||
});
|
||||
}
|
||||
|
||||
private String normalize(Value val) {
|
||||
if (val.valueType() == ValueType.NUMBER) {
|
||||
return String.format("%.2e", val.doubleValue());
|
||||
} else {
|
||||
return String.format("%s", val.stringValue());
|
||||
}
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JPanel chartPannel;
|
||||
private javax.swing.JTextArea consoleBox;
|
||||
private javax.swing.JComboBox delayBox;
|
||||
private javax.swing.JLabel jLabel1;
|
||||
private javax.swing.JLabel jLabel2;
|
||||
private javax.swing.JLabel jLabel3;
|
||||
private javax.swing.JLabel jLabel4;
|
||||
private javax.swing.JLabel jLabel5;
|
||||
private javax.swing.JLabel jLabel6;
|
||||
private javax.swing.JLabel jLabel7;
|
||||
private javax.swing.JPanel optionsPanel;
|
||||
private javax.swing.JLabel p1Label;
|
||||
private javax.swing.JToggleButton p1Power;
|
||||
private javax.swing.JLabel p2Label;
|
||||
private javax.swing.JLabel p3Label;
|
||||
private javax.swing.JLabel pxLabel;
|
||||
private javax.swing.JComboBox rangeBox;
|
||||
private javax.swing.JScrollPane scroll;
|
||||
private javax.swing.JSplitPane split;
|
||||
private javax.swing.JLabel timeLabel;
|
||||
private javax.swing.JPanel valuesPanel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
private class JTextAreaAppender extends AppenderBase<ILoggingEvent> {
|
||||
|
||||
private Encoder<ILoggingEvent> encoder = new EchoEncoder<ILoggingEvent>();
|
||||
private ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
private JTextArea textArea;
|
||||
|
||||
public JTextAreaAppender(JTextArea textArea) {
|
||||
this.textArea = textArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
try {
|
||||
encoder.init(out);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
|
||||
super.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void append(ILoggingEvent event) {
|
||||
try {
|
||||
encoder.doEncode(event);
|
||||
out.flush();
|
||||
String line = out.toString();
|
||||
textArea.append(line);
|
||||
out.reset();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.readvac;
|
||||
|
||||
import hep.dataforge.data.DataFormatBuilder;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.data.DataPoint;
|
||||
import hep.dataforge.exceptions.StorageException;
|
||||
import hep.dataforge.storage.api.PointLoader;
|
||||
import hep.dataforge.storage.api.Storage;
|
||||
import hep.dataforge.storage.commons.LoaderFactory;
|
||||
import hep.dataforge.values.ValueType;
|
||||
import java.time.Instant;
|
||||
import java.util.Iterator;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import javax.swing.SwingUtilities;
|
||||
import jssc.SerialPortException;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class VACManager implements AutoCloseable {
|
||||
|
||||
public static String[] names = {"timestamp", "P1", "P2", "P3", "Px"};
|
||||
|
||||
private VACFrame frame;
|
||||
|
||||
private Timer timer;
|
||||
|
||||
private int timerInterval = 5000;
|
||||
|
||||
// private boolean isValuesShowing;
|
||||
// private boolean isLogShowing;
|
||||
private final PointLoader loader;
|
||||
private VACDeviceReader device;
|
||||
private final Iterator<DataPoint> reader; // Чтение из файла или непосредтсвенно с прибора
|
||||
|
||||
private Instant lastUpdate;
|
||||
|
||||
// public static VACManager fromDirectory(Storage server, String sourceDir, String runPrefix) throws StorageException, FileNotFoundException {
|
||||
// return new VACManager(setupLoader(server, runPrefix), VACFileReader.fromDirectory(sourceDir));
|
||||
// }
|
||||
public static VACManager fromSerial(Storage server, String run, Meta serialConfig) throws StorageException, SerialPortException {
|
||||
return new VACManager(setupLoader(server, run), new VACDeviceReader(serialConfig));
|
||||
}
|
||||
|
||||
public VACManager(PointLoader loader, Iterator<DataPoint> reader) {
|
||||
this.loader = loader;
|
||||
this.reader = reader;
|
||||
showPlot();
|
||||
}
|
||||
|
||||
public VACManager(PointLoader loader, VACDeviceReader reader) {
|
||||
this.loader = loader;
|
||||
this.reader = reader;
|
||||
this.device = reader;
|
||||
showPlot();
|
||||
}
|
||||
|
||||
private static PointLoader setupLoader(Storage storage, String run) throws StorageException {
|
||||
return LoaderFactory.buildPointLoder(storage, "vactms", run, "timestamp",
|
||||
new DataFormatBuilder(names)
|
||||
.setFormat("timestamp", ValueType.TIME)
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the timerInterval
|
||||
*/
|
||||
public int getTimerInterval() {
|
||||
return timerInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Интервал в милисекундах
|
||||
*
|
||||
* @param millis
|
||||
*/
|
||||
public void setTimerInterval(int millis) {
|
||||
this.timerInterval = millis;
|
||||
//Перезапускаем таймер, чтобы обновились интервалы
|
||||
stop();
|
||||
start();
|
||||
// setAutoRange(millis*500);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
timer = new Timer("UpdateTimer");
|
||||
timer.scheduleAtFixedRate(getTimerTask(), 0, getTimerInterval());
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
timer.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
stop();
|
||||
if (device != null) {
|
||||
device.close();
|
||||
}
|
||||
loader.close();
|
||||
}
|
||||
|
||||
public final void showPlot() {
|
||||
if (frame != null) {
|
||||
if (frame.isDisplayable()) {
|
||||
frame.setVisible(true);
|
||||
} else {
|
||||
//Подчищаем неправильно закрытые окна
|
||||
frame.dispose();
|
||||
frame = null;
|
||||
}
|
||||
}
|
||||
if (frame == null) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
frame = VACFrame.display(VACManager.this);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public DataPoint readPoint() {
|
||||
return reader.next();
|
||||
}
|
||||
|
||||
public boolean hasNextPoint() {
|
||||
return reader.hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Пропускаем все точки, до определенного момента. Возвращаем последнюю
|
||||
* точку в списке, или первую, время которой больше, чем у заданной
|
||||
*
|
||||
* @param time
|
||||
* @return
|
||||
*/
|
||||
public DataPoint skipUntil(Instant time) {
|
||||
if (reader.hasNext()) {
|
||||
DataPoint point = reader.next();
|
||||
while (point.getValue("timestamp").timeValue().isBefore(time) && reader.hasNext()) {
|
||||
point = reader.next();
|
||||
}
|
||||
return point;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean p1Available() {
|
||||
return (device != null) && (device.isP1Available());
|
||||
}
|
||||
|
||||
public boolean getP1PowerState() throws P1ControlException {
|
||||
try {
|
||||
if (device == null) {
|
||||
throw new P1ControlException("P1 control is not initialized");
|
||||
}
|
||||
return device.getP1PowerState();
|
||||
} catch (SerialPortException | ResponseParseException ex) {
|
||||
throw new P1ControlException("Can't read P1 answer");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setP1PowerStateOn(boolean state) throws P1ControlException {
|
||||
try {
|
||||
if (device == null) {
|
||||
throw new P1ControlException("P1 control is not initialized");
|
||||
}
|
||||
return device.setP1PowerStateOn(state);
|
||||
} catch (SerialPortException | ResponseParseException ex) {
|
||||
throw new P1ControlException("Can't read P1 answer");
|
||||
}
|
||||
}
|
||||
|
||||
private TimerTask getTimerTask() {
|
||||
return new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// while (hasNextPoint()) {
|
||||
if (hasNextPoint()) {
|
||||
DataPoint point = readPoint();
|
||||
// На всякий случай берем время на секунду назад, чтобы не было накладок с пропусками
|
||||
// DataPoint point = skipUntil(Instant.now().minusSeconds(1));
|
||||
//Проверяем, что точка получена
|
||||
if (point != null) {
|
||||
//Если точка старая, то не обновляем ничего
|
||||
Instant pointTime = point.getValue("timestamp").timeValue();
|
||||
if (lastUpdate != null && pointTime.isAfter(lastUpdate)) {
|
||||
loader.push(point);
|
||||
if (frame != null) {
|
||||
frame.displayPoint(point);
|
||||
}
|
||||
}
|
||||
lastUpdate = pointTime;
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LoggerFactory.getLogger(VACManager.class).error("Unexpected error during point aquisition", ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config>
|
||||
<storage path="/home/numass-storage/"/>
|
||||
<serialconfig P1="/dev/ttyUSB0" P2="/dev/ttyS5" P3="/dev/ttyS4" Px="/dev/ttyUSB1"/>
|
||||
<run>12_2015.test</run>
|
||||
</config>
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.readvac;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class TestMain {
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
// File serverDir = new File("d:\\temp\\test\\remote\\");
|
||||
// NetworkListner listner = new NetworkListner(new FileDataServer(serverDir, null), null);
|
||||
// listner.start();
|
||||
// Annotation config = new XMLAnnotationParser().fromStream(null, TestMain.class.getResourceAsStream("testConfig.xml"));
|
||||
// Main.runConfig(config);
|
||||
//
|
||||
// Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
// try {
|
||||
// listner.close();
|
||||
// } catch (IOException ex) {
|
||||
// LoggerFactory.getLogger("test").error(null, ex);
|
||||
// }
|
||||
// }));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.readvac;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class TestRemote {
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
* @throws java.lang.Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Annotation config = new XMLAnnotationParser().fromStream(null, TestRemote.class.getResourceAsStream("testConfig.xml"));
|
||||
// Main.runConfig(config);
|
||||
// System.exit(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.readvac;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class TimeShiftTest {
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Instant now = Instant.now();
|
||||
System.out.println(now.toString());
|
||||
LocalDateTime ldt = LocalDateTime.now();
|
||||
System.out.println(ldt.toString());
|
||||
System.out.println(ldt.toInstant(ZoneOffset.ofHours(1)).toString());
|
||||
ZonedDateTime zdt = ZonedDateTime.now();
|
||||
System.out.println(zdt.toString());
|
||||
System.out.println(zdt.toInstant());
|
||||
|
||||
System.out.println(ZoneId.systemDefault().getRules().toString());
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
6
numass-control/vac/vac-config.xml
Normal file
6
numass-control/vac/vac-config.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config>
|
||||
<storage path="/home/numass-storage/"/>
|
||||
<serialconfig P1="/dev/ttyUSB0" P2="/dev/ttyS5" P3="/dev/ttyS4" Px="/dev/ttyUSB1"/>
|
||||
<run>12_2015</run>
|
||||
</config>
|
47
numass-main/build.gradle
Normal file
47
numass-main/build.gradle
Normal file
@ -0,0 +1,47 @@
|
||||
apply plugin: 'application'
|
||||
|
||||
if (!hasProperty('mainClass')) {
|
||||
ext.mainClass = 'inr.numass.Main'
|
||||
}
|
||||
mainClassName = mainClass
|
||||
|
||||
description = """The main head of all numass projects"""
|
||||
|
||||
ext{
|
||||
defaultNumassPath = 'D:\\loss-2011\\'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile group: 'commons-cli', name: 'commons-cli', version:'1.+'
|
||||
compile group: 'commons-io', name: 'commons-io', version:'2.+'
|
||||
compile project(':dataforge-fitting:dataforge-minuit')
|
||||
compile project(':dataforge-fx')
|
||||
compile project(':dataforge-grind')
|
||||
compile project(':dataforge-plots')
|
||||
}
|
||||
|
||||
task runNumass(dependsOn: classes, type : JavaExec){
|
||||
main mainClass
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
workingDir defaultNumassPath
|
||||
description "run Main method in the current numass working directory"
|
||||
group "numass"
|
||||
}
|
||||
|
||||
task debugNumass(dependsOn: classes, type: JavaExec) {
|
||||
main mainClass
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
workingDir defaultNumassPath
|
||||
ignoreExitValue = true
|
||||
debug = true
|
||||
description "debug Main method in the current numass working directory"
|
||||
group "numass"
|
||||
}
|
||||
|
||||
task listActions(dependsOn: classes, type: JavaExec) {
|
||||
main mainClass
|
||||
args "-lc"
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
description "print a list of available actions as via -lc command line parameter"
|
||||
group "numass"
|
||||
}
|
15
numass-main/gradle.properties
Normal file
15
numass-main/gradle.properties
Normal file
@ -0,0 +1,15 @@
|
||||
#
|
||||
# Copyright 2015 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.
|
||||
#
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts
|
||||
|
||||
import hep.dataforge.datafitter.ParamSet
|
||||
import hep.dataforge.io.FittingIOUtils
|
||||
import hep.dataforge.io.PrintFunction
|
||||
import hep.dataforge.maths.NamedDoubleArray
|
||||
import hep.dataforge.maths.NamedDoubleSet
|
||||
import hep.dataforge.maths.NamedMatrix
|
||||
import hep.dataforge.plots.PlotFrame
|
||||
import hep.dataforge.plots.data.PlottableFunction
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||
import inr.numass.actions.ShowLossSpectrumAction;
|
||||
import inr.numass.models.ExperimentalVariableLossSpectrum
|
||||
import inr.numass.models.LossCalculator
|
||||
import org.apache.commons.math3.analysis.UnivariateFunction
|
||||
|
||||
|
||||
NamedDoubleSet transformOldMeans(NamedDoubleSet old){
|
||||
String[] names = ["exPos", "ionPos", "exW", "ionW", "exIonRatio"];
|
||||
double[] values = new double[5];
|
||||
values[0] = old.getValue("loss_pos1");
|
||||
values[1] = old.getValue("loss_pos2");
|
||||
values[2] = old.getValue("loss_w1");
|
||||
values[3] = old.getValue("loss_w2");
|
||||
values[4] = old.getValue("loss_A1") / old.getValue("loss_A2");
|
||||
|
||||
return new NamedDoubleArray(names, values);
|
||||
|
||||
}
|
||||
|
||||
ParamSet transformOldParams(ParamSet old){
|
||||
String[] names = ["exPos", "ionPos", "exW", "ionW", "exIonRatio"];
|
||||
ParamSet res = new ParamSet(names);
|
||||
|
||||
res.setPar("exPos", old.getValue("loss_pos1"), old.getError("loss_pos1"));
|
||||
res.setPar("ionPos", old.getValue("loss_pos2"), old.getError("loss_pos2"));
|
||||
res.setPar("exW", old.getValue("loss_w1"), old.getError("loss_w1"));
|
||||
res.setPar("ionW", old.getValue("loss_w2"), old.getError("loss_w2"));
|
||||
|
||||
double ratioValue = old.getValue("loss_A1") / old.getValue("loss_A2");
|
||||
|
||||
double a1RelErr = old.getError("loss_A1") / old.getValue("loss_A1");
|
||||
double a2RelErr = old.getError("loss_A2") / old.getValue("loss_A2");
|
||||
double ratioErr = Math.sqrt(a1RelErr*a1RelErr + a2RelErr*a2RelErr)*ratioValue;
|
||||
res.setPar("exIonRatio", ratioValue, ratioErr);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
PrintWriter out = new PrintWriter(System.out);
|
||||
|
||||
String name = "log14_h2_new"
|
||||
//String name = "log18_long"
|
||||
//String name = "log25_long"
|
||||
|
||||
OldFitResultReader reader = new OldFitResultReader();
|
||||
reader.readFile(new File("C:\\Users\\darksnake\\Dropbox\\Numass\\Analysis\\loss-2014_november\\old_loss\\results\\final\\${name}.txt"));
|
||||
|
||||
double threshold = 17d;
|
||||
|
||||
ParamSet means = transformOldParams (reader.getParamSet());
|
||||
|
||||
double ionRatio = ShowLossSpectrumAction.calcultateIonRatio(means, threshold);
|
||||
NamedMatrix cov = NamedMatrix.diagonal(means.getParErrors());
|
||||
double ionRatioError = ShowLossSpectrumAction.calultateIonRatioError(name, means, cov, threshold);
|
||||
|
||||
println String.format("The ionization ratio (using threshold %f) is %f%n", threshold, ionRatio);
|
||||
println String.format("The ionization ratio standard deviation (using threshold %f) is %f%n", threshold, ionRatioError);
|
||||
println "*** FIT RESULT ***"
|
||||
|
||||
FittingIOUtils.printParamSet(out, means);
|
||||
|
||||
println means.toString();
|
||||
|
||||
UnivariateFunction scatterFunction = LossCalculator.getSingleScatterFunction(means);
|
||||
PlotFrame frame = JFreeChartFrame.drawFrame("Differential scattering crossection for "+name, null);
|
||||
frame.add(new PlottableFunction("Cross-section", null, scatterFunction, 0, 100, 1000));
|
||||
|
||||
PrintFunction.printFunctionSimple(out, scatterFunction, 0, 100, 500);
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts
|
||||
|
||||
|
||||
import hep.dataforge.datafitter.ParamSet
|
||||
import hep.dataforge.maths.integration.RiemanIntegrator
|
||||
import hep.dataforge.maths.integration.UnivariateIntegrator
|
||||
import hep.dataforge.plots.PlotFrame
|
||||
import hep.dataforge.plots.data.PlottableFunction
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||
import org.apache.commons.math3.analysis.UnivariateFunction
|
||||
import org.apache.commons.math3.analysis.solvers.BisectionSolver
|
||||
import inr.numass.models.LossCalculator
|
||||
import inr.numass.models.ResolutionFunction
|
||||
import inr.numass.NumassContext
|
||||
|
||||
|
||||
|
||||
ParamSet params = new ParamSet()
|
||||
.setParValue("exPos", 12.76)
|
||||
.setParValue("ionPos", 13.95)
|
||||
.setParValue("exW", 1.2)
|
||||
.setParValue("ionW", 13.5)
|
||||
.setParValue("exIonRatio", 4.55)
|
||||
|
||||
|
||||
|
||||
|
||||
UnivariateFunction scatterFunction = LossCalculator.getSingleScatterFunction(params);
|
||||
|
||||
PlotFrame frame = JFreeChartFrame.drawFrame("Differential scatter function", null);
|
||||
frame.add(new PlottableFunction("differential", null, scatterFunction, 0, 100, 400));
|
||||
|
||||
UnivariateIntegrator integrator = NumassContext.defaultIntegrator;
|
||||
|
||||
double border = 13.6;
|
||||
|
||||
UnivariateFunction ratioFunction = {e->integrator.integrate(scatterFunction, 0 , e) / integrator.integrate(scatterFunction, e, 100)}
|
||||
|
||||
double ratio = ratioFunction.value(border);
|
||||
println "The true excitation to ionization ratio with border energy $border is $ratio";
|
||||
|
||||
|
||||
double resolution = 1.5d;
|
||||
|
||||
|
||||
def X = 0.527;
|
||||
|
||||
LossCalculator calculator = new LossCalculator();
|
||||
|
||||
List<Double> lossProbs = calculator.getGunLossProbabilities(X);
|
||||
|
||||
UnivariateFunction newScatterFunction = { double d ->
|
||||
double res = scatterFunction.value(d);
|
||||
for(i = 1; i < lossProbs.size(); i++){
|
||||
res += lossProbs.get(i) * calculator.getLossValue(i, d, 0);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
UnivariateFunction resolutionValue = {double e ->
|
||||
if (e <= 0d) {
|
||||
return 0d;
|
||||
} else if (e >= resolution) {
|
||||
return 1d;
|
||||
} else {
|
||||
return e/resolution;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
UnivariateFunction integral = {double u ->
|
||||
if(u <= 0d){
|
||||
return 0d;
|
||||
} else {
|
||||
UnivariateFunction integrand = {double e -> resolutionValue.value(u-e) * newScatterFunction.value(e)};
|
||||
return integrator.integrate(integrand, 0d, u)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
frame.add(new PlottableFunction("integral", null, integral, 0, 100, 800));
|
||||
|
||||
BisectionSolver solver = new BisectionSolver(1e-3);
|
||||
|
||||
UnivariateFunction integralShifted = {u ->
|
||||
def integr = integral.value(u);
|
||||
return integr/(1-integr) - ratio;
|
||||
}
|
||||
|
||||
double integralBorder = solver.solve(400, integralShifted, 10d, 20d);
|
||||
|
||||
println "The integral border is $integralBorder";
|
||||
|
||||
double newBorder = 14.43
|
||||
double integralValue = integral.value(newBorder);
|
||||
|
||||
double err = Math.abs(integralValue/(1-integralValue)/ratio - 1d)
|
||||
|
||||
println "The relative error ic case of using $newBorder instead of real one is $err";
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts
|
||||
|
||||
inr.numass.context.Main.main("-lc")
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts
|
||||
|
||||
import hep.dataforge.actions.Pack
|
||||
import hep.dataforge.datafitter.FitTaskResult
|
||||
import inr.numass.Main
|
||||
import inr.numass.NumassContext
|
||||
|
||||
|
||||
//Main.main("-lc")
|
||||
NumassContext context = new NumassContext();
|
||||
context.putValue("integralThreshold", 15d);
|
||||
Pack resultPack = Main.run(context, "-c","D:\\sterile-new\\loss2014-11\\d2_19_1.xml")
|
||||
FitTaskResult result = resultPack.getData().value()
|
||||
result.print(new PrintWriter(System.out))
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 inr.numass.scripts
|
||||
|
||||
import hep.dataforge.maths.integration.GaussRuleIntegrator;
|
||||
import hep.dataforge.maths.integration.UnivariateIntegrator;
|
||||
import inr.numass.models.LossCalculator;
|
||||
import org.apache.commons.math3.analysis.UnivariateFunction
|
||||
|
||||
UnivariateIntegrator integrator = new GaussRuleIntegrator(400);
|
||||
def exPos = 12.878;
|
||||
def ionPos = 13.86;
|
||||
def exW = 1.32;
|
||||
def ionW = 12.47;
|
||||
def exIonRatio = 3.96;
|
||||
|
||||
def cutoff = 25d
|
||||
|
||||
UnivariateFunction loss = LossCalculator.getSingleScatterFunction(exPos, ionPos, exW, ionW, exIonRatio);
|
||||
|
||||
|
||||
println integrator.integrate(loss,0,600);
|
||||
println integrator.integrate(loss,0,cutoff);
|
||||
println integrator.integrate(loss,cutoff,600d);
|
||||
|
||||
println (integrator.integrate(loss,0,cutoff) + integrator.integrate(loss,cutoff,3000d));
|
||||
//double tailValue = (Math.atan((ionPos-cutoff)*2d/ionW) + 0.5*Math.PI)*ionW/2;
|
||||
//println tailValue
|
||||
//println integrator.integrate(loss,0,100);
|
||||
//println integrator.integrate(loss,100,600);
|
||||
|
||||
//def lorentz = {eps->
|
||||
// double z = 4 * (eps - ionPos) * (eps - ionPos);
|
||||
// 1 / (1 + z / ionW / ionW);
|
||||
//}
|
||||
//
|
||||
//println(integrator.integrate(lorentz, cutoff, 800))
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts
|
||||
|
||||
import hep.dataforge.datafitter.ParamSet
|
||||
import hep.dataforge.maths.NamedDoubleArray
|
||||
import hep.dataforge.maths.NamedDoubleSet
|
||||
import hep.dataforge.maths.NamedMatrix
|
||||
import java.util.regex.Pattern
|
||||
import org.apache.commons.math3.linear.Array2DRowRealMatrix
|
||||
import org.apache.commons.math3.linear.RealMatrix
|
||||
import java.util.Scanner
|
||||
import java.util.regex.Matcher
|
||||
|
||||
/**
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
class OldFitResultReader {
|
||||
private static Pattern meanPattern = ~/\"(?<name>.*)\"\s*:\s*(?<value>[\d.]*)\s*/;
|
||||
|
||||
private NamedDoubleSet means;
|
||||
private RealMatrix covariance;
|
||||
|
||||
void readMeans(String input){
|
||||
Scanner scan = new Scanner(input);
|
||||
List<String> names = new ArrayList<>();
|
||||
List<Double> values = new ArrayList<>();
|
||||
while(scan.hasNextLine()){
|
||||
String nextLine = scan.nextLine();
|
||||
if(!nextLine.isEmpty()){
|
||||
Matcher match = meanPattern.matcher(nextLine);
|
||||
match.matches();
|
||||
names << match.group("name");
|
||||
values << Double.parseDouble(match.group("value"));
|
||||
}
|
||||
}
|
||||
this.means = new NamedDoubleArray(names.toArray(new String[names.size()]), values.toArray(new double[values.size()]));
|
||||
}
|
||||
|
||||
void readCovariance(String input){
|
||||
Scanner scan = new Scanner(input);
|
||||
List<List<Double>> matrix = new ArrayList<>();
|
||||
while(scan.hasNextLine()){
|
||||
String nextLine = scan.nextLine();
|
||||
if(!nextLine.isEmpty()){
|
||||
Scanner lineScan = new Scanner(nextLine);
|
||||
List<Double> line = new ArrayList<>();
|
||||
while(lineScan.hasNextDouble()){
|
||||
line << lineScan.nextDouble();
|
||||
}
|
||||
matrix << line;
|
||||
}
|
||||
}
|
||||
|
||||
Array2DRowRealMatrix result = new Array2DRowRealMatrix(matrix.size(),matrix.size());
|
||||
for(int i = 0; i< matrix.size; i++){
|
||||
List<Double> line = matrix.get(i);
|
||||
for(int j = 0; j< matrix.size; j++){
|
||||
result.setEntry(i,j,line[j]);
|
||||
}
|
||||
}
|
||||
this.covariance = result;
|
||||
}
|
||||
|
||||
void readFile(File file){
|
||||
String text = file.getText();
|
||||
Pattern pattern = Pattern.compile(/.*The best fit values are:\s*(?<parameters>.*)Covariation marix:\s*(?<covariance>.*)Best Likelihood logarithm/, Pattern.DOTALL);
|
||||
List results = text.findAll(pattern);
|
||||
|
||||
String res = results.get(results.size()-1);
|
||||
Matcher match = pattern.matcher(res);
|
||||
match.matches();
|
||||
readMeans(match.group("parameters"));
|
||||
readCovariance(match.group("covariance"));
|
||||
}
|
||||
|
||||
|
||||
NamedDoubleSet getMeans(){
|
||||
return means;
|
||||
}
|
||||
|
||||
ParamSet getParamSet(){
|
||||
ParamSet res = new ParamSet();
|
||||
NamedMatrix cov = getCovariance();
|
||||
for(String name: means.names()){
|
||||
res.setPar(name, means.getValue(name), Math.sqrt(Math.abs(cov.getElement(name, name))));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
NamedMatrix getCovariance(){
|
||||
return new NamedMatrix(covariance, means.namesAsArray());
|
||||
}
|
||||
|
||||
}
|
||||
|
112
numass-main/src/main/groovy/inr/numass/scripts/OldTest.groovy
Normal file
112
numass-main/src/main/groovy/inr/numass/scripts/OldTest.groovy
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts;
|
||||
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.datafitter.FitManager;
|
||||
import hep.dataforge.datafitter.FitState;
|
||||
import hep.dataforge.datafitter.MINUITPlugin
|
||||
|
||||
import hep.dataforge.datafitter.ParamSet;
|
||||
import hep.dataforge.datafitter.models.XYModel;
|
||||
import hep.dataforge.likelihood.BayesianManager
|
||||
import inr.numass.data.SpectrumDataAdapter
|
||||
import inr.numass.models.BetaSpectrum;
|
||||
import inr.numass.models.ModularSpectrum;
|
||||
import inr.numass.models.ModularTritiumSpectrum
|
||||
import inr.numass.models.NBkgSpectrum;
|
||||
import inr.numass.models.RangedNamedSetSpectrum;
|
||||
import inr.numass.models.ResolutionFunction
|
||||
import static inr.numass.utils.OldDataReader.readData;
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Locale;
|
||||
import org.apache.commons.math3.analysis.BivariateFunction
|
||||
import inr.numass.models.ResolutionFunction
|
||||
|
||||
|
||||
PrintWriter out = GlobalContext.out();
|
||||
Locale.setDefault(Locale.US);
|
||||
|
||||
new MINUITPlugin().startGlobal();
|
||||
|
||||
FitManager fm = new FitManager();
|
||||
|
||||
// setSeed(543982);
|
||||
File fssfile = new File("c:\\Users\\Darksnake\\Dropbox\\PlayGround\\FS.txt");
|
||||
|
||||
BivariateFunction resolution = new ResolutionFunction(2.28e-4);
|
||||
resolution.setTailFunction(ResolutionFunction.getRealTail())
|
||||
|
||||
ModularTritiumSpectrum sp = new ModularTritiumSpectrum(resolution, 18395d, 18580d, fssfile);
|
||||
sp.setCaching(false);
|
||||
//RangedNamedSetSpectrum beta = new BetaSpectrum(fssfile);
|
||||
//ModularSpectrum sp = new ModularSpectrum(beta, 2.28e-4, 18395d, 18580d);
|
||||
|
||||
// ModularTritiumSpectrum beta = new ModularTritiumSpectrum(2.28e-4, 18395d, 18580d, "d:\\PlayGround\\FS.txt");
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(sp);
|
||||
XYModel model = new XYModel("tritium", spectrum, new SpectrumDataAdapter());
|
||||
|
||||
ParamSet allPars = new ParamSet();
|
||||
|
||||
allPars.setParValue("N", 602533.94);
|
||||
//значение 6е-6 соответствует полной интенстивности 6е7 распадов в секунду
|
||||
//Проблема была в переполнении счетчика событий в генераторе. Заменил на long. Возможно стоит поставить туда число с плавающей точкой
|
||||
allPars.setParError("N", 1000);
|
||||
allPars.setParDomain("N", 0d, Double.POSITIVE_INFINITY);
|
||||
allPars.setParValue("bkg", 0.012497889);
|
||||
allPars.setParError("bkg", 1e-4);
|
||||
allPars.setParValue("E0", 18575.986);
|
||||
allPars.setParError("E0", 0.05);
|
||||
allPars.setParValue("mnu2", 0d);
|
||||
allPars.setParError("mnu2", 1d);
|
||||
allPars.setParValue("msterile2", 50 * 50);
|
||||
allPars.setParValue("U2", 0);
|
||||
allPars.setParError("U2", 1e-2);
|
||||
allPars.setParDomain("U2", -1d, 1d);
|
||||
allPars.setParValue("X", 0.47);
|
||||
allPars.setParError("X", 0.014);
|
||||
allPars.setParDomain("X", 0d, Double.POSITIVE_INFINITY);
|
||||
allPars.setParValue("trap", 1d);
|
||||
allPars.setParError("trap", 0.2d);
|
||||
allPars.setParDomain("trap", 0d, Double.POSITIVE_INFINITY);
|
||||
|
||||
ListDataSet data = readData("c:\\Users\\Darksnake\\Dropbox\\PlayGround\\RUN23.DAT", 18400d);
|
||||
|
||||
FitState state = fm.buildState(data, model, allPars);
|
||||
|
||||
FitState res = fm.runDefaultTask(state, "E0", "N", "bkg");
|
||||
|
||||
res = fm.runDefaultTask(res, "E0", "N", "bkg", "U2");
|
||||
|
||||
res.print(out);
|
||||
|
||||
//spectrum.counter.print(out);
|
||||
//
|
||||
//// fm.setPriorProb(new GaussianPrior("X", 0.47, 0.47*0.03));
|
||||
//// fm.setPriorProb(new MultivariateGaussianPrior(allPars.getSubSet("X","trap")));
|
||||
//res = fm.runTask(res, "MINUIT", "run", "E0", "N", "bkg", "mnu2");
|
||||
////
|
||||
//res.print(out);
|
||||
|
||||
//sp.setCaching(true);
|
||||
//sp.setSuppressWarnings(true);
|
||||
//
|
||||
//BayesianManager bm = new BayesianManager();
|
||||
//bm.printMarginalLikelihood(out, "U2", res, ["E0", "N", "bkg", "U2", "X"], 10000);
|
||||
|
||||
// PrintNamed.printLike2D(Out.out, "like", res, "N", "E0", 30, 60, 2);
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts;
|
||||
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A basic plot viewer for serialized JFreeChart plots
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class PlotViewer {
|
||||
|
||||
/**
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
if (args.length > 0) {
|
||||
for (String arg : args) {
|
||||
File ser = new File(arg);
|
||||
try {
|
||||
FileInputStream stream = new FileInputStream(ser);
|
||||
ObjectInputStream ostr = new ObjectInputStream(stream);
|
||||
JFreeChartFrame.deserialize(ostr);
|
||||
} catch (IOException ex) {
|
||||
LoggerFactory.getLogger(PlotViewer.class).error("IO error during deserialization", ex);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
LoggerFactory.getLogger(PlotViewer.class).error("Wrong serialized content type", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 inr.numass.scripts
|
||||
|
||||
import inr.numass.models.LossCalculator
|
||||
|
||||
LossCalculator loss = new LossCalculator();
|
||||
|
||||
def X = 0.6
|
||||
|
||||
def lossProbs = loss.getGunLossProbabilities(X);
|
||||
|
||||
printf("%8s\t%8s\t%8s\t%8s\t%n",
|
||||
"eps",
|
||||
"p1",
|
||||
"p2",
|
||||
"p3"
|
||||
)
|
||||
|
||||
def singleScatter = loss.getSingleScatterFunction();
|
||||
|
||||
for(double d = 0; d < 30; d += 0.3){
|
||||
double ei = 18500;
|
||||
double ef = ei-d;
|
||||
printf("%8f\t%8f\t%8f\t%8f\t%n",
|
||||
d,
|
||||
lossProbs[1]*loss.getLossValue(1,ei,ef),
|
||||
lossProbs[2]*loss.getLossValue(2,ei,ef),
|
||||
lossProbs[3]*loss.getLossValue(3,ei,ef)
|
||||
)
|
||||
}
|
||||
|
||||
for(double d = 30; d < 100; d += 1){
|
||||
double ei = 18500;
|
||||
double ef = ei-d;
|
||||
printf("%8f\t%8f\t%8f\t%8f\t%n",
|
||||
d,
|
||||
lossProbs[1]*loss.getLossValue(1,ei,ef),
|
||||
lossProbs[2]*loss.getLossValue(2,ei,ef),
|
||||
lossProbs[3]*loss.getLossValue(3,ei,ef)
|
||||
)
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts;
|
||||
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import static hep.dataforge.context.GlobalContext.out;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.datafitter.FitManager;
|
||||
import hep.dataforge.datafitter.FitState;
|
||||
import hep.dataforge.datafitter.FitTask;
|
||||
import hep.dataforge.datafitter.ParamSet;
|
||||
import hep.dataforge.datafitter.models.XYModel;
|
||||
import hep.dataforge.exceptions.NamingException;
|
||||
import inr.numass.data.SpectrumDataAdapter;
|
||||
import inr.numass.data.SpectrumGenerator;
|
||||
import inr.numass.models.ModularTritiumSpectrum;
|
||||
import inr.numass.models.NBkgSpectrum;
|
||||
import inr.numass.utils.DataModelUtils;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Locale;
|
||||
import static java.util.Locale.setDefault;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
|
||||
setDefault(Locale.US);
|
||||
GlobalContext global = GlobalContext.instance();
|
||||
// global.loadModule(new MINUITModule());
|
||||
|
||||
FitManager fm = new FitManager();
|
||||
|
||||
ModularTritiumSpectrum beta = new ModularTritiumSpectrum(9e-5, 14390d, 19001d, null);
|
||||
beta.setCaching(false);
|
||||
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(beta);
|
||||
XYModel model = new XYModel("tritium", spectrum, new SpectrumDataAdapter());
|
||||
|
||||
ParamSet allPars = new ParamSet();
|
||||
|
||||
allPars.setParValue("N", 3e5);
|
||||
//значение 6е-6 соответствует полной интенстивности 6е7 распадов в секунду
|
||||
//Проблема была в переполнении счетчика событий в генераторе. Заменил на long. Возможно стоит поставить туда число с плавающей точкой
|
||||
allPars.setParError("N", 6);
|
||||
allPars.setParDomain("N", 0d, Double.POSITIVE_INFINITY);
|
||||
allPars.setParValue("bkg", 2d);
|
||||
allPars.setParError("bkg", 0.03);
|
||||
allPars.setParValue("E0", 18575.0);
|
||||
allPars.setParError("E0", 2);
|
||||
allPars.setParValue("mnu2", 0d);
|
||||
allPars.setParError("mnu2", 1d);
|
||||
allPars.setParValue("msterile2", 1000 * 1000);
|
||||
allPars.setParValue("U2", 0);
|
||||
allPars.setParError("U2", 1e-4);
|
||||
allPars.setParDomain("U2", -1d, 1d);
|
||||
allPars.setParValue("X", 0);
|
||||
allPars.setParError("X", 0.01);
|
||||
allPars.setParDomain("X", 0d, Double.POSITIVE_INFINITY);
|
||||
allPars.setParValue("trap", 0);
|
||||
allPars.setParError("trap", 0.01d);
|
||||
allPars.setParDomain("trap", 0d, Double.POSITIVE_INFINITY);
|
||||
|
||||
// PrintNamed.printSpectrum(GlobalContext.out(), spectrum, allPars, 0.0, 18700.0, 600);
|
||||
//String fileName = "d:\\PlayGround\\merge\\scans.out";
|
||||
// String configName = "d:\\PlayGround\\SCAN.CFG";
|
||||
// ListDataSet config = OldDataReader.readConfig(configName);
|
||||
SpectrumGenerator generator = new SpectrumGenerator(model, allPars, 12316);
|
||||
|
||||
ListDataSet data = generator.generateData(DataModelUtils.getUniformSpectrumConfiguration(13500d, 18200, 1e6, 60));
|
||||
|
||||
// data = data.filter("X", Value.of(15510.0), Value.of(18610.0));
|
||||
// allPars.setParValue("X", 0.4);
|
||||
FitState state = fm.buildState(data, model, allPars);
|
||||
|
||||
FitState res = fm.runTask(state, "QOW", FitTask.TASK_RUN, "N", "bkg", "E0", "U2");
|
||||
|
||||
res.print(out());
|
||||
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts
|
||||
|
||||
import static groovy.io.FileType.*
|
||||
import org.apache.commons.io.FilenameUtils
|
||||
|
||||
|
||||
File dir = new File("D:\\loss-2014\\");
|
||||
File resultDir = new File(dir, ".dataforge\\showLoss\\");
|
||||
if(!resultDir.exists()){
|
||||
resultDir.mkdirs()
|
||||
}
|
||||
|
||||
File resultFile = new File(resultDir,"summary");
|
||||
|
||||
|
||||
resultFile.setText("name\tX\tX_err\texPos\texPos_err\tionPos\tionPos_err\texW\texW_err\tionW\tionW_err\texIonRatio\texIonRatio_err\tionRatio\tionRatioErr\tchi\r\n");
|
||||
|
||||
dir.eachFileMatch FILES, {it ==~ /[dh]2_\d\d_\d(?:_bkg)?\.xml/}, {
|
||||
try{
|
||||
inr.numass.Main.main("-c", it.getAbsolutePath())
|
||||
File outFile = new File(resultDir, FilenameUtils.getBaseName(it.getName())+"_loss.out")
|
||||
resultFile.append(outFile.readLines().get(50));
|
||||
resultFile.append("\r\n");
|
||||
} catch(Exception ex){
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts;
|
||||
|
||||
import hep.dataforge.meta.MetaBuilder;
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import hep.dataforge.datafitter.ParamSet;
|
||||
import inr.numass.data.SpectrumInformation;
|
||||
import inr.numass.models.ModularTritiumSpectrum;
|
||||
import inr.numass.models.NBkgSpectrum;
|
||||
import inr.numass.models.ResolutionFunction;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import static java.util.Locale.setDefault;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.math3.analysis.UnivariateFunction;
|
||||
|
||||
|
||||
setDefault(Locale.US);
|
||||
GlobalContext global = GlobalContext.instance();
|
||||
// global.loadModule(new MINUIT());
|
||||
|
||||
// FitManager fm = new FitManager("data 2013");
|
||||
UnivariateFunction reolutionTail = {x ->
|
||||
if (x > 1500) {
|
||||
return 0.98;
|
||||
} else //Intercept = 1.00051, Slope = -1.3552E-5
|
||||
{
|
||||
return 1.00051 - 1.3552E-5 * x;
|
||||
}
|
||||
};
|
||||
|
||||
ModularTritiumSpectrum beta = new ModularTritiumSpectrum(
|
||||
new ResolutionFunction(8.3e-5, reolutionTail), 14490d, 19001d, null);
|
||||
beta.setCaching(false);
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(beta);
|
||||
|
||||
// XYModel model = new XYModel("tritium", spectrum);
|
||||
ParamSet allPars = new ParamSet();
|
||||
|
||||
allPars.setParValue("N", 3090.1458);
|
||||
//значение 6е-6 соответствует полной интенстивности 6е7 распадов в секунду
|
||||
//Проблема была в переполнении счетчика событий в генераторе. Заменил на long. Возможно стоит поставить туда число с плавающей точкой
|
||||
allPars.setParError("N", 6);
|
||||
allPars.setParDomain("N", 0d, Double.POSITIVE_INFINITY);
|
||||
allPars.setParValue("bkg", 2.2110028);
|
||||
allPars.setParError("bkg", 0.03);
|
||||
allPars.setParValue("E0", 18580.742);
|
||||
allPars.setParError("E0", 2);
|
||||
allPars.setParValue("mnu2", 0d);
|
||||
allPars.setParError("mnu2", 1d);
|
||||
allPars.setParValue("msterile2", 1000 * 1000);
|
||||
allPars.setParValue("U2", 0);
|
||||
allPars.setParError("U2", 1e-4);
|
||||
allPars.setParDomain("U2", -1d, 1d);
|
||||
allPars.setParValue("X", 1.0);
|
||||
allPars.setParError("X", 0.01);
|
||||
allPars.setParDomain("X", 0d, Double.POSITIVE_INFINITY);
|
||||
allPars.setParValue("trap", 1.0d);
|
||||
allPars.setParError("trap", 0.01d);
|
||||
allPars.setParDomain("trap", 0d, Double.POSITIVE_INFINITY);
|
||||
|
||||
SpectrumInformation sign = new SpectrumInformation(spectrum);
|
||||
|
||||
// double Elow = 14000d;
|
||||
// double Eup = 18600d;
|
||||
// int numpoints = (int) ((Eup - Elow) / 50);
|
||||
// double time = 1e6 / numpoints;
|
||||
// DataSet config = getUniformSpectrumConfiguration(Elow, Eup, time, numpoints);
|
||||
// NamedMatrix infoMatrix = sign.getInformationMatrix(allPars, config,"U2","E0","N");
|
||||
//
|
||||
// PrintNamed.printNamedMatrix(Out.out, infoMatrix);
|
||||
// NamedMatrix cov = sign.getExpetedCovariance(allPars, config,"U2","E0","N");
|
||||
//
|
||||
// PrintWriter out = GlobalContext.out();
|
||||
//
|
||||
// printNamedMatrix(out, cov);
|
||||
//
|
||||
// cov = sign.getExpetedCovariance(allPars, config,"U2","E0","N","X");
|
||||
//
|
||||
// printNamedMatrix(out, cov);
|
||||
//PlotManager pm = new PlotManager();
|
||||
|
||||
Map<String, UnivariateFunction> functions = new HashMap<>();
|
||||
|
||||
functions.put("U2", sign.getSignificanceFunction(allPars, "U2", "U2"));
|
||||
// functions.put("UX", sign.getSignificanceFunction(allPars, "U2", "X"));
|
||||
functions.put("X", sign.getSignificanceFunction(allPars, "X", "X"));
|
||||
functions.put("trap", sign.getSignificanceFunction(allPars, "trap", "trap"));
|
||||
functions.put("E0", sign.getSignificanceFunction(allPars, "E0", "E0"));
|
||||
|
||||
MetaBuilder builder = new MetaBuilder("significance");
|
||||
builder.putValue("from", 14000d);
|
||||
builder.putValue("to", 18500d);
|
||||
|
||||
pm.plotFunction(builder.build(), functions);
|
||||
|
||||
// printFuntionSimple(out(), func, 14000d, 18600d, 200);
|
||||
|
100
numass-main/src/main/groovy/inr/numass/scripts/Simulate.groovy
Normal file
100
numass-main/src/main/groovy/inr/numass/scripts/Simulate.groovy
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts;
|
||||
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import static hep.dataforge.context.GlobalContext.out;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.datafitter.FitManager;
|
||||
import hep.dataforge.datafitter.FitState;
|
||||
import hep.dataforge.datafitter.FitTask;
|
||||
import hep.dataforge.datafitter.MINUITPlugin
|
||||
|
||||
import hep.dataforge.datafitter.ParamSet;
|
||||
import hep.dataforge.datafitter.models.XYModel;
|
||||
import hep.dataforge.exceptions.NamingException;
|
||||
import hep.dataforge.exceptions.PackFormatException;
|
||||
import inr.numass.data.SpectrumDataAdapter;
|
||||
import inr.numass.data.SpectrumGenerator;
|
||||
import inr.numass.models.ModularTritiumSpectrum;
|
||||
import inr.numass.models.NBkgSpectrum;
|
||||
import inr.numass.utils.DataModelUtils;
|
||||
import hep.dataforge.plotfit.PlotFitResultAction;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Locale;
|
||||
import static java.util.Locale.setDefault;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
|
||||
setDefault(Locale.US);
|
||||
new MINUITPlugin().startGlobal();
|
||||
// global.loadModule(new MINUITModule());
|
||||
|
||||
FitManager fm = new FitManager();
|
||||
|
||||
ModularTritiumSpectrum beta = new ModularTritiumSpectrum(8.3e-5, 14390d, 19001d, null);
|
||||
beta.setCaching(false);
|
||||
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(beta);
|
||||
XYModel model = new XYModel("tritium", spectrum, new SpectrumDataAdapter());
|
||||
|
||||
ParamSet allPars = new ParamSet();
|
||||
|
||||
allPars.setParValue("N", 3e5);
|
||||
//значение 6е-6 соответствует полной интенстивности 6е7 распадов в секунду
|
||||
//Проблема была в переполнении счетчика событий в генераторе. Заменил на long. Возможно стоит поставить туда число с плавающей точкой
|
||||
allPars.setParError("N", 6);
|
||||
allPars.setParDomain("N", 0d, Double.POSITIVE_INFINITY);
|
||||
allPars.setParValue("bkg", 2d);
|
||||
allPars.setParError("bkg", 0.03);
|
||||
allPars.setParValue("E0", 18575.0);
|
||||
allPars.setParError("E0", 2);
|
||||
allPars.setParValue("mnu2", 0d);
|
||||
allPars.setParError("mnu2", 1d);
|
||||
allPars.setParValue("msterile2", 1000 * 1000);
|
||||
allPars.setParValue("U2", 0);
|
||||
allPars.setParError("U2", 1e-4);
|
||||
allPars.setParDomain("U2", -1d, 1d);
|
||||
allPars.setParValue("X", 0);
|
||||
allPars.setParError("X", 0.01);
|
||||
allPars.setParDomain("X", 0d, Double.POSITIVE_INFINITY);
|
||||
allPars.setParValue("trap", 0);
|
||||
allPars.setParError("trap", 0.01d);
|
||||
allPars.setParDomain("trap", 0d, Double.POSITIVE_INFINITY);
|
||||
|
||||
// PrintNamed.printSpectrum(GlobalContext.out(), spectrum, allPars, 0.0, 18700.0, 600);
|
||||
//String fileName = "d:\\PlayGround\\merge\\scans.out";
|
||||
// String configName = "d:\\PlayGround\\SCAN.CFG";
|
||||
// ListDataSet config = OldDataReader.readConfig(configName);
|
||||
SpectrumGenerator generator = new SpectrumGenerator(model, allPars, 12316);
|
||||
|
||||
ListDataSet data = generator.generateData(DataModelUtils.getUniformSpectrumConfiguration(13500d, 18200, 1e6, 60));
|
||||
|
||||
// data = data.filter("X", Value.of(15510.0), Value.of(18610.0));
|
||||
// allPars.setParValue("X", 0.4);
|
||||
FitState state = FitManager.buildState(data, model, allPars);
|
||||
new PlotFitResultAction(GlobalContext.instance(), null).runOne(state);
|
||||
|
||||
|
||||
FitState res = fm.runTask(state, "QOW", FitTask.TASK_RUN, "N", "bkg", "E0", "U2");
|
||||
|
||||
|
||||
|
||||
res.print(out());
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts;
|
||||
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import hep.dataforge.datafitter.FitManager;
|
||||
import hep.dataforge.datafitter.ParamSet;
|
||||
import hep.dataforge.datafitter.models.XYModel;
|
||||
import hep.dataforge.exceptions.NamingException;
|
||||
import hep.dataforge.io.PrintNamed;
|
||||
import inr.numass.data.SpectrumDataAdapter;
|
||||
import inr.numass.models.GunSpectrum;
|
||||
import inr.numass.models.NBkgSpectrum;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Locale;
|
||||
import static java.util.Locale.setDefault;
|
||||
|
||||
|
||||
setDefault(Locale.US);
|
||||
GlobalContext global = GlobalContext.instance();
|
||||
// global.loadModule(new MINUITModule());
|
||||
|
||||
FitManager fm = new FitManager();
|
||||
|
||||
GunSpectrum gsp = new GunSpectrum();
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(gsp);
|
||||
|
||||
XYModel model = new XYModel("gun", spectrum, new SpectrumDataAdapter());
|
||||
|
||||
ParamSet allPars = new ParamSet()
|
||||
.setPar("N", 1e3, 1e2)
|
||||
.setPar("pos", 18500, 0.1)
|
||||
.setPar("bkg", 50, 1)
|
||||
.setPar("resA", 5.3e-5, 1e-5)
|
||||
.setPar("sigma", 0.3, 0.03);
|
||||
|
||||
PrintNamed.printSpectrum(new PrintWriter(System.out), spectrum, allPars, 18495, 18505, 100);
|
||||
|
||||
allPars.setParValue("sigma", 0.6);
|
||||
|
||||
PrintNamed.printSpectrum(new PrintWriter(System.out), spectrum, allPars, 18495, 18505, 100);
|
||||
|
||||
// //String fileName = "d:\\PlayGround\\merge\\scans.out";
|
||||
//// String configName = "d:\\PlayGround\\SCAN.CFG";
|
||||
//// ListDataSet config = OldDataReader.readConfig(configName);
|
||||
// SpectrumGenerator generator = new SpectrumGenerator(model, allPars, 12316);
|
||||
//
|
||||
// ListDataSet data = generator.generateData(DataModelUtils.getUniformSpectrumConfiguration(18495, 18505, 20, 20));
|
||||
//
|
||||
//// data = data.filter("X", Value.of(15510.0), Value.of(18610.0));
|
||||
//// allPars.setParValue("X", 0.4);
|
||||
// FitState state = FitTaskManager.buildState(data, model, allPars);
|
||||
//
|
||||
// FitState res = fm.runTask(state, "QOW", FitTask.TASK_RUN, "N", "bkg", "pos", "sigma");
|
||||
//
|
||||
// res.print(out());
|
||||
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts;
|
||||
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import static hep.dataforge.context.GlobalContext.out;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.datafitter.FitManager;
|
||||
import hep.dataforge.datafitter.FitState;
|
||||
import hep.dataforge.datafitter.FitTask;
|
||||
import hep.dataforge.datafitter.MINUITPlugin
|
||||
|
||||
import hep.dataforge.datafitter.ParamSet;
|
||||
import hep.dataforge.datafitter.models.XYModel;
|
||||
import hep.dataforge.exceptions.NamingException;
|
||||
import hep.dataforge.exceptions.PackFormatException;
|
||||
import inr.numass.data.SpectrumDataAdapter;
|
||||
import inr.numass.data.SpectrumGenerator;
|
||||
import inr.numass.models.ModularTritiumSpectrum;
|
||||
import inr.numass.models.NBkgSpectrum;
|
||||
import inr.numass.models.ResolutionFunction
|
||||
import inr.numass.utils.DataModelUtils;
|
||||
import hep.dataforge.plotfit.PlotFitResultAction;
|
||||
import hep.dataforge.plots.PlotFrame
|
||||
import hep.dataforge.plots.data.PlottableFunction
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Locale;
|
||||
import org.apache.commons.math3.analysis.BivariateFunction
|
||||
|
||||
import static java.util.Locale.setDefault;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
|
||||
setDefault(Locale.US);
|
||||
new MINUITPlugin().startGlobal();
|
||||
|
||||
FitManager fm = new FitManager();
|
||||
|
||||
BivariateFunction resolution = new ResolutionFunction(8.3e-5);
|
||||
|
||||
ModularTritiumSpectrum beta = new ModularTritiumSpectrum(resolution, 13490d, 18575d, null);
|
||||
beta.setCaching(false);
|
||||
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(beta);
|
||||
XYModel model = new XYModel("tritium", spectrum, new SpectrumDataAdapter());
|
||||
|
||||
ParamSet allPars = new ParamSet();
|
||||
|
||||
|
||||
allPars.setPar("N", 6e5, 10, 0, Double.POSITIVE_INFINITY);
|
||||
|
||||
allPars.setPar("bkg", 2d, 0.1 );
|
||||
|
||||
allPars.setPar("E0", 18575.0, 0.05 );
|
||||
|
||||
allPars.setPar("mnu2", 0, 1);
|
||||
|
||||
def mster = 3000;// Mass of sterile neutrino in eV
|
||||
|
||||
allPars.setPar("msterile2", mster**2, 1);
|
||||
|
||||
allPars.setPar("U2", 0, 1e-4);
|
||||
|
||||
allPars.setPar("X", 0, 0.05, 0d, Double.POSITIVE_INFINITY);
|
||||
|
||||
allPars.setPar("trap", 0, 0.01, 0d, Double.POSITIVE_INFINITY);
|
||||
|
||||
SpectrumGenerator generator = new SpectrumGenerator(model, allPars, 12316);
|
||||
|
||||
ListDataSet data = generator.generateData(DataModelUtils.getUniformSpectrumConfiguration(14000d, 18200, 1e6, 60));
|
||||
|
||||
// data = data.filter("X", Value.of(15510.0), Value.of(18610.0));
|
||||
allPars.setParValue("U2", 0);
|
||||
FitState state = FitManager.buildState(data, model, allPars);
|
||||
//new PlotFitResultAction(GlobalContext.instance(), null).runOne(state);
|
||||
|
||||
//double delta = 4e-6;
|
||||
|
||||
//resolution.setTailFunction{double E, double U ->
|
||||
// 1-delta*(E-U);
|
||||
//}
|
||||
|
||||
resolution.setTailFunction(ResolutionFunction.getRealTail())
|
||||
|
||||
PlotFrame frame = JFreeChartFrame.drawFrame("Transmission function", null);
|
||||
frame.add(new PlottableFunction("transmission",null, {U -> resolution.value(18500,U)},13500,18505,500));
|
||||
|
||||
FitState res = fm.runTask(state, "QOW", FitTask.TASK_RUN, "N", "bkg", "E0", "U2", "trap");
|
||||
|
||||
|
||||
|
||||
res.print(out());
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts
|
||||
|
||||
import hep.dataforge.maths.integration.UnivariateIntegrator
|
||||
import hep.dataforge.plots.data.PlottableFunction
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||
import inr.numass.models.ExperimentalVariableLossSpectrum
|
||||
import org.apache.commons.math3.analysis.UnivariateFunction
|
||||
|
||||
import inr.numass.NumassContext
|
||||
import hep.dataforge.datafitter.ParamSet
|
||||
import hep.dataforge.io.PrintFunction
|
||||
|
||||
|
||||
//double exPos = 12.94
|
||||
//double exW = 1.31
|
||||
//double ionPos = 14.13
|
||||
//double ionW = 12.79
|
||||
//double exIonRatio = 0.6059
|
||||
|
||||
ParamSet params = new ParamSet()
|
||||
.setParValue("shift",0)
|
||||
.setParValue("X", 0.4)
|
||||
.setParValue("exPos", 12.94)
|
||||
.setParValue("ionPos", 15.6)
|
||||
.setParValue("exW", 1.31)
|
||||
.setParValue("ionW", 12.79)
|
||||
.setParValue("exIonRatio", 0.6059)
|
||||
|
||||
ExperimentalVariableLossSpectrum lsp = new ExperimentalVariableLossSpectrum(19005, 8e-5, 19010,0.2);
|
||||
|
||||
|
||||
JFreeChartFrame frame = JFreeChartFrame.drawFrame("Experimental Loss Test", null);
|
||||
UnivariateIntegrator integrator = NumassContext.defaultIntegrator
|
||||
|
||||
UnivariateFunction exFunc = lsp.excitation(params.getValue("exPos"), params.getValue("exW"));
|
||||
frame.add(new PlottableFunction("ex", null, exFunc, 0d, 50d, 500));
|
||||
|
||||
println "excitation norm factor " + integrator.integrate(exFunc, 0, 50)
|
||||
|
||||
UnivariateFunction ionFunc = lsp.ionization(params.getValue("ionPos"), params.getValue("ionW"));
|
||||
frame.add(new PlottableFunction("ion", null, ionFunc, 0d, 50d, 500));
|
||||
|
||||
println "ionization norm factor " + integrator.integrate(ionFunc, 0, 200)
|
||||
|
||||
UnivariateFunction sumFunc = lsp.singleScatterFunction(params);
|
||||
frame.add(new PlottableFunction("sum", null, sumFunc, 0d, 50d, 500));
|
||||
|
||||
println "sum norm factor " + integrator.integrate(sumFunc, 0, 100)
|
||||
|
||||
PrintFunction.printFunctionSimple(new PrintWriter(System.out), sumFunc, 0d, 50d, 100)
|
||||
|
||||
|
||||
JFreeChartFrame integerFrame = JFreeChartFrame.drawFrame("Experimental Loss Test", null);
|
||||
|
||||
UnivariateFunction integr = { d-> lsp.value(d,params)}
|
||||
integerFrame.add(new PlottableFunction("integr", null, integr, 18950d, 19005d, 500));
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts
|
||||
|
||||
import hep.dataforge.plots.data.PlottableFunction
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||
import org.apache.commons.math3.analysis.UnivariateFunction
|
||||
|
||||
|
||||
def lorenz = {x, x0, gama -> 1/(3.14*gama*(1+(x-x0)*(x-x0)/gama/gama))}
|
||||
|
||||
|
||||
def excitationSpectrum = {Map<Double,Double> lines, double gama ->
|
||||
UnivariateFunction function = {x->
|
||||
double res = 0;
|
||||
lines.each{k,v -> res += lorenz(x,k,gama)*v};
|
||||
return res;
|
||||
}
|
||||
return function;
|
||||
}
|
||||
|
||||
def lines =
|
||||
[
|
||||
12.6:0.5,
|
||||
12.4:0.3,
|
||||
12.2:0.2
|
||||
]
|
||||
|
||||
UnivariateFunction excitation = excitationSpectrum(lines,0.08)
|
||||
|
||||
JFreeChartFrame frame = JFreeChartFrame.drawFrame("theoretical loss spectrum", null);
|
||||
|
||||
frame.add(new PlottableFunction("excitation", null, excitation, 0d, 20d, 500));
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.scripts;
|
||||
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import hep.dataforge.data.DataSet;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.datafitter.FitManager;
|
||||
import hep.dataforge.datafitter.FitState;
|
||||
import hep.dataforge.datafitter.ParamSet;
|
||||
import hep.dataforge.datafitter.models.XYModel;
|
||||
import hep.dataforge.likelihood.BayesianManager
|
||||
import static hep.dataforge.maths.RandomUtils.setSeed;
|
||||
import inr.numass.data.SpectrumGenerator;
|
||||
import inr.numass.models.ModularTritiumSpectrum;
|
||||
import inr.numass.models.NBkgSpectrum;
|
||||
import static inr.numass.utils.DataModelUtils.getUniformSpectrumConfiguration;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
|
||||
PrintWriter out = GlobalContext.out();
|
||||
FitManager fm = new FitManager();
|
||||
|
||||
setSeed(543982);
|
||||
|
||||
// TritiumSpectrum beta = new TritiumSpectrum(2e-4, 13995d, 18580d);
|
||||
File fssfile = new File("c:\\Users\\Darksnake\\Dropbox\\PlayGround\\FS.txt");
|
||||
ModularTritiumSpectrum beta = new ModularTritiumSpectrum(8.3e-5, 14400d, 19010d, null);
|
||||
beta.setCaching(false);
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(beta);
|
||||
XYModel model = new XYModel("tritium", spectrum);
|
||||
|
||||
ParamSet allPars = new ParamSet();
|
||||
|
||||
allPars.setParValue("N", 6e5);
|
||||
//значение 6е-6 соответствует полной интенстивности 6е7 распадов в секунду
|
||||
//Проблема была в переполнении счетчика событий в генераторе. Заменил на long. Возможно стоит поставить туда число с плавающей точкой
|
||||
allPars.setParError("N", 25);
|
||||
allPars.setParDomain("N", 0d, Double.POSITIVE_INFINITY);
|
||||
allPars.setParValue("bkg", 5);
|
||||
allPars.setParError("bkg", 1e-3);
|
||||
allPars.setParValue("E0", 18575d);
|
||||
allPars.setParError("E0", 0.1);
|
||||
allPars.setParValue("mnu2", 0d);
|
||||
allPars.setParError("mnu2", 1d);
|
||||
allPars.setParValue("msterile2", 1000 * 1000);
|
||||
allPars.setParValue("U2", 0);
|
||||
allPars.setParError("U2", 1e-4);
|
||||
allPars.setParDomain("U2", 0d, 1d);
|
||||
allPars.setParValue("X", 0.0);
|
||||
allPars.setParDomain("X", 0d, Double.POSITIVE_INFINITY);
|
||||
allPars.setParValue("trap", 1d);
|
||||
allPars.setParError("trap", 0.01d);
|
||||
allPars.setParDomain("trap", 0d, Double.POSITIVE_INFINITY);
|
||||
|
||||
// PlotManager pm = new PlotManager();
|
||||
// String plotTitle = "Tritium spectrum";
|
||||
// pm.plotFunction(FunctionUtils.getSpectrumFunction(spectrum, allPars), 14000, 18600, 500,plotTitle, null);
|
||||
// PrintNamed.printSpectrum(Out.out, beta.trapping, allPars, 14000d, 18600d, 500);
|
||||
// double e = 18570d;
|
||||
// trans.alpha = 1e-4;
|
||||
// trans.plotTransmission(System.out, allPars, e, e-1000d, e+100d, 200);
|
||||
SpectrumGenerator generator = new SpectrumGenerator(model, allPars);
|
||||
|
||||
// ColumnedDataFile file = new ColumnedDataFile("d:\\PlayGround\\RUN36.cfg");
|
||||
// ListDataSet config = file.getDataSet("time","X");
|
||||
double Elow = 14000d;
|
||||
double Eup = 18600d;
|
||||
int numpoints = (int) ((Eup - Elow) / 50);
|
||||
double time = 1e6 / numpoints; // 3600 / numpoints;
|
||||
DataSet config = getUniformSpectrumConfiguration(Elow, Eup, time, numpoints);
|
||||
// config.addAll(DataModelUtils.getUniformSpectrumConfiguration(Eup, Elow, time, numpoints));// в обратную сторону
|
||||
|
||||
ListDataSet data = generator.generateData(config);
|
||||
// plotTitle = "Generated tritium spectrum data";
|
||||
// pm.plotXYScatter(data, "X", "Y",plotTitle, null);
|
||||
// bareBeta.setFSS("D:\\PlayGround\\FSS.dat");
|
||||
// data = tritiumUtils.applyDrift(data, 2.8e-6);
|
||||
|
||||
FitState state = fm.buildState(data, model, allPars);
|
||||
|
||||
// fm.checkDerivs();
|
||||
// res.print(Out.out);
|
||||
// fm.checkFitDerivatives();
|
||||
FitState res = fm.runDefaultTask(state, "U2", "N", "trap");
|
||||
|
||||
res.print(out);
|
||||
|
||||
// res = fm.runFrom(res);
|
||||
// res = fm.generateErrorsFrom(res);
|
||||
beta.setCaching(true);
|
||||
beta.setSuppressWarnings(true);
|
||||
|
||||
BayesianManager bm = new BayesianManager();
|
||||
// bm.setPriorProb(new OneSidedUniformPrior("trap", 0, true));
|
||||
// bm.setPriorProb(new GaussianPrior("trap", 1d, 0.002));
|
||||
// bm.printMarginalLikelihood(Out.out,"U2", res);
|
||||
|
||||
FitState conf = bm.getConfidenceInterval("U2", res, ["U2", "N", "trap"]);
|
||||
// plotTitle = String.format("Marginal likelihood for parameter \'%s\'", "U2");
|
||||
// pm.plotFunction(bm.getMarginalLikelihood("U2", res), 0, 2e-3, 40,plotTitle, null);
|
||||
|
||||
conf.print(out);
|
||||
// PrintNamed.printLogProbRandom(Out.out, res, 5000,0.5d, "E0","N");
|
||||
|
||||
spectrum.counter.print(out);
|
||||
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2015 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 hep.dataforge.plotfit;
|
||||
|
||||
import hep.dataforge.actions.OneToOneAction;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.data.DataPoint;
|
||||
import hep.dataforge.data.DataSet;
|
||||
import hep.dataforge.data.XYDataAdapter;
|
||||
import hep.dataforge.datafitter.FitState;
|
||||
import hep.dataforge.datafitter.models.XYModel;
|
||||
import hep.dataforge.description.NodeDef;
|
||||
import hep.dataforge.description.ValueDef;
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.exceptions.ContentException;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import hep.dataforge.plots.PlotFrame;
|
||||
import hep.dataforge.plots.PlotsPlugin;
|
||||
import hep.dataforge.plots.XYPlotFrame;
|
||||
import hep.dataforge.plots.data.PlottableData;
|
||||
import hep.dataforge.plots.data.PlottableFunction;
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.apache.commons.math3.analysis.UnivariateFunction;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
@TypedActionDef(name = "plotFit", description = "Plot fit result", inputType = FitState.class, outputType = FitState.class)
|
||||
@NodeDef(name = "adapter", info = "adapter for DataSet being fitted. By default is taken from model.")
|
||||
@ValueDef(name = "plotTitle", def = "", info = "The title of the plot.")
|
||||
public class PlotFitResultAction extends OneToOneAction<FitState, FitState> {
|
||||
|
||||
public PlotFitResultAction(Context context, Meta annotation) {
|
||||
super(context, annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FitState execute(Logable log, Meta metaData, FitState input){
|
||||
|
||||
DataSet data = input.getDataSet();
|
||||
if(!(input.getModel() instanceof XYModel)){
|
||||
log.logError("The fit model should be instance of XYModel for this action. Action failed!");
|
||||
return input;
|
||||
}
|
||||
XYModel model = (XYModel)input.getModel();
|
||||
|
||||
XYDataAdapter adapter;
|
||||
if (metaData.hasNode("adapter")){
|
||||
adapter = new XYDataAdapter(metaData.getNode("adapter"));
|
||||
} else if(input.getModel() instanceof XYModel){
|
||||
adapter = model.getAdapter();
|
||||
} else throw new ContentException("No adapter defined for data interpretation");
|
||||
|
||||
UnivariateFunction function = (double x) -> model.getSpectrum().value(x, input.getParameters());
|
||||
|
||||
XYPlotFrame frame = (XYPlotFrame) PlotsPlugin.buildFrom(getContext()).buildPlotFrame(getName(), input.getName(), metaData);
|
||||
//JFreeChartFrame.drawFrame(reader.getString("plotTitle", "Fit result plot for "+input.getName()), null);
|
||||
|
||||
double[] x = new double[data.size()];
|
||||
|
||||
// double[] y = new double[data.size()];
|
||||
|
||||
|
||||
double xMin = Double.POSITIVE_INFINITY;
|
||||
|
||||
double xMax = Double.NEGATIVE_INFINITY;
|
||||
|
||||
List<DataPoint> points = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
x[i] = adapter.getX(data.get(i)).doubleValue();
|
||||
// y[i] = adapter.getY(data.get(i));
|
||||
|
||||
points.add(adapter.mapToDefault(data.get(i)));
|
||||
if(x[i]<xMin){
|
||||
xMin = x[i];
|
||||
}
|
||||
|
||||
if(x[i]>xMax){
|
||||
xMax = x[i];
|
||||
}
|
||||
}
|
||||
|
||||
frame.add(new PlottableFunction("fit", null, function, points, "x"));
|
||||
|
||||
frame.add(new PlottableData("data", null, points));
|
||||
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
}
|
200
numass-main/src/main/java/inr/numass/Main.java
Normal file
200
numass-main/src/main/java/inr/numass/Main.java
Normal file
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass;
|
||||
|
||||
import hep.dataforge.actions.ActionResult;
|
||||
import static hep.dataforge.actions.RunManager.executeXML;
|
||||
import hep.dataforge.context.Context;
|
||||
import static hep.dataforge.context.GlobalContext.out;
|
||||
import hep.dataforge.data.DataManager;
|
||||
import hep.dataforge.datafitter.MINUITPlugin;
|
||||
import hep.dataforge.io.IOManager;
|
||||
import static inr.numass.NumassContext.printDescription;
|
||||
import inr.numass.workbench.Workbench;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Locale;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||
import org.apache.commons.cli.BasicParser;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
import static java.util.Locale.setDefault;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
setDefault(Locale.US);
|
||||
|
||||
NumassContext context = new NumassContext();
|
||||
context.loadPlugin(new MINUITPlugin());
|
||||
run(context, args);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static ActionResult run(NumassContext context, String[] args) throws Exception {
|
||||
Logger logger = LoggerFactory.getLogger("numass-main");
|
||||
|
||||
Options options = prepareOptions();
|
||||
CommandLineParser parser = new BasicParser();
|
||||
CommandLine line;
|
||||
try {
|
||||
// parse the command line arguments
|
||||
line = parser.parse(options, args);
|
||||
} catch (ParseException exp) {
|
||||
// oops, something went wrong
|
||||
logger.error("Command line error. Reason: " + exp.getMessage());
|
||||
return ActionResult.empty();
|
||||
}
|
||||
|
||||
if (line.hasOption("lc")) {
|
||||
printDescription(context, true);
|
||||
return ActionResult.empty();
|
||||
} else if (line.hasOption("l")) {
|
||||
printDescription(context, false);
|
||||
return ActionResult.empty();
|
||||
}
|
||||
|
||||
String cfgPath;
|
||||
|
||||
if (args.length == 0) {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("java -jar DataReader.jar [OPTIONS]", options);
|
||||
out().println("Trying to use default config location...");
|
||||
}
|
||||
|
||||
if (line.hasOption("c")) {
|
||||
cfgPath = line.getOptionValue("c");
|
||||
if (cfgPath == null) {
|
||||
logger.info("Configutation path not provided.");
|
||||
return ActionResult.empty();
|
||||
}
|
||||
|
||||
File config = context.io().getFile(cfgPath);
|
||||
|
||||
if (!config.exists()) {
|
||||
throw new FileNotFoundException("Configuration file not found");
|
||||
}
|
||||
|
||||
context.putValue(IOManager.ROOT_DIRECTORY_CONTEXT_KEY, config.getParentFile().toString());
|
||||
|
||||
applyCLItoContext(line, context);
|
||||
|
||||
return executeXML(context, config);
|
||||
} else {
|
||||
Workbench.main(args);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void applyCLItoContext(CommandLine line, Context context) throws FileNotFoundException {
|
||||
File workDir = new File(context.getString(IOManager.ROOT_DIRECTORY_CONTEXT_KEY));
|
||||
|
||||
if (line.hasOption("h")) {
|
||||
workDir = new File(line.getOptionValue("h"));
|
||||
context.putValue(IOManager.ROOT_DIRECTORY_CONTEXT_KEY, workDir.toString());
|
||||
}
|
||||
|
||||
if (line.hasOption("d")) {
|
||||
String dataPath = line.getOptionValue("d");
|
||||
File dataDir = new File(dataPath);
|
||||
if (!dataDir.isAbsolute()) {
|
||||
dataDir = new File(workDir, dataPath);
|
||||
}
|
||||
if (dataDir.exists() && dataDir.isDirectory()) {
|
||||
context.putValue(DataManager.DATA_DIR, dataDir.getAbsolutePath());
|
||||
} else {
|
||||
throw new FileNotFoundException("Data directory not found");
|
||||
}
|
||||
}
|
||||
|
||||
if (line.hasOption("o")) {
|
||||
String outPath = line.getOptionValue("o");
|
||||
File outDir = new File(outPath);
|
||||
if (!outDir.isAbsolute()) {
|
||||
outDir = new File(workDir, outPath);
|
||||
}
|
||||
if (!outDir.exists()) {
|
||||
outDir.mkdirs();
|
||||
}
|
||||
context.putValue(NumassIO.NUMASS_OUTPUT_CONTEXT_KEY, outDir.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static Options prepareOptions() {
|
||||
Options options = new Options();
|
||||
|
||||
options.addOption("c", "config", true, "Configuration file path. "
|
||||
+ "If this option is not present, than workbench is launched and all other parameters are ignored.");
|
||||
options.addOption("h", "home", true,
|
||||
"Working directory (by default the working directory is the directory where config file is placed)");
|
||||
options.addOption("d", "data", true, "Data directory (absolute or relative to working directory)");
|
||||
options.addOption("o", "out", true, "Output directory (absolute or relative to working directory)");
|
||||
options.addOption("l", "list", false, "List of available actions");
|
||||
options.addOption("lc", "list-color", false, "List of available actions with ANSI coloring");
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private static String getFilePathFromDialog(String homeDir) throws FileNotFoundException {
|
||||
//TODO переместить в IOManager
|
||||
|
||||
JFrame frame = new JFrame("Chose a configuration file");
|
||||
JFileChooser fc = new JFileChooser(homeDir);
|
||||
FileFilter xmlFilter = new FileNameExtensionFilter("XML files", "XML", "xml");
|
||||
// fc.addChoosableFileFilter(xmlFilter);
|
||||
|
||||
fc.setFileFilter(xmlFilter);
|
||||
|
||||
int returnVal = fc.showOpenDialog(frame);
|
||||
File file;
|
||||
if (returnVal == JFileChooser.APPROVE_OPTION) {
|
||||
file = fc.getSelectedFile();
|
||||
frame.dispose();
|
||||
return file.getAbsolutePath();
|
||||
} else {
|
||||
frame.dispose();
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
79
numass-main/src/main/java/inr/numass/NumassContext.java
Normal file
79
numass-main/src/main/java/inr/numass/NumassContext.java
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass;
|
||||
|
||||
import hep.dataforge.actions.ActionManager;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.description.ActionDescriptor;
|
||||
import hep.dataforge.description.DescriptorFormatter;
|
||||
import hep.dataforge.description.DescriptorUtils;
|
||||
import hep.dataforge.description.TextDescriptorFormatter;
|
||||
import hep.dataforge.exceptions.DescriptorException;
|
||||
import hep.dataforge.maths.integration.GaussRuleIntegrator;
|
||||
import hep.dataforge.maths.integration.UnivariateIntegrator;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class NumassContext extends Context {
|
||||
|
||||
public static UnivariateIntegrator defaultIntegrator = new GaussRuleIntegrator(300);
|
||||
public static UnivariateIntegrator highDensityIntegrator = new GaussRuleIntegrator(500);
|
||||
|
||||
|
||||
public NumassContext(Context parent, Meta config) {
|
||||
super(parent, "numass", config);
|
||||
init();
|
||||
}
|
||||
|
||||
public NumassContext(Context parent) {
|
||||
super(parent, "numass");
|
||||
init();
|
||||
}
|
||||
|
||||
public NumassContext() {
|
||||
super("numass");
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
attachIoManager(new NumassIO());
|
||||
loadPlugin("inr.numass:numass");
|
||||
}
|
||||
|
||||
public static void printDescription(Context context, boolean allowANSI) throws DescriptorException {
|
||||
PrintWriter writer = new PrintWriter(context.io().out());
|
||||
DescriptorFormatter formatter = new TextDescriptorFormatter(writer, allowANSI);
|
||||
writer.println("***Data description***");
|
||||
writer.print(" ");
|
||||
formatter.showDescription(
|
||||
DescriptorUtils.buildDescriptor(
|
||||
DescriptorUtils.findAnnotatedElement("method::hep.dataforge.data.DataManager.read")
|
||||
));
|
||||
writer.println("***Allowed actions***");
|
||||
|
||||
for (ActionDescriptor descriptor : ActionManager.buildFrom(context).listActions()) {
|
||||
writer.print(" ");
|
||||
formatter.showDescription(descriptor);
|
||||
}
|
||||
writer.println("***End of actions list***");
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
}
|
131
numass-main/src/main/java/inr/numass/NumassIO.java
Normal file
131
numass-main/src/main/java/inr/numass/NumassIO.java
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass;
|
||||
|
||||
import hep.dataforge.data.BinaryData;
|
||||
import hep.dataforge.data.FileData;
|
||||
import hep.dataforge.io.BasicIOManager;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.names.Name;
|
||||
import inr.numass.data.NumassDataReader;
|
||||
import inr.numass.data.NumassPawReader;
|
||||
import inr.numass.data.RawNMFile;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.apache.commons.io.output.TeeOutputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class NumassIO extends BasicIOManager {
|
||||
|
||||
public static final String NUMASS_OUTPUT_CONTEXT_KEY = "numass.outputDir";
|
||||
|
||||
@Override
|
||||
public OutputStream out(Name stage, Name name) {
|
||||
List<String> tokens = new ArrayList<>();
|
||||
if (getContext().hasValue("numass.path")) {
|
||||
String path = getContext().getString("numass.path");
|
||||
if (path.contains(".")) {
|
||||
tokens.addAll(Arrays.asList(path.split(".")));
|
||||
} else {
|
||||
tokens.add(path);
|
||||
}
|
||||
}
|
||||
|
||||
if (stage != null) {
|
||||
tokens.addAll(Arrays.asList(stage.asArray()));
|
||||
}
|
||||
|
||||
String dirName = String.join(File.separator, tokens);
|
||||
String fileName = name.removeNameSpace().toString() + ".out";
|
||||
return buildOut(getOutputDir(), dirName, fileName);
|
||||
}
|
||||
|
||||
private File getOutputDir() {
|
||||
String outputDirPath = getContext().getString(NUMASS_OUTPUT_CONTEXT_KEY, ".dataforge");
|
||||
File res = new File(getRootDirectory(), outputDirPath);
|
||||
if (!res.exists()) {
|
||||
res.mkdir();
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
protected OutputStream buildOut(File parentDir, String dirName, String fileName) {
|
||||
File outputFile;
|
||||
|
||||
if (!parentDir.exists()) {
|
||||
throw new RuntimeException("Working directory does not exist");
|
||||
}
|
||||
if (dirName != null && !dirName.isEmpty()) {
|
||||
parentDir = new File(parentDir, dirName);
|
||||
if (!parentDir.exists()) {
|
||||
parentDir.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
// String output = source.meta().getString("output", this.meta().getString("output", fileName + ".out"));
|
||||
outputFile = new File(parentDir, fileName);
|
||||
try {
|
||||
if (getContext().getBoolean("numass.consoleOutput", false)) {
|
||||
return new TeeOutputStream(new FileOutputStream(outputFile), System.out);
|
||||
} else {
|
||||
return new FileOutputStream(outputFile);
|
||||
}
|
||||
} catch (FileNotFoundException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static RawNMFile readAsDat(BinaryData source, Meta config) {
|
||||
try {
|
||||
return new NumassDataReader(source, config).read();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static RawNMFile readAsPaw(BinaryData source) {
|
||||
try {
|
||||
return new NumassPawReader().readPaw(source.getInputStream(), source.getName());
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static RawNMFile getNumassData(FileData source, Meta config) {
|
||||
RawNMFile dataFile;
|
||||
switch (source.getExtension()) {
|
||||
case "paw":
|
||||
dataFile = readAsPaw(source);
|
||||
break;
|
||||
case "dat":
|
||||
dataFile = readAsDat(source, config);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Wrong file format");
|
||||
}
|
||||
return dataFile;
|
||||
}
|
||||
}
|
275
numass-main/src/main/java/inr/numass/NumassPlugin.java
Normal file
275
numass-main/src/main/java/inr/numass/NumassPlugin.java
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass;
|
||||
|
||||
import hep.dataforge.actions.ActionManager;
|
||||
import hep.dataforge.context.BasicPlugin;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.context.PluginDef;
|
||||
import hep.dataforge.data.DataAdapter;
|
||||
import hep.dataforge.data.XYDataAdapter;
|
||||
import hep.dataforge.datafitter.FitManager;
|
||||
import hep.dataforge.datafitter.FitPlugin;
|
||||
import hep.dataforge.datafitter.models.Model;
|
||||
import hep.dataforge.datafitter.models.ModelManager;
|
||||
import hep.dataforge.datafitter.models.WeightedXYModel;
|
||||
import hep.dataforge.datafitter.models.XYModel;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.plotfit.PlotFitResultAction;
|
||||
import hep.dataforge.plots.PlotDataAction;
|
||||
import inr.numass.actions.AdjustErrorsAction;
|
||||
import inr.numass.actions.FindBorderAction;
|
||||
import inr.numass.actions.MergeDataAction;
|
||||
import inr.numass.actions.MonitorCorrectAction;
|
||||
import inr.numass.actions.PrepareDataAction;
|
||||
import inr.numass.actions.ReadNumassDataAction;
|
||||
import inr.numass.actions.ShowLossSpectrumAction;
|
||||
import inr.numass.actions.ShowSpectrumAction;
|
||||
import inr.numass.actions.SlicingAction;
|
||||
import inr.numass.actions.SummaryAction;
|
||||
import inr.numass.models.BetaSpectrum;
|
||||
import inr.numass.models.CustomNBkgSpectrum;
|
||||
import inr.numass.models.EmpiricalLossSpectrum;
|
||||
import inr.numass.models.ExperimentalVariableLossSpectrum;
|
||||
import inr.numass.models.GaussSourceSpectrum;
|
||||
import inr.numass.models.GunSpectrum;
|
||||
import inr.numass.models.ModularSpectrum;
|
||||
import inr.numass.models.NBkgSpectrum;
|
||||
import inr.numass.models.RangedNamedSetSpectrum;
|
||||
import inr.numass.models.ResolutionFunction;
|
||||
import inr.numass.models.TransmissionInterpolator;
|
||||
import inr.numass.models.VariableLossSpectrum;
|
||||
import org.apache.commons.math3.analysis.BivariateFunction;
|
||||
import org.apache.commons.math3.analysis.UnivariateFunction;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@PluginDef(group = "inr.numass", name = "numass",
|
||||
dependsOn = {"hep.dataforge:MINUIT", "hep.dataforge:plots"},
|
||||
description = "Numass data analysis tools")
|
||||
public class NumassPlugin extends BasicPlugin {
|
||||
|
||||
@Override
|
||||
public void apply(Context context) {
|
||||
FitManager fm = context.provide("hep.dataforge:fitting", FitPlugin.class).getFitManager();
|
||||
ModelManager mm = fm.getModelManager();
|
||||
loadModels(mm);
|
||||
|
||||
ActionManager actions = ActionManager.buildFrom(context);
|
||||
actions.registerAction(SlicingAction.class);
|
||||
actions.registerAction(ShowSpectrumAction.class);
|
||||
actions.registerAction(PrepareDataAction.class);
|
||||
actions.registerAction(ReadNumassDataAction.class);
|
||||
actions.registerAction(MergeDataAction.class);
|
||||
actions.registerAction(FindBorderAction.class);
|
||||
actions.registerAction(MonitorCorrectAction.class);
|
||||
actions.registerAction(SummaryAction.class);
|
||||
actions.registerAction(PlotDataAction.class);
|
||||
actions.registerAction(PlotFitResultAction.class);
|
||||
actions.registerAction(ShowLossSpectrumAction.class);
|
||||
actions.registerAction(AdjustErrorsAction.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clean(Context context) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all numass model factories
|
||||
*
|
||||
* @param manager
|
||||
*/
|
||||
private void loadModels(ModelManager manager) {
|
||||
|
||||
manager.addModel("modularbeta", (context, an) -> {
|
||||
double A = an.getDouble("resolution", 8.3e-5);//8.3e-5
|
||||
double from = an.getDouble("from", 14400d);
|
||||
double to = an.getDouble("to", 19010d);
|
||||
RangedNamedSetSpectrum beta = new BetaSpectrum(context.io().getFile("FS.txt"));
|
||||
ModularSpectrum sp = new ModularSpectrum(beta, A, from, to);
|
||||
sp.setCaching(false);
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(sp);
|
||||
|
||||
return new XYModel("tritium", spectrum, getAdapter(an));
|
||||
});
|
||||
|
||||
manager.addModel("scatter", (context, an) -> {
|
||||
double A = an.getDouble("resolution", 8.3e-5);//8.3e-5
|
||||
double from = an.getDouble("from", 0);
|
||||
double to = an.getDouble("to", 0);
|
||||
|
||||
ModularSpectrum sp;
|
||||
if (from == to) {
|
||||
sp = new ModularSpectrum(new GaussSourceSpectrum(), A);
|
||||
} else {
|
||||
sp = new ModularSpectrum(new GaussSourceSpectrum(), A, from, to);
|
||||
}
|
||||
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(sp);
|
||||
sp.setCaching(false);
|
||||
|
||||
return new XYModel("scatter", spectrum, getAdapter(an));
|
||||
});
|
||||
|
||||
manager.addModel("scatter-empiric", (context, an) -> {
|
||||
double eGun = an.getDouble("eGun", 19005d);
|
||||
|
||||
TransmissionInterpolator interpolator = buildInterpolator(context, an, eGun);
|
||||
|
||||
EmpiricalLossSpectrum loss = new EmpiricalLossSpectrum(interpolator, eGun + 5);
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(loss);
|
||||
|
||||
double weightReductionFactor = an.getDouble("weightReductionFactor", 2.0);
|
||||
|
||||
return new WeightedXYModel("scatter-empiric", spectrum, getAdapter(an), (dp) -> weightReductionFactor);
|
||||
});
|
||||
|
||||
manager.addModel("scatter-empiric-variable", (context, an) -> {
|
||||
double eGun = an.getDouble("eGun", 19005d);
|
||||
|
||||
//build transmisssion with given data, annotation and smoothing
|
||||
UnivariateFunction interpolator = buildInterpolator(context, an, eGun);
|
||||
|
||||
VariableLossSpectrum loss = VariableLossSpectrum.withData(interpolator, eGun + 5);
|
||||
|
||||
double tritiumBackground = an.getDouble("tritiumBkg", 0);
|
||||
|
||||
NBkgSpectrum spectrum;
|
||||
if (tritiumBackground == 0) {
|
||||
spectrum = new NBkgSpectrum(loss);
|
||||
} else {
|
||||
spectrum = CustomNBkgSpectrum.tritiumBkgSpectrum(loss, tritiumBackground);
|
||||
}
|
||||
|
||||
double weightReductionFactor = an.getDouble("weightReductionFactor", 2.0);
|
||||
|
||||
Model res = new WeightedXYModel("scatter-variable", spectrum, getAdapter(an), (dp) -> weightReductionFactor);
|
||||
res.configure(an);
|
||||
return res;
|
||||
});
|
||||
|
||||
manager.addModel("scatter-analytic-variable", (context, an) -> {
|
||||
double eGun = an.getDouble("eGun", 19005d);
|
||||
|
||||
VariableLossSpectrum loss = VariableLossSpectrum.withGun(eGun + 5);
|
||||
|
||||
double tritiumBackground = an.getDouble("tritiumBkg", 0);
|
||||
|
||||
NBkgSpectrum spectrum;
|
||||
if (tritiumBackground == 0) {
|
||||
spectrum = new NBkgSpectrum(loss);
|
||||
} else {
|
||||
spectrum = CustomNBkgSpectrum.tritiumBkgSpectrum(loss, tritiumBackground);
|
||||
}
|
||||
|
||||
return new XYModel("scatter-variable", spectrum, getAdapter(an));
|
||||
});
|
||||
|
||||
manager.addModel("scatter-empiric-experimental", (context, an) -> {
|
||||
double eGun = an.getDouble("eGun", 19005d);
|
||||
|
||||
//build transmisssion with given data, annotation and smoothing
|
||||
UnivariateFunction interpolator = buildInterpolator(context, an, eGun);
|
||||
|
||||
double smoothing = an.getDouble("lossSmoothing", 0.3);
|
||||
|
||||
VariableLossSpectrum loss = ExperimentalVariableLossSpectrum.withData(interpolator, eGun + 5, smoothing);
|
||||
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(loss);
|
||||
|
||||
double weightReductionFactor = an.getDouble("weightReductionFactor", 2.0);
|
||||
|
||||
Model res = new WeightedXYModel("scatter-empiric-experimental", spectrum, getAdapter(an), (dp) -> weightReductionFactor);
|
||||
res.configure(an);
|
||||
return res;
|
||||
});
|
||||
|
||||
manager.addModel("modularbeta-unadeabatic", (context, an) -> {
|
||||
double A = an.getDouble("resolution", 8.3e-5);//8.3e-5
|
||||
double from = an.getDouble("from", 14400d);
|
||||
double to = an.getDouble("to", 19010d);
|
||||
BivariateFunction reolutionTail = (double E, double U) -> {
|
||||
double x = E - U;
|
||||
if (x > 1500) {
|
||||
return 0.98;
|
||||
} else //Intercept = 1.00051, Slope = -1.3552E-5
|
||||
{
|
||||
return 1.00051 - 1.3552E-5 * x;
|
||||
}
|
||||
};
|
||||
RangedNamedSetSpectrum beta = new BetaSpectrum(context.io().getFile("FS.txt"));
|
||||
ModularSpectrum sp = new ModularSpectrum(beta, new ResolutionFunction(A, reolutionTail), from, to);
|
||||
sp.setCaching(false);
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(sp);
|
||||
|
||||
return new XYModel("tritium", spectrum, getAdapter(an));
|
||||
});
|
||||
|
||||
manager.addModel("gun", (context, an) -> {
|
||||
GunSpectrum gsp = new GunSpectrum();
|
||||
|
||||
double tritiumBackground = an.getDouble("tritiumBkg", 0);
|
||||
|
||||
NBkgSpectrum spectrum;
|
||||
if (tritiumBackground == 0) {
|
||||
spectrum = new NBkgSpectrum(gsp);
|
||||
} else {
|
||||
spectrum = CustomNBkgSpectrum.tritiumBkgSpectrum(gsp, tritiumBackground);
|
||||
}
|
||||
|
||||
return new XYModel("gun", spectrum, getAdapter(an));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private TransmissionInterpolator buildInterpolator(Context context, Meta an, double eGun) {
|
||||
String transXName = an.getString("transXName", "Uset");
|
||||
String transYName = an.getString("transYName", "CR");
|
||||
|
||||
double stitchBorder = an.getDouble("stitchBorder", eGun - 7);
|
||||
int nSmooth = an.getInt("nSmooth", 15);
|
||||
|
||||
double w = an.getDouble("w", 0.8);
|
||||
|
||||
if (an.hasValue("transFile")) {
|
||||
String transmissionFile = an.getString("transFile");
|
||||
|
||||
return TransmissionInterpolator
|
||||
.fromFile(context, transmissionFile, transXName, transYName, nSmooth, w, stitchBorder);
|
||||
} else if (an.hasNode("transBuildAction")) {
|
||||
Meta transBuild = an.getNode("transBuildAction");
|
||||
try {
|
||||
return TransmissionInterpolator.fromAction((Context) context,
|
||||
transBuild, transXName, transYName, nSmooth, w, stitchBorder);
|
||||
} catch (InterruptedException ex) {
|
||||
throw new RuntimeException("Transmission build failed");
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Transmission declaration not found");
|
||||
}
|
||||
}
|
||||
|
||||
private XYDataAdapter getAdapter(Meta an) {
|
||||
if (an.hasNode(DataAdapter.DATA_ADAPTER_ANNOTATION_NAME)) {
|
||||
return new XYDataAdapter(an.getNode(DataAdapter.DATA_ADAPTER_ANNOTATION_NAME));
|
||||
} else {
|
||||
return new XYDataAdapter("Uread", "CR", "CRerr");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.actions.OneToOneAction;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.data.DataPoint;
|
||||
import hep.dataforge.data.DataSet;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Adjust errors for all numass points in the dataset
|
||||
*
|
||||
* @author Alexander Nozik <altavir@gmail.com>
|
||||
*/
|
||||
@TypedActionDef(name = "adjustErrors", inputType = DataSet.class, outputType = DataSet.class)
|
||||
public class AdjustErrorsAction extends OneToOneAction<DataSet, DataSet> {
|
||||
|
||||
public AdjustErrorsAction(Context context, Meta annotation) {
|
||||
super(context, annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSet execute(Logable log, Meta meta, DataSet input) {
|
||||
List<DataPoint> points = new ArrayList<>();
|
||||
for (DataPoint dp : input) {
|
||||
points.add(evalPoint(meta, dp));
|
||||
}
|
||||
|
||||
return new ListDataSet(input.getName(), input.meta(), points, input.getDataFormat());
|
||||
}
|
||||
|
||||
private DataPoint evalPoint(Meta meta, DataPoint dp) {
|
||||
if (meta.hasNode("point")) {
|
||||
for (Meta pointMeta : meta.getNodes("point")) {
|
||||
if (pointMeta.getDouble("Uset") == dp.getDouble("Uset")) {
|
||||
return adjust(dp, pointMeta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (meta.hasNode("range")) {
|
||||
for (Meta rangeMeta : meta.getNodes("range")) {
|
||||
double from = rangeMeta.getDouble("from", 0);
|
||||
double to = rangeMeta.getDouble("to", Double.POSITIVE_INFINITY);
|
||||
double u = rangeMeta.getDouble("Uset");
|
||||
if (rangeMeta.getDouble("Uset") == dp.getDouble("Uset")) {
|
||||
return adjust(dp, rangeMeta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (meta.hasNode("all")) {
|
||||
return adjust(dp, meta.getNode("all"));
|
||||
}
|
||||
|
||||
return dp;
|
||||
}
|
||||
|
||||
private DataPoint adjust(DataPoint dp, Meta config) {
|
||||
MapDataPoint res = new MapDataPoint(dp);
|
||||
if (res.hasValue("CRerr")) {
|
||||
double instability = 0;
|
||||
if (dp.hasValue("CR")) {
|
||||
instability = dp.getDouble("CR") * config.getDouble("instability", 0);
|
||||
}
|
||||
|
||||
double factor = config.getDouble("factor", 1d);
|
||||
double base = config.getDouble("base", 0);
|
||||
double adjusted = res.getDouble("CRerr") * factor + instability + base;
|
||||
res.putValue("CRerr", adjusted);
|
||||
} else {
|
||||
throw new RuntimeException("The value CRerr is not found in the data point!");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
86
numass-main/src/main/java/inr/numass/actions/BorderData.java
Normal file
86
numass-main/src/main/java/inr/numass/actions/BorderData.java
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.values.Value;
|
||||
import inr.numass.data.NMFile;
|
||||
import inr.numass.data.NMPoint;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class BorderData extends ListDataSet {
|
||||
|
||||
private final static String[] names = {"U", "80%", "90%", "95%", "99%"};
|
||||
private final static double[] percents = {0.8, 0.9, 0.95, 0.99};
|
||||
|
||||
public static double getNorm(Map<Double, Double> spectrum, int lower, int upper) {
|
||||
double res = 0;
|
||||
for (Map.Entry<Double, Double> entry : spectrum.entrySet()) {
|
||||
if ((entry.getKey() >= lower) && (entry.getKey() <= upper)) {
|
||||
res += entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public BorderData(NMFile file, int upper, int lower, NMPoint reference) {
|
||||
super(names);
|
||||
if (upper <= lower) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
fill(file, lower, upper, reference);
|
||||
}
|
||||
|
||||
private void fill(NMFile file, int lower, int upper, NMPoint reference) {
|
||||
for (NMPoint point : file.getNMPoints()) {
|
||||
if ((reference != null) && (point.getUset() == reference.getUset())) {
|
||||
continue;
|
||||
}
|
||||
//создаем основу для будущей точки
|
||||
HashMap<String, Value> map = new HashMap<>();
|
||||
map.put(names[0], Value.of(point.getUset()));
|
||||
Map<Double, Double> spectrum;
|
||||
if (reference != null) {
|
||||
spectrum = point.getMapWithBinning(reference, 0);
|
||||
} else {
|
||||
spectrum = point.getMapWithBinning(0, true);
|
||||
}
|
||||
double norm = getNorm(spectrum, lower, upper);
|
||||
double counter = 0;
|
||||
int chanel = upper;
|
||||
while (chanel > lower) {
|
||||
chanel--;
|
||||
counter += spectrum.get((double) chanel);
|
||||
for (int i = 0; i < percents.length; i++) {
|
||||
if (counter / norm > percents[i]) {
|
||||
if (!map.containsKey(names[i + 1])) {
|
||||
map.put(names[i + 1], Value.of(chanel));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.add(new MapDataPoint(map));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.actions.OneToOneAction;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.description.ValueDef;
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.exceptions.ContentException;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import inr.numass.data.RawNMFile;
|
||||
import inr.numass.data.RawNMPoint;
|
||||
import inr.numass.debunch.DebunchReport;
|
||||
import inr.numass.debunch.FrameAnalizer;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
@TypedActionDef(name = "debunch", inputType = RawNMFile.class, outputType = RawNMFile.class)
|
||||
@ValueDef(name = "upperchanel", type = "NUMBER", def = "4095", info = "An upper chanel for debuncing")
|
||||
@ValueDef(name = "lowerchanel", type = "NUMBER", def = "0", info = "A lower chanel for debuncing")
|
||||
@ValueDef(name = "rejectprob", type = "NUMBER", def = "1e-5", info = "Rejection probability")
|
||||
@ValueDef(name = "framelength", type = "NUMBER", def = "5", info = "Frame length in seconds")
|
||||
@ValueDef(name = "maxcr", type = "NUMBER", def = "100", info = "Maximum count rate for debunching")
|
||||
public class DebunchAction extends OneToOneAction<RawNMFile,RawNMFile> {
|
||||
|
||||
|
||||
public DebunchAction(Context context, Meta an) {
|
||||
super(context, an);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RawNMFile execute(Logable log, Meta reader, RawNMFile source) throws ContentException {
|
||||
log.log("File {} started", source.getName());
|
||||
|
||||
int upper = source.meta().getInt("upperchanel", this.meta().getInt("upperchanel", RawNMPoint.MAX_CHANEL));
|
||||
int lower = source.meta().getInt("lowerchanel", this.meta().getInt("lowerchanel", 0));
|
||||
double rejectionprob = source.meta().getDouble("rejectprob", this.meta().getDouble("rejectprob", 1e-5));
|
||||
double framelength = source.meta().getDouble("framelength", this.meta().getDouble("framelength", 5));
|
||||
double maxCR = source.meta().getDouble("maxcr", this.meta().getDouble("maxcr", 100d));
|
||||
|
||||
RawNMFile res = new RawNMFile(source.getName());
|
||||
res.setHead(source.getHead());
|
||||
source.getData().stream().map((point) -> {
|
||||
double cr = point.selectChanels(lower, upper).getCR();
|
||||
if (cr < maxCR) {
|
||||
DebunchReport report = new FrameAnalizer(rejectionprob, framelength, lower, upper).debunchPoint(point);
|
||||
|
||||
log.log("Debunching file '{}', point '{}': {} percent events {} percent time in bunches",
|
||||
source.getName(), point.getUset(), report.eventsFiltred() * 100, report.timeFiltred() * 100);
|
||||
point = report.getPoint();
|
||||
}
|
||||
return point;
|
||||
}).forEach((point) -> {
|
||||
res.putPoint(point);
|
||||
});
|
||||
log.log("File {} completed", source.getName());
|
||||
|
||||
log.getLog().print(new PrintWriter(buildActionOutput(source)));
|
||||
|
||||
// res.configure(source.meta());
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.actions.OneToOneAction;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.exceptions.ContentException;
|
||||
import hep.dataforge.io.ColumnedDataWriter;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import inr.numass.data.NMFile;
|
||||
import inr.numass.data.NMPoint;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
@TypedActionDef(name = "findBorder", inputType = NMFile.class, outputType = NMFile.class)
|
||||
public class FindBorderAction extends OneToOneAction<NMFile, NMFile> {
|
||||
|
||||
|
||||
public FindBorderAction(Context context, Meta an) {
|
||||
super(context, an);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NMFile execute(Logable log, Meta reader, NMFile source) throws ContentException {
|
||||
log.log("File {} started", source.getName());
|
||||
|
||||
int upperBorder = meta().getInt("upper", 4096);
|
||||
int lowerBorder = meta().getInt("lower", 0);
|
||||
double substractReference = meta().getDouble("reference", 0);
|
||||
|
||||
NMPoint referencePoint = null;
|
||||
if (substractReference > 0) {
|
||||
referencePoint = source.getByUset(substractReference);
|
||||
if (referencePoint == null) {
|
||||
log.log("Reference point {} not found", substractReference);
|
||||
}
|
||||
}
|
||||
|
||||
BorderData bData = new BorderData(source, upperBorder, lowerBorder, referencePoint);
|
||||
|
||||
OutputStream stream = buildActionOutput(source);
|
||||
|
||||
ColumnedDataWriter.writeDataSet(stream, bData, String.format("%s : lower = %d upper = %d", source.getName(), lowerBorder, upperBorder));
|
||||
|
||||
log.log("File {} completed", source.getName());
|
||||
return source;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.actions.ManyToOneAction;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.content.NamedGroup;
|
||||
import hep.dataforge.content.GroupBuilder;
|
||||
import hep.dataforge.description.NodeDef;
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.data.DataPoint;
|
||||
import hep.dataforge.data.DataSet;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.io.ColumnedDataWriter;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
@TypedActionDef(name = "merge", inputType = DataSet.class, outputType = DataSet.class, description = "Merge different numass data files into one.")
|
||||
@NodeDef(name = "grouping", info = "The defenition of grouping rule for this merge", target = "method::hep.dataforge.content.GroupBuilder.byAnnotation")
|
||||
//@Parameter(name = "groupBy", def = "mergeTag", info = "Defines the name of the value by which grouping is made. The value is supposed to be a String, but in practice could be any type which could be converted to String.")
|
||||
public class MergeDataAction extends ManyToOneAction<DataSet, DataSet> {
|
||||
|
||||
public static final String MERGE_NAME = "mergeName";
|
||||
public static String[] parnames = {"Uset", "Uread", "Length", "Total", "Window", "Corrected", "CR", "CRerr"};
|
||||
|
||||
public MergeDataAction(Context context, Meta an) {
|
||||
super(context, an);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<NamedGroup<DataSet>> buildGroups(Meta reader, List<DataSet> input) {
|
||||
List<NamedGroup<DataSet>> groups;
|
||||
if (reader.hasNode("grouping")) {
|
||||
groups = super.buildGroups(reader, input);
|
||||
} else {
|
||||
groups = GroupBuilder.byValue(MERGE_NAME, reader.getString(MERGE_NAME, "merge")).group(input);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSet execute(Logable log, Meta reader, NamedGroup<DataSet> input) {
|
||||
return mergeOne(log, input.getName(), input.asList());
|
||||
// List<DataSet> res = new ArrayList<>();
|
||||
// for (NamedGroup<DataSet> group : groups) {
|
||||
// res.add(mergeOne(log, group.getName(), group.asList()));
|
||||
// }
|
||||
// return new ContentList<>(input.getName(), DataSet.class, res);
|
||||
}
|
||||
|
||||
private DataSet mergeOne(Logable log, String fileName, List<DataSet> files) {
|
||||
DataSet[] data = new DataSet[files.size()];
|
||||
String head = "Numass data merge\n";
|
||||
|
||||
String numassPath = "";
|
||||
|
||||
/*
|
||||
* Проверяем являются ли пути одинаковыми у всех файлов
|
||||
* TODO не изящное решение
|
||||
*/
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
data[i] = files.get(i);
|
||||
head += "\t" + data[i].getName() + "\n";
|
||||
if (numassPath != null) {
|
||||
String newPath = data[i].meta().getString("numass.path", null);
|
||||
if (numassPath.isEmpty()) {
|
||||
numassPath = newPath;
|
||||
} else {
|
||||
if (!numassPath.equals(newPath)) {
|
||||
numassPath = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DataSet res = mergeDataSets(fileName, data);
|
||||
|
||||
/*
|
||||
* Указываем путь только если он одинаковый для всех входных файлов
|
||||
*/
|
||||
if (numassPath != null) {
|
||||
res.configure(res.meta().getBuilder().putValue("numass.path", numassPath).build());
|
||||
}
|
||||
|
||||
res = res.sort("Uset", true);
|
||||
|
||||
OutputStream stream = buildActionOutput(res);
|
||||
|
||||
ColumnedDataWriter.writeDataSet(stream, res, head);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// private Map<String, List<DataSet>> buildMergeGroups(String mergeBy, NamedGroup<DataSet> input) {
|
||||
// Map<String, List<DataSet>> map = new HashMap<>();
|
||||
// for (DataSet ds : input) {
|
||||
// String tag = ds.meta().getString(mergeBy, meta().getString(mergeBy, "merge"));
|
||||
// if (!map.containsKey(tag)) {
|
||||
// map.put(tag, new ArrayList<>());
|
||||
// }
|
||||
// map.get(tag).add(ds);
|
||||
// }
|
||||
// return map;
|
||||
// }
|
||||
private DataPoint mergeDataPoints(DataPoint dp1, DataPoint dp2) {
|
||||
if (dp1 == null) {
|
||||
return dp2;
|
||||
}
|
||||
if (dp2 == null) {
|
||||
return dp1;
|
||||
}
|
||||
|
||||
double Uset = dp1.getValue(parnames[0]).doubleValue();
|
||||
//усредняем измеренное напряжение
|
||||
double Uread = (dp1.getValue(parnames[1]).doubleValue() + dp2.getValue(parnames[1]).doubleValue()) / 2;
|
||||
|
||||
double t1 = dp1.getValue("Length").doubleValue();
|
||||
double t2 = dp2.getValue("Length").doubleValue();
|
||||
double time = t1 + t2;
|
||||
|
||||
long total = dp1.getValue(parnames[3]).intValue() + dp2.getValue(parnames[3]).intValue();
|
||||
long wind = dp1.getValue(parnames[4]).intValue() + dp2.getValue(parnames[4]).intValue();
|
||||
double corr = dp1.getValue(parnames[5]).doubleValue() + dp2.getValue(parnames[5]).doubleValue();
|
||||
|
||||
double cr1 = dp1.getValue("CR").doubleValue();
|
||||
double cr2 = dp2.getValue("CR").doubleValue();
|
||||
|
||||
double cr = (cr1 * t1 + cr2 * t2) / (t1 + t2);
|
||||
|
||||
double err1 = dp1.getDouble("CRerr");
|
||||
double err2 = dp2.getDouble("CRerr");
|
||||
|
||||
// абсолютные ошибки складываются квадратично
|
||||
double crErr = Math.sqrt(err1 * err1 * t1 * t1 + err2 * err2 * t2 * t2) / time;
|
||||
|
||||
MapDataPoint map = new MapDataPoint(parnames, Uset, Uread, time, total, wind, corr, cr, crErr);
|
||||
|
||||
if (dp1.names().contains("relCR") && dp2.names().contains("relCR")) {
|
||||
double relCR = (dp1.getDouble("relCR") + dp2.getDouble("relCR")) / 2;
|
||||
map.putValue("relCR", relCR);
|
||||
map.putValue("relCRerr", crErr * relCR / cr);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private DataSet mergeDataSets(String name, DataSet... ds) {
|
||||
//Сливаем все точки в один набор данных
|
||||
Map<Double, List<DataPoint>> points = new LinkedHashMap<>();
|
||||
for (DataSet d : ds) {
|
||||
if (!d.getDataFormat().contains(parnames)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
for (DataPoint dp : d) {
|
||||
double uset = dp.getValue(parnames[0]).doubleValue();
|
||||
if (!points.containsKey(uset)) {
|
||||
points.put(uset, new ArrayList<>());
|
||||
}
|
||||
points.get(uset).add(dp);
|
||||
}
|
||||
}
|
||||
|
||||
List<DataPoint> res = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<Double, List<DataPoint>> entry : points.entrySet()) {
|
||||
DataPoint curPoint = null;
|
||||
for (DataPoint newPoint : entry.getValue()) {
|
||||
curPoint = mergeDataPoints(curPoint, newPoint);
|
||||
}
|
||||
res.add(curPoint);
|
||||
}
|
||||
|
||||
return new ListDataSet(name, null, res);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.actions.ActionResult;
|
||||
import hep.dataforge.actions.OneToOneAction;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.data.DataPoint;
|
||||
import hep.dataforge.data.DataSet;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.description.ValueDef;
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.exceptions.ContentException;
|
||||
import hep.dataforge.io.ColumnedDataWriter;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import hep.dataforge.values.Value;
|
||||
import java.io.OutputStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
@TypedActionDef(name = "monitor", inputType = DataSet.class, outputType = DataSet.class)
|
||||
@ValueDef(name = "monitorPoint", type = "UMBER", required = true, info = "The Uset for monitor point")
|
||||
@ValueDef(name = "monitorFile", info = "The outputfile for monitor points", def = "monitor.out")
|
||||
@ValueDef(name = "calculateRelative", info = "Calculate count rate relative to average monitor point", def = "false")
|
||||
public class MonitorCorrectAction extends OneToOneAction<DataSet, DataSet> {
|
||||
|
||||
private static final String[] monitorNames = {"Timestamp", "Total", "CR", "CRerr"};
|
||||
|
||||
CopyOnWriteArrayList<DataPoint> monitorPoints = new CopyOnWriteArrayList<>();
|
||||
|
||||
public MonitorCorrectAction(Context context, Meta an) {
|
||||
super(context, an);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSet execute(Logable log, Meta reader, DataSet sourceData) throws ContentException {
|
||||
|
||||
double monitor = reader.getDouble("monitorPoint", Double.NaN);
|
||||
|
||||
TreeMap<LocalDateTime, DataPoint> index = getMonitorIndex(monitor, sourceData);
|
||||
if (index.isEmpty()) {
|
||||
log.logError("No monitor points found");
|
||||
return sourceData;
|
||||
}
|
||||
double norm = 0;
|
||||
double totalAv = 0;
|
||||
String head = "";
|
||||
head += String.format("%20s\t%10s\t%s%n", "Timestamp", "Total", "CR in window");
|
||||
for (DataPoint dp : index.values()) {
|
||||
head += String.format("%20s\t%10d\t%g%n", getTime(dp).toString(), getTotal(dp), getCR(dp));
|
||||
norm += getCR(dp) / index.size();
|
||||
totalAv += getTotal(dp) / index.size();
|
||||
monitorPoints.add(dp);
|
||||
}
|
||||
|
||||
head += String.format("%20s\t%10g\t%g%n", "Average", totalAv, norm);
|
||||
|
||||
List<DataPoint> dataList = new ArrayList<>();
|
||||
|
||||
for (DataPoint dp : sourceData) {
|
||||
MapDataPoint point = new MapDataPoint(dp);
|
||||
point.putValue("Monitor", 1.0);
|
||||
if (!isMonitorPoint(monitor, dp) || index.isEmpty()) {
|
||||
LocalDateTime time = getTime(dp);
|
||||
Entry<LocalDateTime, DataPoint> previousMonitor = index.floorEntry(time);
|
||||
Entry<LocalDateTime, DataPoint> nextMonitor = index.ceilingEntry(time);
|
||||
|
||||
if (previousMonitor == null) {
|
||||
previousMonitor = nextMonitor;
|
||||
}
|
||||
|
||||
if (nextMonitor == null) {
|
||||
nextMonitor = previousMonitor;
|
||||
}
|
||||
|
||||
double p;
|
||||
// p = (getTime(dp).toEpochMilli() - previousMonitor.getKey().toEpochMilli())/
|
||||
p = 0.5;
|
||||
|
||||
double corrFactor = (getCR(previousMonitor.getValue()) * p + getCR(nextMonitor.getValue()) * (1 - p)) / norm;
|
||||
double corrErr = previousMonitor.getValue().getValue("CRerr").doubleValue() / getCR(previousMonitor.getValue());
|
||||
double pointErr = dp.getValue("CRerr").doubleValue() / getCR(dp);
|
||||
double err = Math.sqrt(corrErr * corrErr + pointErr * pointErr) * getCR(dp);
|
||||
|
||||
if (dp.names().contains("Monitor")) {
|
||||
point.putValue("Monitor", Value.of(dp.getValue("Monitor").doubleValue() / corrFactor));
|
||||
} else {
|
||||
point.putValue("Monitor", corrFactor);
|
||||
}
|
||||
point.putValue("CR", Value.of(dp.getValue("CR").doubleValue() / corrFactor));
|
||||
point.putValue("Window", Value.of(dp.getValue("Window").doubleValue() / corrFactor));
|
||||
point.putValue("Corrected", Value.of(dp.getValue("Corrected").doubleValue() / corrFactor));
|
||||
point.putValue("CRerr", Value.of(err));
|
||||
}
|
||||
if (meta().getBoolean("calculateRelative", false)) {
|
||||
point.putValue("relCR", point.getValue("CR").doubleValue() / norm);
|
||||
point.putValue("relCRerr", point.getValue("CRerr").doubleValue() / norm);
|
||||
}
|
||||
dataList.add(point);
|
||||
}
|
||||
|
||||
// DataFormat format;
|
||||
//
|
||||
// if (!dataList.isEmpty()) {
|
||||
// //Генерируем автоматический формат по первой строчке
|
||||
// format = DataFormat.of(dataList.get(0));
|
||||
// } else {
|
||||
// format = DataFormat.of(parnames);
|
||||
// }
|
||||
DataSet data = new ListDataSet(sourceData.getName(), sourceData.meta(), dataList);
|
||||
|
||||
OutputStream stream = buildActionOutput(data);
|
||||
|
||||
ColumnedDataWriter.writeDataSet(stream, data, head);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterAction(ActionResult<DataSet> pack) throws ContentException {
|
||||
printMonitorData();
|
||||
super.afterAction(pack);
|
||||
}
|
||||
|
||||
private void printMonitorData() {
|
||||
String monitorFileName = meta().getString("monitorFile", "monitor");
|
||||
OutputStream stream = buildActionOutput(monitorFileName);
|
||||
ListDataSet data = new ListDataSet("monitor", null, monitorPoints);
|
||||
ColumnedDataWriter.writeDataSet(stream, data.sort("Timestamp", true), "Monitor points", monitorNames);
|
||||
}
|
||||
|
||||
private boolean isMonitorPoint(double monitor, DataPoint point) {
|
||||
return point.getValue("Uset").doubleValue() == monitor;
|
||||
}
|
||||
|
||||
private LocalDateTime getTime(DataPoint point) {
|
||||
return LocalDateTime.ofInstant(point.getValue("Timestamp").timeValue(), ZoneId.of("GMT+3"));
|
||||
}
|
||||
|
||||
private int getTotal(DataPoint point) {
|
||||
return point.getValue("Total").intValue();
|
||||
}
|
||||
|
||||
private double getCR(DataPoint point) {
|
||||
return point.getValue("CR").doubleValue();
|
||||
}
|
||||
|
||||
private TreeMap<LocalDateTime, DataPoint> getMonitorIndex(double monitor, Iterable<DataPoint> data) {
|
||||
TreeMap<LocalDateTime, DataPoint> res = new TreeMap<>();
|
||||
for (DataPoint dp : data) {
|
||||
if (isMonitorPoint(monitor, dp)) {
|
||||
res.put(getTime(dp), dp);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.actions.OneToOneAction;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.description.ValueDef;
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.data.DataFormat;
|
||||
import hep.dataforge.data.DataPoint;
|
||||
import hep.dataforge.data.DataSet;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.exceptions.ContentException;
|
||||
import hep.dataforge.io.ColumnedDataWriter;
|
||||
import hep.dataforge.io.XMLMetaWriter;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import inr.numass.data.NMFile;
|
||||
import inr.numass.data.NMPoint;
|
||||
import inr.numass.data.RawNMPoint;
|
||||
import java.io.OutputStream;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
@TypedActionDef(name = "prepareData", inputType = NMFile.class, outputType = DataSet.class)
|
||||
@ValueDef(name = "lowerWindow", type = "NUMBER", def = "0", info = "Base for the window lowerWindow bound")
|
||||
@ValueDef(name = "lowerWindowSlope", type = "NUMBER", def = "0", info = "Slope for the window lowerWindow bound")
|
||||
@ValueDef(name = "upperWindow", type = "NUMBER", info = "Upper bound for window")
|
||||
@ValueDef(name = "deadTime", type = "NUMBER", def = "0", info = "Dead time in us")
|
||||
public class PrepareDataAction extends OneToOneAction<NMFile, DataSet> {
|
||||
|
||||
public static String[] parnames = {"Uset", "Uread", "Length", "Total", "Window", "Corrected", "CR", "CRerr", "Timestamp"};
|
||||
|
||||
public PrepareDataAction(Context context, Meta an) {
|
||||
super(context, an);
|
||||
}
|
||||
|
||||
private int getLowerBorder(Meta source, double Uset) throws ContentException {
|
||||
double b = source.getDouble("lowerWindow", this.meta().getDouble("lowerWindow", 0));
|
||||
double a = source.getDouble("lowerWindowSlope", this.meta().getDouble("lowerWindowSlope", 0));
|
||||
|
||||
return (int) (b + Uset * a);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListDataSet execute(Logable log, Meta reader, NMFile dataFile) throws ContentException {
|
||||
// log.logString("File %s started", dataFile.getName());
|
||||
|
||||
int upper = dataFile.meta().getInt("upperWindow", this.meta().getInt("upperWindow", RawNMPoint.MAX_CHANEL - 1));
|
||||
|
||||
double deadTime = dataFile.meta().getDouble("deadTime", this.meta().getDouble("deadTime", 0));
|
||||
// double bkg = source.meta().getDouble("background", this.meta().getDouble("background", 0));
|
||||
|
||||
List<DataPoint> dataList = new ArrayList<>();
|
||||
for (NMPoint point : dataFile.getNMPoints()) {
|
||||
|
||||
long total = point.getEventsCount();
|
||||
double Uset = point.getUset();
|
||||
double Uread = point.getUread();
|
||||
double time = point.getLength();
|
||||
int a = getLowerBorder(dataFile.meta(), Uset);
|
||||
int b = Math.min(upper, RawNMPoint.MAX_CHANEL);
|
||||
|
||||
// analyzer.setMonitorCorrector(corrector);
|
||||
long wind = point.getCountInWindow(a, b);
|
||||
|
||||
double corr = point.getCountRate(a, b, deadTime) * point.getLength();// - bkg * (b - a);
|
||||
|
||||
double cr = point.getCountRate(a, b, deadTime);
|
||||
double crErr = point.getCountRateErr(a, b, deadTime);
|
||||
|
||||
Instant timestamp = point.getAbsouteTime().toInstant(ZoneOffset.UTC);
|
||||
|
||||
dataList.add(new MapDataPoint(parnames, new Object[]{Uset, Uread, time, total, wind, corr, cr, crErr, timestamp}));
|
||||
}
|
||||
|
||||
DataFormat format;
|
||||
|
||||
if (!dataList.isEmpty()) {
|
||||
//Генерируем автоматический формат по первой строчке
|
||||
format = DataFormat.forPoint(dataList.get(0));
|
||||
} else {
|
||||
format = DataFormat.forNames(8, parnames);
|
||||
}
|
||||
|
||||
// AnnotationBuilder builder = dataFile.meta().getBuilder();
|
||||
String head;
|
||||
if (dataFile.getHead() != null) {
|
||||
head = dataFile.getHead();
|
||||
// builder.putValue("datafilehead",head);
|
||||
} else {
|
||||
head = dataFile.getName();
|
||||
}
|
||||
head = head + "\n" + new XMLMetaWriter().writeString(meta(), null) + "\n";
|
||||
|
||||
ListDataSet data = new ListDataSet(dataFile.getName(), dataFile.meta(), dataList, format);
|
||||
|
||||
OutputStream stream = buildActionOutput(data);
|
||||
|
||||
ColumnedDataWriter.writeDataSet(stream, data, head);
|
||||
// log.logString("File %s completed", dataFile.getName());
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.actions.OneToOneAction;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.description.NodeDef;
|
||||
import hep.dataforge.description.ValueDef;
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.data.FileData;
|
||||
import hep.dataforge.exceptions.ContentException;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import static inr.numass.NumassIO.getNumassData;
|
||||
import inr.numass.data.NMFile;
|
||||
import inr.numass.data.RawNMFile;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
@TypedActionDef(name = "readData",
|
||||
inputType = FileData.class, outputType = NMFile.class, description = "Read binary numass data file")
|
||||
@ValueDef(name = "fileName", info = "The name of the file. By default equals file name.")
|
||||
@ValueDef(name = "HVdev", info = "Divider for HV measurements. Should be set to 1.0 for numass data 2014",
|
||||
def = "2.468555393226049", type = "NUMBER")
|
||||
@ValueDef(name = "noUset", info = "If 'true', then Uset = Uread")
|
||||
@NodeDef(name = "debunch", target = "class::inr.numass.actions.DebunchAction", info = "If given, governs debunching")
|
||||
public class ReadNumassDataAction extends OneToOneAction<FileData, NMFile> {
|
||||
|
||||
public ReadNumassDataAction(Context context, Meta an) {
|
||||
super(context, an);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NMFile execute(Logable log, Meta reader, FileData source) throws ContentException {
|
||||
// log.logString("File '%s' started", source.getName());
|
||||
RawNMFile raw = getNumassData(source, meta());
|
||||
if (meta().getBoolean("paw", false)) {
|
||||
raw.generatePAW(buildActionOutput(source.getName() + ".paw"));
|
||||
}
|
||||
|
||||
if(meta().hasNode("debunch")){
|
||||
DebunchAction debunch = new DebunchAction(getContext(), meta().getNode("debunch"));
|
||||
raw = debunch.execute(log, null, raw);
|
||||
}
|
||||
|
||||
NMFile result = new NMFile(raw);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.actions.OneToOneAction;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.data.DataSet;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.datafitter.FitState;
|
||||
import hep.dataforge.datafitter.FitTaskResult;
|
||||
import hep.dataforge.datafitter.Param;
|
||||
import hep.dataforge.datafitter.ParamSet;
|
||||
import hep.dataforge.datafitter.models.Histogram;
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.io.ColumnedDataWriter;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import hep.dataforge.io.PrintFunction;
|
||||
import hep.dataforge.maths.GridCalculator;
|
||||
import hep.dataforge.maths.NamedDoubleSet;
|
||||
import hep.dataforge.maths.NamedMatrix;
|
||||
import hep.dataforge.maths.integration.UnivariateIntegrator;
|
||||
import hep.dataforge.meta.MetaBuilder;
|
||||
import hep.dataforge.plots.PlotFrame;
|
||||
import hep.dataforge.plots.PlotsPlugin;
|
||||
import hep.dataforge.plots.XYPlotFrame;
|
||||
import hep.dataforge.plots.data.PlottableData;
|
||||
import hep.dataforge.plots.data.PlottableFunction;
|
||||
import hep.dataforge.simulation.GaussianParameterGenerator;
|
||||
import inr.numass.NumassContext;
|
||||
import inr.numass.models.ExperimentalVariableLossSpectrum;
|
||||
import inr.numass.models.LossCalculator;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import org.apache.commons.math3.analysis.UnivariateFunction;
|
||||
import org.apache.commons.math3.analysis.interpolation.LinearInterpolator;
|
||||
import org.apache.commons.math3.analysis.interpolation.UnivariateInterpolator;
|
||||
import org.apache.commons.math3.stat.StatUtils;
|
||||
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author darksnake
|
||||
*/
|
||||
@TypedActionDef(name = "showLoss", inputType = FitState.class, outputType = FitState.class,
|
||||
description = "Show loss spectrum for fit with loss model. Calculate excitation to ionisation ratio.")
|
||||
public class ShowLossSpectrumAction extends OneToOneAction<FitState, FitState> {
|
||||
|
||||
private static final String[] names = {"X", "exPos", "ionPos", "exW", "ionW", "exIonRatio"};
|
||||
|
||||
public ShowLossSpectrumAction(Context context, Meta annotation) {
|
||||
super(context, annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FitState execute(Logable log, Meta reader, FitState input) {
|
||||
ParamSet pars = input.getParameters();
|
||||
if (!pars.names().contains(names)) {
|
||||
LoggerFactory.getLogger(getClass()).error("Wrong input FitState. Must be loss spectrum fit.");
|
||||
throw new RuntimeException("Wrong input FitState");
|
||||
}
|
||||
|
||||
UnivariateFunction scatterFunction;
|
||||
boolean calculateRatio = false;
|
||||
XYPlotFrame frame = (XYPlotFrame) PlotsPlugin.buildFrom(getContext())
|
||||
.buildPlotFrame(getName(), input.getName()+".loss",
|
||||
new MetaBuilder("plot")
|
||||
.setValue("plotTitle", "Differential scattering crossection for " + input.getName())
|
||||
);
|
||||
switch (input.getModel().getName()) {
|
||||
case "scatter-variable":
|
||||
scatterFunction = LossCalculator.getSingleScatterFunction(pars);
|
||||
calculateRatio = true;
|
||||
|
||||
LossCalculator.plotScatter(frame, pars);
|
||||
break;
|
||||
case "scatter-empiric-experimental":
|
||||
scatterFunction = new ExperimentalVariableLossSpectrum.Loss(0.3).total(pars);
|
||||
|
||||
frame.add(new PlottableFunction("Cross-section", null, scatterFunction, 0, 100, 1000));
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Can work only with variable loss spectra");
|
||||
}
|
||||
|
||||
double threshold = 0;
|
||||
double ionRatio = -1;
|
||||
double ionRatioError = -1;
|
||||
if (calculateRatio) {
|
||||
threshold = reader.getDouble("ionThreshold", 17);
|
||||
ionRatio = calcultateIonRatio(pars, threshold);
|
||||
log.log("The ionization ratio (using threshold {}) is {}", threshold, ionRatio);
|
||||
ionRatioError = calultateIonRatioError(input, threshold);
|
||||
log.log("the ionization ration standard deviation (using threshold {}) is {}", threshold, ionRatioError);
|
||||
}
|
||||
|
||||
if (reader.getBoolean("printResult", false)) {
|
||||
PrintWriter writer = new PrintWriter(new OutputStreamWriter(buildActionOutput(input), Charset.forName("UTF-8")));
|
||||
// writer.println("*** FIT PARAMETERS ***");
|
||||
input.print(writer);
|
||||
// for (Param param : pars.getSubSet(names).getParams()) {
|
||||
// writer.println(param.toString());
|
||||
// }
|
||||
// writer.println();
|
||||
// out.printf("Chi squared over degrees of freedom: %g/%d = %g", input.getChi2(), input.ndf(), chi2 / this.ndf());
|
||||
|
||||
writer.println();
|
||||
|
||||
writer.println("*** LOSS SPECTRUM INFORMATION ***");
|
||||
writer.println();
|
||||
|
||||
if (calculateRatio) {
|
||||
writer.printf("The ionization ratio (using threshold %f) is %f%n", threshold, ionRatio);
|
||||
writer.printf("The ionization ratio standard deviation (using threshold %f) is %f%n", threshold, ionRatioError);
|
||||
writer.println();
|
||||
}
|
||||
|
||||
// double integralThreshold = reader.getDouble("numass.eGun", 19005d) - reader.getDouble("integralThreshold", 14.82);
|
||||
// double integralRatio = calculateIntegralExIonRatio(input.getDataSet(), input.getParameters().getValue("X"), integralThreshold);
|
||||
// writer.printf("The excitation to ionization ratio from integral spectrum (using threshold %f) is %f%n", integralThreshold, integralRatio);
|
||||
writer.println();
|
||||
|
||||
writer.println("*** SUMMARY ***");
|
||||
|
||||
writer.printf("%s\t", "name");
|
||||
|
||||
for (String parName : names) {
|
||||
writer.printf("%s\t%s\t", parName, parName + "_err");
|
||||
}
|
||||
if (calculateRatio) {
|
||||
writer.printf("%s\t", "ionRatio");
|
||||
writer.printf("%s\t", "ionRatioErr");
|
||||
}
|
||||
writer.printf("%s%n", "chi2");
|
||||
|
||||
writer.printf("%s\t", input.getName());
|
||||
|
||||
for (Param param : pars.getSubSet(names).getParams()) {
|
||||
writer.printf("%f\t%f\t", param.value(), param.getErr());
|
||||
}
|
||||
|
||||
if (calculateRatio) {
|
||||
writer.printf("%f\t", ionRatio);
|
||||
writer.printf("%f\t", ionRatioError);
|
||||
}
|
||||
|
||||
writer.printf("%f%n", input.getChi2() / ((FitTaskResult) input).ndf());
|
||||
writer.println();
|
||||
|
||||
writer.println("***LOSS SPECTRUM***");
|
||||
writer.println();
|
||||
PrintFunction.printFunctionSimple(writer, scatterFunction, 0, 100, 500);
|
||||
|
||||
if (meta().getBoolean("showSpread", false)) {
|
||||
writer.println("***SPECTRUM SPREAD***");
|
||||
writer.println();
|
||||
|
||||
ParamSet parameters = input.getParameters().getSubSet(new String[]{"exPos", "ionPos", "exW", "ionW", "exIonRatio"});
|
||||
NamedMatrix covariance = input.getCovariance();
|
||||
DataSet spreadData = generateSpread(writer, input.getName(), parameters, covariance);
|
||||
ColumnedDataWriter.writeDataSet(System.out, spreadData, "", spreadData.getDataFormat().asArray());
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
public static double calcultateIonRatio(NamedDoubleSet set, double threshold) {
|
||||
UnivariateIntegrator integrator = NumassContext.highDensityIntegrator;
|
||||
UnivariateFunction integrand = LossCalculator.getSingleScatterFunction(set);
|
||||
return 1d - integrator.integrate(integrand, 5d, threshold);
|
||||
}
|
||||
|
||||
private double calculateIntegralExIonRatio(DataSet data, double X, double integralThreshold) {
|
||||
double scatterProb = 1 - Math.exp(-X);
|
||||
|
||||
double[] x = data.getColumn("Uset").asList().stream().mapToDouble((val) -> val.doubleValue()).toArray();
|
||||
double[] y = data.getColumn("CR").asList().stream().mapToDouble((val) -> val.doubleValue()).toArray();
|
||||
|
||||
double yMax = StatUtils.max(y);
|
||||
|
||||
UnivariateInterpolator interpolator = new LinearInterpolator();
|
||||
UnivariateFunction interpolated = interpolator.interpolate(x, y);
|
||||
|
||||
double thresholdValue = interpolated.value(integralThreshold);
|
||||
|
||||
double one = 1 - X * Math.exp(-X);
|
||||
|
||||
double ionProb = (one - thresholdValue / yMax);
|
||||
double exProb = (thresholdValue / yMax - one + scatterProb);
|
||||
return exProb / ionProb;
|
||||
}
|
||||
|
||||
public double calultateIonRatioError(FitState state, double threshold) {
|
||||
ParamSet parameters = state.getParameters().getSubSet(new String[]{"exPos", "ionPos", "exW", "ionW", "exIonRatio"});
|
||||
NamedMatrix covariance = state.getCovariance();
|
||||
return calultateIonRatioError(state.getName(), parameters, covariance, threshold);
|
||||
}
|
||||
|
||||
@SuppressWarnings("Unchecked")
|
||||
public double calultateIonRatioError(String name, NamedDoubleSet parameters, NamedMatrix covariance, double threshold) {
|
||||
int number = 10000;
|
||||
|
||||
double[] res = new GaussianParameterGenerator(parameters, covariance)
|
||||
.generate(number)
|
||||
.stream()
|
||||
.mapToDouble((vector) -> calcultateIonRatio(vector, threshold))
|
||||
.filter(d -> !Double.isNaN(d))
|
||||
.toArray();
|
||||
|
||||
Histogram hist = new Histogram("ionRatio", 0.3, 0.5, 0.002);
|
||||
hist.fill(res);
|
||||
XYPlotFrame frame = (XYPlotFrame) PlotsPlugin.buildFrom(getContext())
|
||||
.buildPlotFrame(getName(), name+".ionRatio",
|
||||
new MetaBuilder("plot").setValue("plotTitle", "Ion ratio Distribution for " + name)
|
||||
);
|
||||
// XYPlotFrame frame = JFreeChartFrame.drawFrame("Ion ratio Distribution for " + name, null);
|
||||
frame.add(new PlottableData(hist, "binCenter", "count"));
|
||||
|
||||
return new DescriptiveStatistics(res).getStandardDeviation();
|
||||
}
|
||||
|
||||
public static DataSet generateSpread(PrintWriter writer, String name, NamedDoubleSet parameters, NamedMatrix covariance) {
|
||||
int numCalls = 1000;
|
||||
int gridPoints = 200;
|
||||
double a = 8;
|
||||
double b = 32;
|
||||
|
||||
double[] grid = GridCalculator.getUniformUnivariateGrid(a, b, gridPoints);
|
||||
|
||||
double[] upper = new double[gridPoints];
|
||||
double[] lower = new double[gridPoints];
|
||||
double[] dispersion = new double[gridPoints];
|
||||
|
||||
double[] central = new double[gridPoints];
|
||||
|
||||
UnivariateFunction func = LossCalculator.getSingleScatterFunction(parameters);
|
||||
for (int j = 0; j < gridPoints; j++) {
|
||||
central[j] = func.value(grid[j]);
|
||||
}
|
||||
|
||||
Arrays.fill(upper, Double.NEGATIVE_INFINITY);
|
||||
Arrays.fill(lower, Double.POSITIVE_INFINITY);
|
||||
Arrays.fill(dispersion, 0);
|
||||
|
||||
GaussianParameterGenerator generator = new GaussianParameterGenerator(parameters, covariance);
|
||||
|
||||
for (int i = 0; i < numCalls; i++) {
|
||||
func = LossCalculator.getSingleScatterFunction(generator.generate());
|
||||
for (int j = 0; j < gridPoints; j++) {
|
||||
double val = func.value(grid[j]);
|
||||
upper[j] = Math.max(upper[j], val);
|
||||
lower[j] = Math.min(lower[j], val);
|
||||
dispersion[j] += (val - central[j]) * (val - central[j]) / numCalls;
|
||||
}
|
||||
}
|
||||
String[] pointNames = {"e", "central", "lower", "upper", "dispersion"};
|
||||
ListDataSet res = new ListDataSet("spread", pointNames);
|
||||
for (int i = 0; i < gridPoints; i++) {
|
||||
res.add(new MapDataPoint(pointNames, grid[i], central[i], lower[i], upper[i], dispersion[i]));
|
||||
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.actions.OneToOneAction;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.exceptions.ContentException;
|
||||
import hep.dataforge.io.ColumnedDataWriter;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||
import inr.numass.data.ESpectrum;
|
||||
import inr.numass.data.NMFile;
|
||||
import inr.numass.data.NMPoint;
|
||||
import java.awt.Color;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.jfree.chart.JFreeChart;
|
||||
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
||||
import org.jfree.data.xy.XYSeries;
|
||||
import org.jfree.data.xy.XYSeriesCollection;
|
||||
import org.jfree.ui.RectangleEdge;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
@TypedActionDef(name = "showSpectrum", inputType = NMFile.class, outputType = NMFile.class)
|
||||
public class ShowSpectrumAction extends OneToOneAction<NMFile, NMFile> {
|
||||
|
||||
public ShowSpectrumAction(Context context, Meta an) {
|
||||
super(context, an);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NMFile execute(Logable log, Meta reader, NMFile source) throws ContentException {
|
||||
log.log("File {} started", source.getName());
|
||||
|
||||
List<NMPoint> printPoints = new ArrayList<>();
|
||||
List<NMPoint> showPoints = new ArrayList<>();
|
||||
|
||||
for (NMPoint point : source.getNMPoints()) {
|
||||
if (toPrint(point)) {
|
||||
printPoints.add(point);
|
||||
}
|
||||
if (toShow(point)) {
|
||||
showPoints.add(point);
|
||||
}
|
||||
}
|
||||
|
||||
int chanelsPerBin = meta().getInt("binning", 1); // биннинг
|
||||
boolean normalize = meta().getBoolean("normalize", false); // нормировка на время набора точки
|
||||
|
||||
if (showPoints.size() > 0) {
|
||||
showSpectra(showPoints, source.getName(), chanelsPerBin, normalize);
|
||||
}
|
||||
|
||||
if (printPoints.size() > 0) {
|
||||
ESpectrum data = new ESpectrum(source.getName(), printPoints, chanelsPerBin, normalize);
|
||||
|
||||
OutputStream stream = buildActionOutput(data);
|
||||
|
||||
ColumnedDataWriter.writeDataSet(stream, data, source.getName());
|
||||
|
||||
}
|
||||
|
||||
log.log("File {} completed", source.getName());
|
||||
return source;
|
||||
}
|
||||
|
||||
private boolean toPrint(NMPoint point) throws ContentException {
|
||||
Meta root = this.meta();
|
||||
|
||||
if (root.hasNode("print")) {
|
||||
List<? extends Meta> cfg = meta().getNodes("print");
|
||||
boolean res = false;
|
||||
for (Meta e : cfg) {
|
||||
double from = e.getDouble("from", 0);
|
||||
double to = e.getDouble("to", Double.POSITIVE_INFINITY);
|
||||
res = res || ((point.getUset() >= from) && (point.getUset() <= to));
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return root.getBoolean("print", false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean toShow(NMPoint point) throws ContentException {
|
||||
Meta root = this.meta();
|
||||
|
||||
if (root.hasNode("show")) {
|
||||
List<? extends Meta> cfg = meta().getNodes("show");
|
||||
boolean res = false;
|
||||
for (Meta e : cfg) {
|
||||
double from = e.getDouble("from", 0);
|
||||
double to = e.getDouble("to", Double.POSITIVE_INFINITY);
|
||||
res = res || ((point.getUset() >= from) && (point.getUset() <= to));
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return root.getBoolean("show", false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void showSpectra(List<NMPoint> points, String head, int binning, boolean normalize) {
|
||||
XYSeriesCollection dataset = new XYSeriesCollection();
|
||||
|
||||
for (NMPoint point : points) {
|
||||
Map<Double, Double> spectrum = point.getMapWithBinning(binning, normalize);
|
||||
|
||||
String serName = Double.toString(point.getUset());
|
||||
XYSeries ser;
|
||||
if (dataset.getSeriesIndex(serName) >= 0) {
|
||||
serName = serName + " " + Integer.toString(points.indexOf(point));
|
||||
}
|
||||
ser = new XYSeries(serName);
|
||||
for (Map.Entry<Double, Double> sp : spectrum.entrySet()) {
|
||||
ser.add(sp.getKey(), sp.getValue());
|
||||
}
|
||||
|
||||
dataset.addSeries(ser);
|
||||
}
|
||||
|
||||
showSpectra(dataset, head, binning, normalize);
|
||||
|
||||
}
|
||||
|
||||
private static void showSpectra(XYSeriesCollection dataset, String head, int binning, boolean normalize) {
|
||||
|
||||
String axisName = "count";
|
||||
if (normalize) {
|
||||
axisName += " rate";
|
||||
} else {
|
||||
axisName += " number";
|
||||
}
|
||||
|
||||
if (binning != 1) {
|
||||
axisName += " per " + binning + " chanels";
|
||||
}
|
||||
|
||||
JFreeChartFrame frame = JFreeChartFrame.drawFrame(head, null);
|
||||
|
||||
frame.getYAxisConfig().putValue("title", axisName);
|
||||
|
||||
JFreeChart chart = frame.getChart();
|
||||
|
||||
chart.getXYPlot().setDataset(dataset);
|
||||
|
||||
chart.getXYPlot().setRenderer(new XYLineAndShapeRenderer(true, false));
|
||||
|
||||
chart.getLegend().setPosition(RectangleEdge.RIGHT);
|
||||
chart.getXYPlot().setDomainGridlinesVisible(true);
|
||||
chart.getXYPlot().setRangeGridlinesVisible(true);
|
||||
chart.getXYPlot().setDomainGridlinePaint(Color.BLACK);
|
||||
chart.getXYPlot().setRangeGridlinePaint(Color.BLACK);
|
||||
}
|
||||
|
||||
}
|
91
numass-main/src/main/java/inr/numass/actions/SlicedData.java
Normal file
91
numass-main/src/main/java/inr/numass/actions/SlicedData.java
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.data.DataFormat;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.values.Value;
|
||||
import inr.numass.data.NMFile;
|
||||
import inr.numass.data.NMPoint;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.math3.util.Pair;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class SlicedData extends ListDataSet {
|
||||
private static final String TNAME = "Time";
|
||||
//format = {U,username1,username2, ...}
|
||||
private static final String UNAME = "U";
|
||||
|
||||
|
||||
private static DataFormat prepateFormat(Map<String,Pair<Integer,Integer>> intervals){
|
||||
ArrayList<String> names = new ArrayList<>(intervals.keySet());
|
||||
names.add(0, TNAME);
|
||||
names.add(0, UNAME);
|
||||
return DataFormat.forNames(8, names);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public SlicedData(NMFile file, Map<String,Pair<Integer,Integer>> intervals, boolean normalize) {
|
||||
super(prepateFormat(intervals));
|
||||
fill(file, intervals, normalize);
|
||||
}
|
||||
|
||||
private void fill(NMFile file, Map<String,Pair<Integer,Integer>> intervals, boolean normalize){
|
||||
for (NMPoint point : file.getNMPoints()) {
|
||||
|
||||
//создаем основу для будущей точки
|
||||
HashMap<String,Value> map = new HashMap<>();
|
||||
|
||||
//Кладем напряжение
|
||||
map.put(UNAME, Value.of(point.getUset()));
|
||||
double t = point.getLength();
|
||||
map.put(TNAME, Value.of(t));
|
||||
|
||||
for (Map.Entry<String, Pair<Integer, Integer>> entry : intervals.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
Pair<Integer, Integer> pair = entry.getValue();
|
||||
int a = pair.getFirst();
|
||||
int b = pair.getSecond();
|
||||
|
||||
int count;
|
||||
// проверяем порядок границ и переворачиваем если нужно
|
||||
if(b>a){
|
||||
count = point.getCountInWindow(a, b);
|
||||
} else if(b<a) {
|
||||
count = point.getCountInWindow(b, a);
|
||||
} else{
|
||||
count = point.getCountInChanel(a);
|
||||
}
|
||||
//пихаем все в map
|
||||
if(normalize){
|
||||
map.put(name, Value.of(count/t));
|
||||
} else {
|
||||
map.put(name, Value.of(count));
|
||||
}
|
||||
}
|
||||
this.add(new MapDataPoint(map));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.actions.OneToOneAction;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.exceptions.ContentException;
|
||||
import hep.dataforge.io.ColumnedDataWriter;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import inr.numass.data.NMFile;
|
||||
import inr.numass.data.RawNMPoint;
|
||||
import java.io.OutputStream;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.math3.util.Pair;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
@TypedActionDef(name = "slicing", inputType = NMFile.class, outputType = NMFile.class)
|
||||
public class SlicingAction extends OneToOneAction<NMFile, NMFile> {
|
||||
|
||||
public static final String name = "slicing";
|
||||
|
||||
public SlicingAction(Context context, Meta an) {
|
||||
super(context, an);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NMFile execute(Logable log, Meta reader, NMFile source) throws ContentException {
|
||||
boolean normalize;
|
||||
Map<String, Pair<Integer, Integer>> slicingConfig;
|
||||
|
||||
LinkedHashMap<String, Pair<Integer, Integer>> res = new LinkedHashMap<>();
|
||||
List<? extends Meta> list = meta().getNode("sliceconfig").getNodes("slicepoint");
|
||||
|
||||
for (Meta slice : list) {
|
||||
String title = slice.getString("title", slice.getName());
|
||||
int from = slice.getInt("from", 0);
|
||||
int to = slice.getInt("to", RawNMPoint.MAX_CHANEL);
|
||||
res.put(title, new Pair<>(from, to));
|
||||
}
|
||||
slicingConfig = res;
|
||||
|
||||
normalize = meta().getBoolean("normalize", false);
|
||||
|
||||
if (slicingConfig == null) {
|
||||
throw new RuntimeException("Slice configuration not defined");
|
||||
}
|
||||
log.log("File {} started", source.getName());
|
||||
|
||||
SlicedData sData = new SlicedData(source, slicingConfig, normalize);
|
||||
|
||||
OutputStream stream = buildActionOutput(source);
|
||||
|
||||
ColumnedDataWriter.writeDataSet(stream, sData, null);
|
||||
|
||||
log.log("File {} completed", source.getName());
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
}
|
117
numass-main/src/main/java/inr/numass/actions/SummaryAction.java
Normal file
117
numass-main/src/main/java/inr/numass/actions/SummaryAction.java
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.actions;
|
||||
|
||||
import hep.dataforge.actions.ManyToOneAction;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.content.NamedGroup;
|
||||
import hep.dataforge.content.GroupBuilder;
|
||||
import hep.dataforge.description.TypedActionDef;
|
||||
import hep.dataforge.context.Context;
|
||||
import hep.dataforge.data.DataFormat;
|
||||
import hep.dataforge.data.DataPoint;
|
||||
import hep.dataforge.data.DataSet;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.values.Value;
|
||||
import hep.dataforge.datafitter.FitState;
|
||||
import hep.dataforge.io.ColumnedDataWriter;
|
||||
import hep.dataforge.io.log.Logable;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
@TypedActionDef(name = "summary", inputType = FitState.class, outputType = DataSet.class, description = "Generate summary for fit results of different datasets.")
|
||||
public class SummaryAction extends ManyToOneAction<FitState, DataSet> {
|
||||
|
||||
public static final String SUMMARY_NAME = "sumName";
|
||||
|
||||
public SummaryAction(Context context, Meta annotation) {
|
||||
super(context, annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<NamedGroup<FitState>> buildGroups(Meta reader, List<FitState> input) {
|
||||
List<NamedGroup<FitState>> groups;
|
||||
if (reader.hasNode("grouping")) {
|
||||
groups = super.buildGroups(reader, input);
|
||||
} else {
|
||||
groups = GroupBuilder.byValue(SUMMARY_NAME, reader.getString(SUMMARY_NAME, "summary")).group(input);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataSet execute(Logable log, Meta reader, NamedGroup<FitState> input){
|
||||
String[] parNames = meta().getStringArray("parnames");
|
||||
String[] names = new String[2 * parNames.length + 2];
|
||||
names[0] = "file";
|
||||
for (int i = 0; i < parNames.length; i++) {
|
||||
names[2 * i + 1] = parNames[i];
|
||||
names[2 * i + 2] = parNames[i] + "Err";
|
||||
}
|
||||
names[names.length - 1] = "chi2";
|
||||
|
||||
// boolean calculateWAV = meta().getBoolean("wav", true);
|
||||
String fileName = reader.getString(SUMMARY_NAME, "summary");
|
||||
|
||||
ListDataSet res = new ListDataSet(fileName, DataFormat.forNames(8, names));
|
||||
|
||||
double[] weights = new double[parNames.length];
|
||||
Arrays.fill(weights, 0);
|
||||
double[] av = new double[parNames.length];
|
||||
Arrays.fill(av, 0);
|
||||
|
||||
for (FitState state : input) {
|
||||
Value[] values = new Value[names.length];
|
||||
values[0] = Value.of(state.getName());
|
||||
for (int i = 0; i < parNames.length; i++) {
|
||||
Value val = Value.of(state.getParameters().getValue(parNames[i]));
|
||||
values[2 * i + 1] = val;
|
||||
Value err = Value.of(state.getParameters().getError(parNames[i]));
|
||||
values[2 * i + 2] = err;
|
||||
double weight = 1 / err.doubleValue() / err.doubleValue();
|
||||
av[i] += val.doubleValue() * weight;
|
||||
weights[i] += weight;
|
||||
}
|
||||
values[values.length - 1] = Value.of(state.getChi2());
|
||||
DataPoint point = new MapDataPoint(names, values);
|
||||
res.add(point);
|
||||
}
|
||||
|
||||
Value[] averageValues = new Value[names.length];
|
||||
averageValues[0] = Value.of("average");
|
||||
averageValues[averageValues.length - 1] = Value.of(0);
|
||||
|
||||
for (int i = 0; i < parNames.length; i++) {
|
||||
averageValues[2 * i + 1] = Value.of(av[i] / weights[i]);
|
||||
averageValues[2 * i + 2] = Value.of(1 / Math.sqrt(weights[i]));
|
||||
}
|
||||
|
||||
res.add(new MapDataPoint(names, averageValues));
|
||||
|
||||
OutputStream stream = buildActionOutput(res);
|
||||
|
||||
ColumnedDataWriter.writeDataSet(stream, res, fileName);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
89
numass-main/src/main/java/inr/numass/data/ESpectrum.java
Normal file
89
numass-main/src/main/java/inr/numass/data/ESpectrum.java
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.data;
|
||||
|
||||
import hep.dataforge.data.DataFormat;
|
||||
import hep.dataforge.data.ListDataSet;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import hep.dataforge.values.Value;
|
||||
import hep.dataforge.values.ValueFormat;
|
||||
import hep.dataforge.values.ValueFormatFactory;
|
||||
import hep.dataforge.values.ValueType;
|
||||
import hep.dataforge.io.ColumnedDataWriter;
|
||||
import java.io.OutputStream;
|
||||
import static java.lang.String.format;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class ESpectrum extends ListDataSet {
|
||||
|
||||
private final static String binCenter = "chanel";
|
||||
|
||||
private static DataFormat prepareFormat(List<NMPoint> points) {
|
||||
// ArrayList<String> names = new ArrayList<>();
|
||||
// names.add(binCenter);
|
||||
Map<String, ValueFormat> format = new LinkedHashMap<>();
|
||||
format.put(binCenter, ValueFormatFactory.forType(ValueType.STRING));
|
||||
for (NMPoint point : points) {
|
||||
// names.add(format("%.3f", point.getUread()));
|
||||
format.put(format("%.3f", point.getUread()), ValueFormatFactory.fixedWidth(10));
|
||||
}
|
||||
|
||||
return new DataFormat(format);
|
||||
}
|
||||
|
||||
int binning = 1;
|
||||
|
||||
public ESpectrum(String name, List<NMPoint> points, int binning, boolean normalize) {
|
||||
super(name, prepareFormat(points));
|
||||
this.binning = binning;
|
||||
fill(points, normalize);
|
||||
}
|
||||
|
||||
private void fill(List<NMPoint> points, boolean normalize) {
|
||||
assert !points.isEmpty();
|
||||
|
||||
List<Map<Double, Double>> spectra = new ArrayList<>();
|
||||
|
||||
for (NMPoint numassPoint : points) {
|
||||
spectra.add(numassPoint.getMapWithBinning(binning, normalize));
|
||||
}
|
||||
|
||||
for (Double x : spectra.get(0).keySet()) {
|
||||
Map<String, Value> res = new HashMap<>();
|
||||
res.put(binCenter, Value.of(x));
|
||||
for (int j = 0; j < points.size(); j++) {
|
||||
res.put(format("%.3f", points.get(j).getUread()), Value.of(spectra.get(j).get(x)));
|
||||
}
|
||||
this.add(new MapDataPoint(res));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void printToFile(OutputStream stream) {
|
||||
ColumnedDataWriter.writeDataSet(stream, this, null);
|
||||
// new ColumnedDataWriter(stream, this.getDataFormat().asArray()).writeDataSet(this, null);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.data;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
|
||||
/**
|
||||
* инструменты для работы с энергитическим спектром (который в каналах)
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class ESpectrumUtils {
|
||||
public static int[] substract(int[] sp1, int[] sp2) {
|
||||
return substract(sp1, sp2, 0, sp1.length);
|
||||
}
|
||||
|
||||
public static int[] substract(int[] sp1, int[] sp2, int from, int to) {
|
||||
assert sp1.length == sp2.length;
|
||||
assert to >= from;
|
||||
assert to <= sp1.length;
|
||||
|
||||
int[] res = new int[sp1.length];
|
||||
for (int i = from; i < to; i++) {
|
||||
res[i] = max(0, sp1[i]-sp2[i]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.data;
|
||||
|
||||
import hep.dataforge.context.GlobalContext;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.time.LocalDateTime;
|
||||
import static java.time.temporal.ChronoUnit.SECONDS;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Заплатка для задания поправки на масс-спектрометр
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class MonitorCorrector {
|
||||
|
||||
private final double average;
|
||||
private final List<MonitorPoint> list;
|
||||
|
||||
public MonitorCorrector(String path) throws ParseException, IOException {
|
||||
this(GlobalContext.instance().io().getFile(path));
|
||||
}
|
||||
|
||||
public MonitorCorrector(File monitorFile) throws ParseException, IOException {
|
||||
list = new ArrayList<>();
|
||||
|
||||
BufferedReader reader = new BufferedReader(new FileReader(monitorFile));
|
||||
// Scanner sc = new Scanner(monitorFile);
|
||||
|
||||
double sum = 0;
|
||||
String str = reader.readLine();
|
||||
while ((str!=null)&&(!str.isEmpty())) {
|
||||
MonitorPoint point = new MonitorPoint(str);
|
||||
str = reader.readLine();
|
||||
list.add(point);
|
||||
sum += point.getMonitorValue();
|
||||
}
|
||||
average = sum / list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* возвращает ближайшую по времени точку
|
||||
*
|
||||
* @param time
|
||||
* @return
|
||||
*/
|
||||
public MonitorPoint findNearestMonitorPoint(LocalDateTime time) {
|
||||
MonitorPoint nearest = this.list.get(0);
|
||||
for (MonitorPoint point : this.list) {
|
||||
if (Math.abs(point.getTime().until(time, SECONDS))
|
||||
< Math.abs(nearest.getTime().until(time, SECONDS))) {
|
||||
nearest = point;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
|
||||
}
|
||||
|
||||
public double getCorrection(LocalDateTime start, double length) {
|
||||
LocalDateTime finish = start.plusSeconds((long) length);
|
||||
|
||||
return (findNearestMonitorPoint(start).getMonitorValue() + findNearestMonitorPoint(finish).getMonitorValue()) / 2 / average;
|
||||
}
|
||||
|
||||
public double getCorrectionError(LocalDateTime start, double length) {
|
||||
LocalDateTime finish = start.plusSeconds((long) length);
|
||||
|
||||
return (findNearestMonitorPoint(start).getMonitorError() + findNearestMonitorPoint(finish).getMonitorError()) / 2 / average;
|
||||
}
|
||||
|
||||
}
|
74
numass-main/src/main/java/inr/numass/data/MonitorPoint.java
Normal file
74
numass-main/src/main/java/inr/numass/data/MonitorPoint.java
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.data;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class MonitorPoint {
|
||||
|
||||
// private static SimpleDateFormat format = new SimpleDateFormat("yyyy:MM:dd:HH:mm:ss");
|
||||
|
||||
private final double monitorError;
|
||||
private final double monitorValue;
|
||||
private final LocalDateTime time;
|
||||
|
||||
public MonitorPoint(LocalDateTime time, double monitorValue, double monitorError) {
|
||||
this.time = time;
|
||||
this.monitorValue = monitorValue;
|
||||
this.monitorError = monitorError;
|
||||
}
|
||||
|
||||
public MonitorPoint(String str) throws ParseException {
|
||||
Scanner sc = new Scanner(str);
|
||||
String datestr = sc.next();
|
||||
//using ISO-8601
|
||||
time = LocalDateTime.parse(datestr);
|
||||
monitorValue = sc.nextDouble();
|
||||
if (sc.hasNextDouble()) {
|
||||
monitorError = sc.nextDouble();
|
||||
} else {
|
||||
monitorError = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the monitorError
|
||||
*/
|
||||
public double getMonitorError() {
|
||||
return monitorError;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the monitorValue
|
||||
*/
|
||||
public double getMonitorValue() {
|
||||
return monitorValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the time
|
||||
*/
|
||||
public LocalDateTime getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
}
|
49
numass-main/src/main/java/inr/numass/data/NMEvent.java
Normal file
49
numass-main/src/main/java/inr/numass/data/NMEvent.java
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class NMEvent implements Cloneable{
|
||||
protected final short chanel;
|
||||
protected final double time;
|
||||
|
||||
public NMEvent(short chanel, double time) {
|
||||
this.chanel = chanel;
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NMEvent clone() {
|
||||
return new NMEvent(chanel, time);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the chanel
|
||||
*/
|
||||
public short getChanel() {
|
||||
return chanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the time
|
||||
*/
|
||||
public double getTime(){
|
||||
return time;
|
||||
}
|
||||
}
|
120
numass-main/src/main/java/inr/numass/data/NMFile.java
Normal file
120
numass-main/src/main/java/inr/numass/data/NMFile.java
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.data;
|
||||
|
||||
import hep.dataforge.content.AbstractContent;
|
||||
import hep.dataforge.description.ValueDef;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaBuilder;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* Объект, содержащий только спектры, но не сами события
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
@ValueDef(name = "numass.path", info = "Path to this data file in numass repository.")
|
||||
@ValueDef(name = "numass.name", info = "The name of this data file.")
|
||||
public class NMFile extends AbstractContent implements NumassData {
|
||||
|
||||
public static NMFile readStream(InputStream is, String fname, Meta config) throws IOException{
|
||||
return new NMFile(new NumassDataReader(is, fname, config).read());
|
||||
}
|
||||
|
||||
private final String head;
|
||||
private final List<NMPoint> points;
|
||||
|
||||
public NMFile(RawNMFile file) {
|
||||
super(file.getName(), file.meta());
|
||||
this.head = file.getHead();
|
||||
points = new ArrayList<>();
|
||||
for (RawNMPoint point : file.getData()) {
|
||||
points.add(new NMPoint(point));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the head
|
||||
*/
|
||||
public String getHead() {
|
||||
return head;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Meta getInfo() {
|
||||
return new MetaBuilder("info").setValue("info", head);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the points
|
||||
*/
|
||||
@Override
|
||||
public List<NMPoint> getNMPoints() {
|
||||
return points;
|
||||
}
|
||||
|
||||
/**
|
||||
* merge of all point with given Uset
|
||||
*
|
||||
* @param U
|
||||
* @return
|
||||
*/
|
||||
public NMPoint getByUset(double U) {
|
||||
for (NMPoint point : points) {
|
||||
if (point.getUset() == U) {
|
||||
return point;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* merge of all point with given Uread
|
||||
*
|
||||
* @param U
|
||||
* @return
|
||||
*/
|
||||
public NMPoint getByUread(double U) {
|
||||
for (NMPoint point : points) {
|
||||
if (point.getUread() == U) {
|
||||
return point;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instant startTime() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
256
numass-main/src/main/java/inr/numass/data/NMPoint.java
Normal file
256
numass-main/src/main/java/inr/numass/data/NMPoint.java
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.data;
|
||||
|
||||
import hep.dataforge.data.DataPoint;
|
||||
import hep.dataforge.data.MapDataPoint;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import static java.util.Arrays.sort;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class NMPoint {
|
||||
|
||||
static final String[] dataNames = {"chanel", "count"};
|
||||
private LocalDateTime absouteTime;
|
||||
|
||||
// private MonitorCorrector corrector = null;
|
||||
// private double deadTime;
|
||||
private long eventsCount;
|
||||
|
||||
private int overflow;
|
||||
|
||||
private double pointLength;
|
||||
// private final MeasurementPoint point;
|
||||
private final int[] spectrum;
|
||||
private double uread;
|
||||
private double uset;
|
||||
|
||||
public NMPoint(RawNMPoint point) {
|
||||
if (point == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
this.pointLength = point.getLength();
|
||||
this.uset = point.getUset();
|
||||
this.uread = point.getUread();
|
||||
this.absouteTime = point.getAbsouteTime();
|
||||
this.eventsCount = point.getEventsCount();
|
||||
// this.point = point;
|
||||
spectrum = calculateSpectrum(point);
|
||||
}
|
||||
|
||||
// public PointSpectrum(RawPoint point, double deadTime) {
|
||||
// this(point);
|
||||
// this.deadTime = deadTime;
|
||||
// }
|
||||
private int[] calculateSpectrum(RawNMPoint point) {
|
||||
assert point.getEventsCount() > 0;
|
||||
|
||||
int[] result = new int[RawNMPoint.MAX_CHANEL];
|
||||
Arrays.fill(result, 0);
|
||||
point.getEvents().stream().forEach((event) -> {
|
||||
if (event.getChanel() >= RawNMPoint.MAX_CHANEL) {
|
||||
overflow++;
|
||||
} else {
|
||||
result[event.getChanel()]++;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public DataPoint fastSlice(int... borders) {
|
||||
assert borders.length > 0;//FIXME replace by condition check
|
||||
sort(borders);
|
||||
assert borders[borders.length] < RawNMPoint.MAX_CHANEL;//FIXME replace by condition check
|
||||
|
||||
Integer[] slices = new Integer[borders.length + 2];
|
||||
String[] names = new String[borders.length + 2];
|
||||
|
||||
slices[0] = getCountInWindow(0, borders[0]);
|
||||
names[0] = Integer.toString(borders[0]);
|
||||
for (int i = 1; i < borders.length; i++) {
|
||||
slices[i] = getCountInWindow(borders[i - 1], borders[i]);
|
||||
names[i] = Integer.toString(borders[i]);
|
||||
}
|
||||
slices[borders.length + 1] = getCountInWindow(borders[borders.length], RawNMPoint.MAX_CHANEL);
|
||||
names[borders.length + 1] = Integer.toString(RawNMPoint.MAX_CHANEL);
|
||||
|
||||
slices[borders.length + 2] = RawNMPoint.MAX_CHANEL;
|
||||
names[borders.length + 2] = "TOTAL";
|
||||
|
||||
//FIXME fix it!
|
||||
return new MapDataPoint(names, slices);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the absouteTime
|
||||
*/
|
||||
public LocalDateTime getAbsouteTime() {
|
||||
return absouteTime;
|
||||
}
|
||||
|
||||
public int getCountInChanel(int chanel) {
|
||||
return spectrum[chanel];
|
||||
}
|
||||
|
||||
public int getCountInWindow(int from, int to) {
|
||||
int res = 0;
|
||||
for (int i = from; i <= to; i++) {
|
||||
res += spectrum[i];
|
||||
}
|
||||
if (res == Integer.MAX_VALUE) {
|
||||
throw new RuntimeException("integer overflow in spectrum calculation");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public double getCountRate(int from, int to, double deadTime) {
|
||||
double wind = getCountInWindow(from, to) / getLength();
|
||||
double res;
|
||||
if (deadTime > 0) {
|
||||
double total = getEventsCount();
|
||||
double time = getLength();
|
||||
res = wind / (1 - total * deadTime / time);
|
||||
} else {
|
||||
res = wind;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public double getCountRateErr(int from, int to, double deadTime) {
|
||||
return Math.sqrt(getCountRate(from, to, deadTime) / getLength());
|
||||
}
|
||||
|
||||
public List<DataPoint> getData() {
|
||||
List<DataPoint> data = new ArrayList<>();
|
||||
for (int i = 0; i < RawNMPoint.MAX_CHANEL; i++) {
|
||||
data.add(new MapDataPoint(dataNames, i, spectrum[i]));
|
||||
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Events count - overflow
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getEventsCount() {
|
||||
return eventsCount - getOverflow();
|
||||
}
|
||||
|
||||
public List<DataPoint> getData(int binning, boolean normalize) {
|
||||
List<DataPoint> data = new ArrayList<>();
|
||||
|
||||
double norm;
|
||||
if (normalize) {
|
||||
norm = getLength();
|
||||
} else {
|
||||
norm = 1d;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (i < RawNMPoint.MAX_CHANEL - binning) {
|
||||
int start = i;
|
||||
double sum = spectrum[start] / norm;
|
||||
while (i < start + binning) {
|
||||
sum += spectrum[i] / norm;
|
||||
i++;
|
||||
}
|
||||
data.add(new MapDataPoint(dataNames, start + binning / 2d, sum));
|
||||
i++;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public Map<Double, Double> getMapWithBinning(int binning, boolean normalize) {
|
||||
Map<Double, Double> res = new LinkedHashMap<>();
|
||||
|
||||
double norm;
|
||||
if (normalize) {
|
||||
norm = getLength();
|
||||
} else {
|
||||
norm = 1d;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (i < RawNMPoint.MAX_CHANEL - binning) {
|
||||
int start = i;
|
||||
double sum = spectrum[start] / norm;
|
||||
while (i < start + binning) {
|
||||
sum += spectrum[i] / norm;
|
||||
i++;
|
||||
}
|
||||
res.put(start + binning / 2d, sum);
|
||||
i++;
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
public Map<Double, Double> getMapWithBinning(NMPoint reference, int binning) {
|
||||
Map<Double, Double> sp = this.getMapWithBinning(binning, true);
|
||||
Map<Double, Double> referenceSpectrum = reference.getMapWithBinning(binning, true);
|
||||
|
||||
Map<Double, Double> res = new LinkedHashMap<>();
|
||||
|
||||
sp.entrySet().stream().map((entry) -> entry.getKey()).forEach((bin) -> {
|
||||
res.put(bin, Math.max(sp.get(bin) - referenceSpectrum.get(bin), 0));
|
||||
});
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the overflow
|
||||
*/
|
||||
public int getOverflow() {
|
||||
return overflow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the pointLength
|
||||
*/
|
||||
public double getLength() {
|
||||
return pointLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the uread
|
||||
*/
|
||||
public double getUread() {
|
||||
return uread;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the uset
|
||||
*/
|
||||
public double getUset() {
|
||||
return uset;
|
||||
}
|
||||
|
||||
}
|
29
numass-main/src/main/java/inr/numass/data/NumassData.java
Normal file
29
numass-main/src/main/java/inr/numass/data/NumassData.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 inr.numass.data;
|
||||
|
||||
import hep.dataforge.content.Named;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexander Nozik <altavir@gmail.com>
|
||||
*/
|
||||
public interface NumassData extends Named{
|
||||
|
||||
String getDescription();
|
||||
|
||||
Meta getInfo();
|
||||
|
||||
List<NMPoint> getNMPoints();
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
Instant startTime();
|
||||
|
||||
}
|
515
numass-main/src/main/java/inr/numass/data/NumassDataReader.java
Normal file
515
numass-main/src/main/java/inr/numass/data/NumassDataReader.java
Normal file
@ -0,0 +1,515 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.data;
|
||||
|
||||
import hep.dataforge.data.BinaryData;
|
||||
import hep.dataforge.meta.MergeRule;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake, based on program by S.V.Zadorozhny, 1996
|
||||
*/
|
||||
public class NumassDataReader {
|
||||
|
||||
private String name;
|
||||
private final InputStream stream;
|
||||
private Meta config;
|
||||
private double HVdev;
|
||||
|
||||
public NumassDataReader(BinaryData data, Meta config) throws IOException {
|
||||
this(data.getInputStream(), data.meta()
|
||||
.getString("filename", data.getName()), MergeRule.replace(config, data.meta()));
|
||||
}
|
||||
|
||||
public NumassDataReader(String file, String fname, Meta config) throws FileNotFoundException {
|
||||
this(new FileInputStream(file), fname, config);
|
||||
if ((fname == null) || (fname.isEmpty())) {
|
||||
name = file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public NumassDataReader(InputStream is, String fname, Meta config) {
|
||||
this.stream = new BufferedInputStream(is);
|
||||
this.name = fname;
|
||||
this.config = config;
|
||||
HVdev = config.getDouble("HVdev", 2.468555393226049);
|
||||
}
|
||||
|
||||
public RawNMFile read() throws IOException {
|
||||
return readFile(name);
|
||||
}
|
||||
|
||||
private int[] readBlock(int length) throws IOException {
|
||||
int[] res = new int[length];
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
res[i] = readByte();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private int readByte() throws IOException {
|
||||
return stream.read();
|
||||
}
|
||||
|
||||
private short readChanel(int hb) throws IOException {
|
||||
assert hb < 127;
|
||||
return (short) (readByte() + 256 * hb);
|
||||
}
|
||||
|
||||
private LocalDateTime readDate(String head) throws IOException {
|
||||
// Должны считать 14 символов
|
||||
Scanner sc = new Scanner(head);
|
||||
sc.nextLine();
|
||||
String dateStr = sc.nextLine().trim();
|
||||
//DD.MM.YY HH:MM
|
||||
//12:35:16 19-11-2013
|
||||
DateTimeFormatter format = DateTimeFormatter.ofPattern("HH:mm:ss dd-MM-yyyy");
|
||||
|
||||
LocalDateTime date = LocalDateTime.parse(dateStr, format);
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
private NMEvent readEvent(int b, double timeDiv) throws IOException {
|
||||
short chanel;
|
||||
long time;
|
||||
|
||||
int hb = (b & 0x0f);
|
||||
int lab = (b & 0xf0);
|
||||
|
||||
switch (lab) {
|
||||
case 0x10:
|
||||
chanel = readChanel(hb);
|
||||
time = readTime();
|
||||
break;
|
||||
case 0x20:
|
||||
chanel = 0;
|
||||
time = readTime();
|
||||
break;
|
||||
case 0x40:
|
||||
time = 0;
|
||||
chanel = readChanel(hb);
|
||||
break;
|
||||
case 0x80:
|
||||
time = 0;
|
||||
chanel = 0;
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Event head expected");
|
||||
}
|
||||
|
||||
return new NMEvent(chanel, time / timeDiv);
|
||||
}
|
||||
|
||||
private RawNMFile readFile(String name) throws IOException {
|
||||
|
||||
RawNMFile file = new RawNMFile(name);
|
||||
String head = readHead();//2048
|
||||
file.setHead(head.replaceAll("\u0000", ""));
|
||||
|
||||
LocalDateTime filedate = readDate(head);
|
||||
|
||||
int lab = readByte();
|
||||
do {
|
||||
RawNMPoint point = readPoint(lab, filedate);
|
||||
//Устанавливаем дату точки
|
||||
file.putPoint(point);
|
||||
lab = readByte();
|
||||
} while (lab != 0xff);
|
||||
|
||||
//Check if input file head is numass data file
|
||||
return file;
|
||||
}
|
||||
|
||||
private String readHead() throws IOException {
|
||||
byte[] bytes = new byte[2048];
|
||||
stream.read(bytes);
|
||||
return new String(bytes);
|
||||
}
|
||||
|
||||
private RawNMPoint readPoint(int head, LocalDateTime filedate) throws IOException {
|
||||
|
||||
int[] rx;
|
||||
|
||||
int voltage;
|
||||
short time_out;
|
||||
double timeDiv = 0;
|
||||
boolean phoneFlag;
|
||||
|
||||
RawNMPoint point = new RawNMPoint();
|
||||
|
||||
int lab = head;
|
||||
|
||||
//point head
|
||||
if (lab != 0x0f) {
|
||||
//Ожидается, что это голова точки
|
||||
throw new IOException("Point head expected");
|
||||
}
|
||||
|
||||
rx = readBlock(32);
|
||||
|
||||
voltage = rx[2] + 256 * rx[3];
|
||||
voltage = 65536 * voltage + rx[0] + 256 * rx[1];
|
||||
|
||||
time_out = (short) (rx[6] + 256 * rx[7]);
|
||||
phoneFlag = (rx[19] != 0);
|
||||
|
||||
switch (time_out) {
|
||||
case 5:
|
||||
case 10:
|
||||
timeDiv = 2e7;
|
||||
break;
|
||||
case 15:
|
||||
case 20:
|
||||
timeDiv = 1e7;
|
||||
break;
|
||||
case 50:
|
||||
timeDiv = 5e6;
|
||||
break;
|
||||
case 100:
|
||||
timeDiv = 2.5e6;
|
||||
break;
|
||||
case 200:
|
||||
timeDiv = 1.25e6;
|
||||
break;
|
||||
default:
|
||||
throw new IOException("Unknown time divider in input data");
|
||||
}
|
||||
|
||||
if (phoneFlag) {
|
||||
timeDiv /= 20.0;
|
||||
time_out *= 20;
|
||||
}
|
||||
|
||||
lab = readByte();
|
||||
while (lab == 0xBF) {
|
||||
skip(4);//badHV
|
||||
lab = readByte();
|
||||
}
|
||||
do {
|
||||
point.putEvent(readEvent(lab, timeDiv));
|
||||
lab = readByte();
|
||||
} while (lab != 0xAF);
|
||||
|
||||
//point end
|
||||
skip(37);
|
||||
|
||||
int hours = readByte();
|
||||
int minutes = readByte();
|
||||
|
||||
LocalDateTime absoluteTime = filedate.withHour(hours).withMinute(minutes);
|
||||
|
||||
//проверяем, не проскочили ли мы полночь
|
||||
if (absoluteTime.isBefore(filedate)) {
|
||||
absoluteTime = absoluteTime.plusDays(1);
|
||||
}
|
||||
|
||||
point.setAbsouteTime(absoluteTime);
|
||||
|
||||
rx = readBlock(4);
|
||||
int Uread = rx[2] + 256 * rx[3];
|
||||
Uread = 65536 * Uread + rx[0] + 256 * rx[1];
|
||||
|
||||
skip(21);
|
||||
|
||||
point.setLength(time_out);
|
||||
point.setUread(Uread / 10d / HVdev);
|
||||
if (config.getBoolean("noUset", false)) {
|
||||
point.setUset(Uread / 10d / HVdev);
|
||||
} else {
|
||||
point.setUset(voltage / 10d);
|
||||
}
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
private long readTime() throws IOException {
|
||||
int[] rx = readBlock(4);
|
||||
long time = rx[0] + 256 * rx[1] + 65536 * rx[2] + 256 * 65536 * rx[3];
|
||||
return time;
|
||||
}
|
||||
|
||||
private void skip(int length) throws IOException {
|
||||
long n = stream.skip(length);
|
||||
if (n != length) {
|
||||
stream.skip(length - n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
PROGRAM DAT2PAW;
|
||||
|
||||
{$N+}
|
||||
|
||||
{$D Copyright (C) 1996 by S.V.Zadorozhny, INR RAS}
|
||||
|
||||
Uses Dos, Crt;
|
||||
|
||||
CONST
|
||||
Rec_Len = 32768; { Buffer size }
|
||||
|
||||
TYPE
|
||||
Dim = ARRAY [1..Rec_Len] OF Byte; { Read / Write Buffer }
|
||||
|
||||
VAR
|
||||
DATA : WORD;
|
||||
TIME : LONGINT;
|
||||
TD : Double;
|
||||
i, j, k : WORD;
|
||||
Voltage, li, CN : LONGINT;
|
||||
St, St1 : String;
|
||||
f : File;
|
||||
txt : Text;
|
||||
Buf : ^Dim;
|
||||
Buf_point : Word;
|
||||
err : INTEGER;
|
||||
Monitor, Pressure : WORD;
|
||||
|
||||
paths : PathStr;
|
||||
dirs : DirStr;
|
||||
nams : NameStr;
|
||||
exts : ExtStr;
|
||||
name, mask : String;
|
||||
sr : SearchRec;
|
||||
|
||||
rx : Array [1..64] OF Byte;
|
||||
lab, bt : Byte;
|
||||
time_out : Word;
|
||||
hb : Word;
|
||||
|
||||
{Gate_L, Gate_H : Word;}
|
||||
|
||||
TimDiv : Double;
|
||||
Phone_Flag, OK : Boolean;
|
||||
|
||||
live : word;
|
||||
|
||||
(*----------------------------- PROCEDURES ----------------------------------*)
|
||||
PROCEDURE NextChar;
|
||||
BEGIN
|
||||
CASE (live) OF
|
||||
0 : BEGIN
|
||||
Write('|');
|
||||
Inc(live);
|
||||
END;
|
||||
1 : BEGIN
|
||||
Write(#8'/');
|
||||
Inc(live);
|
||||
END;
|
||||
2 : BEGIN
|
||||
Write(#8'--');
|
||||
Inc(live);
|
||||
END;
|
||||
3 : BEGIN
|
||||
Write(#8#8'\ ');
|
||||
Inc(live);
|
||||
END;
|
||||
4 : BEGIN
|
||||
Write(#8#8'|');
|
||||
live := 1;
|
||||
END;
|
||||
END;
|
||||
END;
|
||||
|
||||
|
||||
PROCEDURE ReadB(VAR bt : BYTE);
|
||||
VAR fact : INTEGER;
|
||||
BEGIN
|
||||
IF Buf_point = 0 THEN
|
||||
BEGIN
|
||||
BlockRead(f,Buf^,Rec_Len,fact);
|
||||
NextChar;
|
||||
END;
|
||||
Inc(Buf_point);
|
||||
bt := Buf^[Buf_point];
|
||||
IF Buf_point = Rec_Len THEN Buf_point:=0;
|
||||
END { ReadB };
|
||||
|
||||
PROCEDURE SaveTXT;
|
||||
BEGIN
|
||||
Writeln(txt, CN, #9, TD:10:5, #9, DATA, #9, time_out, #9, (voltage/10):7:1);
|
||||
END;
|
||||
|
||||
PROCEDURE ReadFile;
|
||||
BEGIN
|
||||
Assign(f,name);
|
||||
{$I-}
|
||||
Reset(f,1);
|
||||
{$I+}
|
||||
IF (IOResult <> 0) THEN
|
||||
BEGIN
|
||||
Writeln('Can''t open data file ', name);
|
||||
Halt(3);
|
||||
END;
|
||||
|
||||
BlockRead(f,Buf^,2048,i); {Skip First Block}
|
||||
Buf_point := 0;
|
||||
|
||||
IF ((Buf^[1] <> Ord('N'))OR(Buf^[2] <> Ord('M'))) THEN
|
||||
BEGIN
|
||||
Close(f);
|
||||
Writeln('File ', name, ' is not a data file !');
|
||||
Exit;
|
||||
END;
|
||||
|
||||
Write('File : ',name, ' ');
|
||||
|
||||
paths := name;
|
||||
Fsplit(paths, dirs, nams, exts);
|
||||
Assign(txt, nams + '.paw');
|
||||
Rewrite(txt);
|
||||
|
||||
live := 0;
|
||||
CN := 0;
|
||||
|
||||
REPEAT
|
||||
ReadB(lab);
|
||||
hb := lab AND $0F; { High data byte }
|
||||
lab := lab AND $F0;
|
||||
CASE (lab) OF
|
||||
$00 : { New Point }
|
||||
BEGIN
|
||||
FOR i:=1 TO 32 DO ReadB(rx[i]);
|
||||
Voltage := rx[3] + 256 * Word(rx[4]);
|
||||
Voltage := 65536 * Voltage + rx[1] + 256 * Longint(rx[2]);
|
||||
time_out := rx[7] + 256 * Word(rx[8]);
|
||||
{pressure := rx[11] + 256 * Word(rx[12]);}
|
||||
{Chan := rx[19];}
|
||||
IF (rx[20] <> 0) THEN Phone_Flag := TRUE ELSE Phone_Flag := FALSE;
|
||||
CASE (time_out) OF
|
||||
5, 10 : TimDiv := 20000000.0;
|
||||
15, 20 : TimDiv := 10000000.0;
|
||||
50 : TimDiv := 5000000.0;
|
||||
100 : TimDiv := 2500000.0;
|
||||
200 : TimDiv := 1250000.0;
|
||||
END;
|
||||
IF (Phone_Flag) THEN
|
||||
BEGIN
|
||||
TimDiv := TimDiv / 20.0;
|
||||
time_out := time_out * 20;
|
||||
END;
|
||||
END;
|
||||
|
||||
$10 : { Event, all present }
|
||||
BEGIN
|
||||
FOR i:=1 TO 5 DO ReadB(rx[i]);
|
||||
TIME := rx[2] + 256 * Longint(rx[3])
|
||||
+ 65536 * Longint(rx[4])+ 256 * 65536 * Longint(rx[5]);
|
||||
TD := TIME / TimDiv;
|
||||
DATA := rx[1] + 256 * hb;
|
||||
Inc(CN);
|
||||
SaveTXT;
|
||||
END;
|
||||
|
||||
$20 : { Event, time only }
|
||||
BEGIN
|
||||
FOR i:=1 TO 4 DO ReadB(rx[i]);
|
||||
TIME := rx[1] + 256 * Longint(rx[2])
|
||||
+ 65536 * Longint(rx[3])+ 256 * 65536 * Longint(rx[4]);
|
||||
TD := TIME / TimDiv;
|
||||
DATA := 0;
|
||||
Inc(CN);
|
||||
SaveTXT;
|
||||
END;
|
||||
|
||||
$40 : { Event, code only }
|
||||
BEGIN
|
||||
ReadB(rx[1]);
|
||||
DATA := rx[1] + 256 * hb;
|
||||
TD := 0.0;
|
||||
Inc(CN);
|
||||
SaveTXT;
|
||||
END;
|
||||
|
||||
$80 : { Event, nothing }
|
||||
BEGIN
|
||||
DATA := 0;
|
||||
TD := 0.0;
|
||||
Inc(CN);
|
||||
SaveTXT;
|
||||
END;
|
||||
|
||||
$B0 : { Bad HV }
|
||||
BEGIN
|
||||
FOR i:=1 TO 4 DO ReadB(rx[i]);
|
||||
END;
|
||||
|
||||
$A0 : { End of the point }
|
||||
BEGIN
|
||||
FOR i := 1 TO 64 DO ReadB(rx[i]);
|
||||
END;
|
||||
END;
|
||||
|
||||
UNTIL (lab=$F0);
|
||||
Close(f);
|
||||
Close(txt);
|
||||
Writeln(#8#8' ');
|
||||
END;
|
||||
|
||||
|
||||
PROCEDURE ReadDataFiles;
|
||||
BEGIN
|
||||
mask := ParamStr(1);
|
||||
FindFirst(mask, anyfile, sr);
|
||||
WHILE (DosError = 0) DO
|
||||
BEGIN
|
||||
name := sr.Name;
|
||||
ReadFile;
|
||||
FindNext(sr);
|
||||
END
|
||||
END;
|
||||
|
||||
(*--------------------------- Main ------------------------------------------*)
|
||||
|
||||
BEGIN
|
||||
ClrScr;
|
||||
|
||||
Writeln('TROITSK V-MASS EXPERIMENT DATA FILE -> TEXT FILE CONVERTER');
|
||||
Writeln('WRITTEN BY S.V.ZADOROZHNY');
|
||||
Writeln;
|
||||
|
||||
|
||||
IF (ParamCount <> 1) THEN
|
||||
BEGIN
|
||||
Writeln('Usage : dat2paw <mask.dat>');
|
||||
Writeln;
|
||||
Writeln('--- Press any key to continue ---');
|
||||
ReadKey;
|
||||
Halt(1);
|
||||
END;
|
||||
|
||||
New(Buf);
|
||||
|
||||
ReadDataFiles;
|
||||
|
||||
Writeln;
|
||||
Writeln('O.K.');
|
||||
|
||||
Dispose(Buf);
|
||||
END. {-- Main --}
|
||||
|
||||
*/
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.data;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class NumassPawReader {
|
||||
|
||||
public RawNMFile readPaw(InputStream stream, String name){
|
||||
Locale.setDefault(Locale.US);
|
||||
BufferedInputStream bs = new BufferedInputStream(stream);
|
||||
return readPaw(new Scanner(bs), name);
|
||||
}
|
||||
|
||||
public RawNMFile readPaw(String filePath) throws FileNotFoundException{
|
||||
FileInputStream fs = new FileInputStream(filePath);
|
||||
return readPaw(fs, filePath);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private RawNMFile readPaw(Scanner s, String fileName) {
|
||||
RawNMFile result = new RawNMFile(fileName);
|
||||
|
||||
while (s.hasNext()) {
|
||||
long eventNum = s.nextLong();
|
||||
double time = s.nextDouble();
|
||||
short chanel = s.nextShort();
|
||||
short timeTotal = s.nextShort();
|
||||
double U = s.nextDouble();
|
||||
|
||||
// NumassEvent event = new NumassEvent(chanel, time);
|
||||
result.putEvent(U, chanel, time);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
}
|
132
numass-main/src/main/java/inr/numass/data/RawNMFile.java
Normal file
132
numass-main/src/main/java/inr/numass/data/RawNMFile.java
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.data;
|
||||
|
||||
import hep.dataforge.content.AbstractContent;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Contains the whole data but requires a lot of memory
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class RawNMFile extends AbstractContent {
|
||||
|
||||
// public static String TYPE = ":data:numassdatafile";
|
||||
|
||||
private final List<RawNMPoint> points;
|
||||
|
||||
private String head;
|
||||
|
||||
public void setHead(String head) {
|
||||
this.head = head;
|
||||
}
|
||||
|
||||
public String getHead() {
|
||||
return head;
|
||||
}
|
||||
|
||||
public RawNMFile(String fileName) {
|
||||
super(fileName);
|
||||
this.points = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void generatePAW(OutputStream stream) {
|
||||
PrintWriter writer = new PrintWriter(new BufferedOutputStream(stream));
|
||||
long counter = 0;
|
||||
for (RawNMPoint point : this.getData()) {
|
||||
double U = point.getUread();
|
||||
for (NMEvent event : point.getEvents()) {
|
||||
counter++;
|
||||
writer.printf("%d\t%f\t%d\t%.1f\t%.2f%n", counter, event.getTime(), event.getChanel(), point.getLength(), U);
|
||||
}
|
||||
|
||||
}
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* merge of all point with given Uset
|
||||
* @param U
|
||||
* @return
|
||||
*/
|
||||
public RawNMPoint getByUset(double U) {
|
||||
RawNMPoint res = null;
|
||||
|
||||
for (RawNMPoint point : points) {
|
||||
if (point.getUset() == U) {
|
||||
if (res == null) {
|
||||
res = point.clone();
|
||||
} else {
|
||||
res = res.merge(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* merge of all point with given Uread
|
||||
* @param U
|
||||
* @return
|
||||
*/
|
||||
public RawNMPoint getByUread(double U) {
|
||||
RawNMPoint res = null;
|
||||
|
||||
for (RawNMPoint point : points) {
|
||||
if (point.getUread()== U) {
|
||||
if (res == null) {
|
||||
res = point.clone();
|
||||
} else {
|
||||
res = res.merge(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the data
|
||||
*/
|
||||
public List<RawNMPoint> getData() {
|
||||
return points;
|
||||
}
|
||||
|
||||
void putEvent(double U, short chanel, double time) {
|
||||
for (RawNMPoint point : this.getData()) {
|
||||
if (U == point.getUread()) {
|
||||
point.putEvent(new NMEvent(chanel, time));
|
||||
return;
|
||||
}
|
||||
}
|
||||
RawNMPoint newpoint = new RawNMPoint();
|
||||
newpoint.putEvent(new NMEvent(chanel, time));
|
||||
this.putPoint(newpoint);
|
||||
}
|
||||
|
||||
public void putPoint(RawNMPoint point) {
|
||||
points.add(point);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.points.size();
|
||||
}
|
||||
|
||||
}
|
181
numass-main/src/main/java/inr/numass/data/RawNMPoint.java
Normal file
181
numass-main/src/main/java/inr/numass/data/RawNMPoint.java
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright 2015 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 inr.numass.data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Хранит информацию о спектре точки, но не об отдельных событиях.
|
||||
*
|
||||
* @author Darksnake
|
||||
*/
|
||||
public class RawNMPoint implements Cloneable {
|
||||
|
||||
public static int MAX_CHANEL = 4095;
|
||||
private LocalDateTime absouteTime;
|
||||
private final List<NMEvent> events;
|
||||
private double t;
|
||||
private double uread;
|
||||
|
||||
private double uset;
|
||||
|
||||
public RawNMPoint(double U, List<NMEvent> events, double t) {
|
||||
this.uset = U;
|
||||
this.uread = U;
|
||||
this.events = events;
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public RawNMPoint(double Uset, double Uread, List<NMEvent> events, double t) {
|
||||
this.uset = Uset;
|
||||
this.uread = Uread;
|
||||
this.events = events;
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public RawNMPoint(double uset, double uread, List<NMEvent> events, double t, LocalDateTime absouteTime) {
|
||||
this.uset = uset;
|
||||
this.uread = uread;
|
||||
this.t = t;
|
||||
this.absouteTime = absouteTime;
|
||||
this.events = events;
|
||||
}
|
||||
|
||||
RawNMPoint() {
|
||||
events = new ArrayList<>();
|
||||
uset = 0;
|
||||
uread = 0;
|
||||
t = Double.NaN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RawNMPoint clone() {
|
||||
ArrayList<NMEvent> newevents = new ArrayList<>();
|
||||
for (NMEvent event : this.getEvents()) {
|
||||
newevents.add(event.clone());
|
||||
}
|
||||
return new RawNMPoint(getUset(), getUread(), newevents, getLength());
|
||||
}
|
||||
|
||||
public LocalDateTime getAbsouteTime() {
|
||||
return absouteTime;
|
||||
}
|
||||
|
||||
public double getCR() {
|
||||
return getEventsCount() / getLength();
|
||||
}
|
||||
|
||||
public double getCRError() {
|
||||
return Math.sqrt(getEventsCount()) / getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the events
|
||||
*/
|
||||
public List<NMEvent> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
public long getEventsCount() {
|
||||
return events.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Measurement time
|
||||
* @return the tset
|
||||
*/
|
||||
public double getLength() {
|
||||
if (Double.isNaN(t)) {
|
||||
throw new Error();
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Uread
|
||||
*/
|
||||
public double getUread() {
|
||||
if (uread <= 0) {
|
||||
return getUset();
|
||||
} else {
|
||||
return uread;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Uset
|
||||
*/
|
||||
public double getUset() {
|
||||
if (uset < 0) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return uset;
|
||||
}
|
||||
|
||||
public RawNMPoint merge(RawNMPoint point) {
|
||||
RawNMPoint res = this.clone();
|
||||
for (NMEvent newEvent : point.getEvents()) {
|
||||
res.putEvent(new NMEvent(newEvent.getChanel(), newEvent.getTime() + this.getLength()));
|
||||
}
|
||||
res.t += point.getLength();
|
||||
res.uread = (this.uread + point.uread) / 2;
|
||||
return res;
|
||||
}
|
||||
|
||||
void putEvent(NMEvent event) {
|
||||
events.add(event);
|
||||
}
|
||||
|
||||
public RawNMPoint selectChanels(int from, int to) {
|
||||
assert to > from;
|
||||
|
||||
List<NMEvent> res = new ArrayList<>();
|
||||
for (NMEvent event : this.getEvents()) {
|
||||
if ((event.getChanel() >= from) && (event.getChanel() <= to)) {
|
||||
res.add(event);
|
||||
}
|
||||
}
|
||||
return new RawNMPoint(getUset(), getUread(), res, getLength());
|
||||
}
|
||||
|
||||
void setAbsouteTime(LocalDateTime absouteTime) {
|
||||
this.absouteTime = absouteTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tset the tset to set
|
||||
*/
|
||||
void setLength(double tset) {
|
||||
this.t = tset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Uread the Uread to set
|
||||
*/
|
||||
void setUread(double Uread) {
|
||||
assert Uread >= 0;
|
||||
this.uread = Uread;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Uset the Uset to set
|
||||
*/
|
||||
void setUset(double Uset) {
|
||||
this.uset = Uset;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user