Fixed numass k-task
This commit is contained in:
parent
6b4dbfd23f
commit
6b8faf4eb7
@ -1,305 +0,0 @@
|
||||
/*
|
||||
* 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.kodex.fx.plots.PlotContainer;
|
||||
import hep.dataforge.maths.MathPlugin;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.plotfit.PlotFitResultAction;
|
||||
import hep.dataforge.plots.PlotDataAction;
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||
import hep.dataforge.stat.fit.FitManager;
|
||||
import hep.dataforge.stat.models.ModelManager;
|
||||
import hep.dataforge.stat.models.WeightedXYModel;
|
||||
import hep.dataforge.stat.models.XYModel;
|
||||
import hep.dataforge.tables.ValuesAdapter;
|
||||
import hep.dataforge.tables.XYAdapter;
|
||||
import inr.numass.actions.*;
|
||||
import inr.numass.data.api.NumassAnalyzer;
|
||||
import inr.numass.data.api.NumassPoint;
|
||||
import inr.numass.models.*;
|
||||
import inr.numass.models.sterile.SterileNeutrinoSpectrum;
|
||||
import inr.numass.tasks.*;
|
||||
import org.apache.commons.math3.analysis.UnivariateFunction;
|
||||
import org.apache.commons.math3.util.FastMath;
|
||||
|
||||
/**
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@PluginDef(group = "inr.numass", name = "numass",
|
||||
dependsOn = {"hep.dataforge:math", "hep.dataforge:MINUIT"},
|
||||
support = false,
|
||||
info = "Numass data analysis tools")
|
||||
public class NumassPlugin extends BasicPlugin {
|
||||
|
||||
/**
|
||||
* Display a JFreeChart plot frame in a separate stage window
|
||||
*
|
||||
* @param title
|
||||
* @param width
|
||||
* @param height
|
||||
* @return
|
||||
*/
|
||||
public static JFreeChartFrame displayJFreeChart(String title, double width, double height, Meta meta) {
|
||||
JFreeChartFrame frame = new JFreeChartFrame(meta);
|
||||
frame.configureValue("title", title);
|
||||
PlotContainer.Companion.display(frame, title, width, height);
|
||||
return frame;
|
||||
}
|
||||
|
||||
public static JFreeChartFrame displayJFreeChart(String title) {
|
||||
return displayJFreeChart(title, 800, 600, Meta.empty());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void attach(Context context) {
|
||||
// StorageManager.buildFrom(context);
|
||||
super.attach(context);
|
||||
context.pluginManager().load(new NumassIO());
|
||||
FitManager fm = context.getFeature(FitManager.class);
|
||||
loadModels(fm.getModelManager());
|
||||
loadMath(MathPlugin.buildFrom(context));
|
||||
|
||||
ActionManager actions = context.pluginManager().getOrLoad(ActionManager.class);
|
||||
actions.attach(context);
|
||||
|
||||
actions.putAction(MergeDataAction.class);
|
||||
actions.putAction(MonitorCorrectAction.class);
|
||||
actions.putAction(SummaryAction.class);
|
||||
actions.putAction(PlotDataAction.class);
|
||||
actions.putAction(PlotFitResultAction.class);
|
||||
actions.putAction(AdjustErrorsAction.class);
|
||||
actions.putAction(SubstractSpectrumAction.class);
|
||||
|
||||
actions.putTask(NumassPrepareTask.class);
|
||||
actions.putTask(NumassTableFilterTask.class);
|
||||
actions.putTask(NumassFitScanTask.class);
|
||||
actions.putTask(NumassSubstractEmptySourceTask.class);
|
||||
actions.putTask(NumassFitScanSummaryTask.class);
|
||||
actions.putTask(NumassFitTask.class);
|
||||
actions.putTask(NumassFitSummaryTask.class);
|
||||
actions.put(NumassTasksKt.getSelectDataTask());
|
||||
actions.put(NumassTasksKt.getMonitorTableTask());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
//TODO clean up
|
||||
super.detach();
|
||||
}
|
||||
|
||||
private void loadMath(MathPlugin math) {
|
||||
math.registerBivariate("numass.trap.lowFields", (Ei, Ef) -> {
|
||||
return 3.92e-5 * FastMath.exp(-(Ei - Ef) / 300d) + 1.97e-4 - 6.818e-9 * Ei;
|
||||
});
|
||||
|
||||
math.registerBivariate("numass.trap.nominal", (Ei, Ef) -> {
|
||||
//return 1.64e-5 * FastMath.exp(-(Ei - Ef) / 300d) + 1.1e-4 - 4e-9 * Ei;
|
||||
return 1.2e-4 - 4.5e-9 * Ei;
|
||||
});
|
||||
|
||||
math.registerBivariate("numass.resolutionTail", meta -> {
|
||||
double alpha = meta.getDouble("tailAlpha", 0);
|
||||
double beta = meta.getDouble("tailBeta", 0);
|
||||
return (double E, double U) -> 1 - (E - U) * (alpha + E / 1000d * beta) / 1000d;
|
||||
});
|
||||
|
||||
math.registerBivariate("numass.resolutionTail.2017", meta ->
|
||||
(double E, double U) -> {
|
||||
double D = E - U;
|
||||
return 0.99797 - 3.05346E-7 * D - 5.45738E-10 * Math.pow(D, 2) - 6.36105E-14 * Math.pow(D, 3);
|
||||
});
|
||||
|
||||
math.registerBivariate("numass.resolutionTail.2017.mod", meta ->
|
||||
(double E, double U) -> {
|
||||
double D = E - U;
|
||||
return (0.99797 - 3.05346E-7 * D - 5.45738E-10 * Math.pow(D, 2) - 6.36105E-14 * Math.pow(D, 3)) * (1 - 5e-3 * Math.sqrt(E / 1000));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(getClass().getResourceAsStream("/data/FS.txt"));
|
||||
// ModularSpectrum sp = new ModularSpectrum(beta, A, from, to);
|
||||
// NBkgSpectrum spectrum = new NBkgSpectrum(sp);
|
||||
//
|
||||
// return new XYModel(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);
|
||||
|
||||
return new XYModel(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(spectrum, getAdapter(an), (dp) -> weightReductionFactor);
|
||||
});
|
||||
|
||||
manager.addModel("scatter-empiric-variable", (context, an) -> {
|
||||
double eGun = an.getDouble("eGun", 19005d);
|
||||
|
||||
//builder 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);
|
||||
|
||||
WeightedXYModel res = new WeightedXYModel(spectrum, getAdapter(an), (dp) -> weightReductionFactor);
|
||||
res.setMeta(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(spectrum, getAdapter(an));
|
||||
});
|
||||
|
||||
manager.addModel("scatter-empiric-experimental", (context, an) -> {
|
||||
double eGun = an.getDouble("eGun", 19005d);
|
||||
|
||||
//builder 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);
|
||||
|
||||
WeightedXYModel res
|
||||
= new WeightedXYModel(spectrum, getAdapter(an), (dp) -> weightReductionFactor);
|
||||
res.setMeta(an);
|
||||
return res;
|
||||
});
|
||||
|
||||
manager.addModel("sterile", (context, meta) -> {
|
||||
SterileNeutrinoSpectrum sp = new SterileNeutrinoSpectrum(context, meta);
|
||||
NBkgSpectrum spectrum = new NBkgSpectrum(sp);
|
||||
|
||||
return new XYModel(spectrum, getAdapter(meta));
|
||||
});
|
||||
|
||||
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(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.hasMeta("transBuildAction")) {
|
||||
Meta transBuild = an.getMeta("transBuildAction");
|
||||
try {
|
||||
return TransmissionInterpolator.fromAction(context,
|
||||
transBuild, transXName, transYName, nSmooth, w, stitchBorder);
|
||||
} catch (InterruptedException ex) {
|
||||
throw new RuntimeException("Transmission builder failed");
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("Transmission declaration not found");
|
||||
}
|
||||
}
|
||||
|
||||
private XYAdapter getAdapter(Meta an) {
|
||||
if (an.hasMeta(ValuesAdapter.ADAPTER_KEY)) {
|
||||
return new XYAdapter(an.getMeta(ValuesAdapter.ADAPTER_KEY));
|
||||
} else {
|
||||
return new XYAdapter(NumassPoint.HV_KEY, NumassAnalyzer.COUNT_RATE_KEY, NumassAnalyzer.COUNT_RATE_ERROR_KEY);
|
||||
}
|
||||
}
|
||||
}
|
@ -84,7 +84,7 @@ public class NumassPrepareTask extends AbstractTask<Table> {
|
||||
|
||||
);
|
||||
|
||||
model.dependsOn("data", meta.getMetaOrEmpty("data"), "data");
|
||||
model.dependsOn("select", meta, "data");
|
||||
}
|
||||
|
||||
private <T, R> DataNode<R> runAction(GenericAction<T, R> action, Context context, DataNode<T> data, Meta meta) {
|
||||
|
@ -1,104 +0,0 @@
|
||||
/*
|
||||
* 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.tasks;
|
||||
|
||||
import hep.dataforge.data.Data;
|
||||
import hep.dataforge.data.DataNode;
|
||||
import hep.dataforge.data.DataTree;
|
||||
import hep.dataforge.data.DataUtils;
|
||||
import hep.dataforge.io.ColumnedDataWriter;
|
||||
import hep.dataforge.meta.Meta;
|
||||
import hep.dataforge.meta.MetaBuilder;
|
||||
import hep.dataforge.tables.ListTable;
|
||||
import hep.dataforge.tables.Table;
|
||||
import hep.dataforge.tables.ValueMap;
|
||||
import hep.dataforge.values.Values;
|
||||
import hep.dataforge.workspace.tasks.AbstractTask;
|
||||
import hep.dataforge.workspace.tasks.TaskModel;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Created by darksnake on 06-Sep-16.
|
||||
*/
|
||||
public class NumassSubstractEmptySourceTask extends AbstractTask<Table> {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "subtractEmpty";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DataNode<Table> run(TaskModel model, DataNode<?> data) {
|
||||
DataTree.Builder<Table> builder = DataTree.builder(Table.class);
|
||||
DataNode<Table> rootNode = data.getCheckedNode("prepare", Table.class);
|
||||
Data<Table> emptySource = data.getCheckedNode("empty", Table.class).getData();
|
||||
rootNode.forEachData(Table.class, input -> {
|
||||
Data<Table> res = subtract(input, emptySource);
|
||||
res.getGoal().onComplete((r, err) -> {
|
||||
if (r != null) {
|
||||
OutputStream out = model.getContext().io().out("merge", input.getName() + ".subtract");
|
||||
ColumnedDataWriter.writeTable(out, r,
|
||||
input.meta().getBuilder().setNode("empty", emptySource.meta()).toString());
|
||||
}
|
||||
});
|
||||
|
||||
builder.putData(input.getName(), res);
|
||||
});
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void buildModel(TaskModel.Builder model, Meta meta) {
|
||||
model.dependsOn("prepare", meta, "prepare");
|
||||
MetaBuilder emptyCfg = new MetaBuilder("prepare")
|
||||
.setNode(meta.getMeta("prepare"))
|
||||
.setNode("data", meta.getMeta("empty"))
|
||||
.setNode(new MetaBuilder("merge").setValue("mergeName", model.getName() + ".empty"));
|
||||
model.dependsOn("prepare", emptyCfg, "empty");
|
||||
}
|
||||
|
||||
|
||||
|
||||
private Data<Table> subtract(Data<Table> mergeData, Data<Table> emptyData) {
|
||||
return DataUtils.combine(
|
||||
mergeData,
|
||||
emptyData,
|
||||
Table.class,
|
||||
mergeData.meta(), this::subtract);
|
||||
}
|
||||
|
||||
private Table subtract(Table merge, Table empty) {
|
||||
ListTable.Builder builder = new ListTable.Builder(merge.getFormat());
|
||||
merge.getRows().forEach(point -> {
|
||||
ValueMap.Builder pointBuilder = new ValueMap.Builder(point);
|
||||
Optional<Values> referencePoint = empty.getRows()
|
||||
.filter(p -> Math.abs(p.getDouble("Uset") - point.getDouble("Uset")) < 0.1).findFirst();
|
||||
if (referencePoint.isPresent()) {
|
||||
pointBuilder.putValue("CR", Math.max(0, point.getDouble("CR") - referencePoint.get().getDouble("CR")));
|
||||
pointBuilder.putValue("CRerr", Math.sqrt(Math.pow(point.getDouble("CRerr"), 2d) + Math.pow(referencePoint.get().getDouble("CRerr"), 2d)));
|
||||
} else {
|
||||
LoggerFactory.getLogger(getClass()).warn("No reference point found for Uset = {}", point.getDouble("Uset"));
|
||||
}
|
||||
builder.row(pointBuilder.build());
|
||||
});
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}
|
305
numass-main/src/main/kotlin/inr/numass/NumassPlugin.kt
Normal file
305
numass-main/src/main/kotlin/inr/numass/NumassPlugin.kt
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
* 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.kodex.fx.plots.PlotContainer
|
||||
import hep.dataforge.maths.MathPlugin
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.plotfit.PlotFitResultAction
|
||||
import hep.dataforge.plots.PlotDataAction
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||
import hep.dataforge.stat.fit.FitManager
|
||||
import hep.dataforge.stat.models.ModelManager
|
||||
import hep.dataforge.stat.models.WeightedXYModel
|
||||
import hep.dataforge.stat.models.XYModel
|
||||
import hep.dataforge.tables.ValuesAdapter
|
||||
import hep.dataforge.tables.XYAdapter
|
||||
import inr.numass.actions.*
|
||||
import inr.numass.data.api.NumassAnalyzer
|
||||
import inr.numass.data.api.NumassPoint
|
||||
import inr.numass.models.*
|
||||
import inr.numass.models.sterile.SterileNeutrinoSpectrum
|
||||
import inr.numass.tasks.*
|
||||
import org.apache.commons.math3.analysis.BivariateFunction
|
||||
import org.apache.commons.math3.util.FastMath
|
||||
|
||||
/**
|
||||
* @author Alexander Nozik
|
||||
*/
|
||||
@PluginDef(
|
||||
group = "inr.numass",
|
||||
name = "numass",
|
||||
dependsOn = arrayOf("hep.dataforge:math", "hep.dataforge:MINUIT"),
|
||||
support = false,
|
||||
info = "Numass data analysis tools"
|
||||
)
|
||||
class NumassPlugin : BasicPlugin() {
|
||||
|
||||
|
||||
override fun attach(context: Context) {
|
||||
// StorageManager.buildFrom(context);
|
||||
super.attach(context)
|
||||
context.pluginManager().load(NumassIO())
|
||||
val fm = context.getFeature(FitManager::class.java)
|
||||
loadModels(fm.modelManager)
|
||||
loadMath(MathPlugin.buildFrom(context))
|
||||
|
||||
val actions = context.pluginManager().getOrLoad(ActionManager::class.java)
|
||||
actions.attach(context)
|
||||
|
||||
actions.putAction(MergeDataAction::class.java)
|
||||
actions.putAction(MonitorCorrectAction::class.java)
|
||||
actions.putAction(SummaryAction::class.java)
|
||||
actions.putAction(PlotDataAction::class.java)
|
||||
actions.putAction(PlotFitResultAction::class.java)
|
||||
actions.putAction(AdjustErrorsAction::class.java)
|
||||
actions.putAction(SubstractSpectrumAction::class.java)
|
||||
|
||||
//actions.putTask(NumassPrepareTask::class.java)
|
||||
actions.putTask(NumassTableFilterTask::class.java)
|
||||
actions.putTask(NumassFitScanTask::class.java)
|
||||
actions.putTask(NumassFitScanSummaryTask::class.java)
|
||||
actions.putTask(NumassFitTask::class.java)
|
||||
actions.putTask(NumassFitSummaryTask::class.java)
|
||||
actions.put(selectDataTask)
|
||||
actions.put(analyzeTask)
|
||||
actions.put(mergeTask)
|
||||
actions.put(mergeEmptyTask)
|
||||
actions.put(monitorTableTask)
|
||||
actions.put(subtractEmptyTask)
|
||||
}
|
||||
|
||||
override fun detach() {
|
||||
//TODO clean up
|
||||
super.detach()
|
||||
}
|
||||
|
||||
private fun loadMath(math: MathPlugin) {
|
||||
math.registerBivariate("numass.trap.lowFields") { Ei, Ef -> 3.92e-5 * FastMath.exp(-(Ei - Ef) / 300.0) + 1.97e-4 - 6.818e-9 * Ei }
|
||||
|
||||
math.registerBivariate("numass.trap.nominal") { Ei, Ef ->
|
||||
//return 1.64e-5 * FastMath.exp(-(Ei - Ef) / 300d) + 1.1e-4 - 4e-9 * Ei;
|
||||
1.2e-4 - 4.5e-9 * Ei
|
||||
}
|
||||
|
||||
math.registerBivariate("numass.resolutionTail") { meta ->
|
||||
val alpha = meta.getDouble("tailAlpha", 0.0)!!
|
||||
val beta = meta.getDouble("tailBeta", 0.0)!!
|
||||
BivariateFunction { E: Double, U: Double -> 1 - (E - U) * (alpha + E / 1000.0 * beta) / 1000.0 }
|
||||
}
|
||||
|
||||
math.registerBivariate("numass.resolutionTail.2017") { meta ->
|
||||
BivariateFunction { E: Double, U: Double ->
|
||||
val D = E - U
|
||||
0.99797 - 3.05346E-7 * D - 5.45738E-10 * Math.pow(D, 2.0) - 6.36105E-14 * Math.pow(D, 3.0)
|
||||
}
|
||||
}
|
||||
|
||||
math.registerBivariate("numass.resolutionTail.2017.mod") { meta ->
|
||||
BivariateFunction { E: Double, U: Double ->
|
||||
val D = E - U
|
||||
(0.99797 - 3.05346E-7 * D - 5.45738E-10 * Math.pow(D, 2.0) - 6.36105E-14 * Math.pow(D, 3.0)) * (1 - 5e-3 * Math.sqrt(E / 1000))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all numass model factories
|
||||
*
|
||||
* @param manager
|
||||
*/
|
||||
private fun loadModels(manager: ModelManager) {
|
||||
|
||||
// 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(getClass().getResourceAsStream("/data/FS.txt"));
|
||||
// ModularSpectrum sp = new ModularSpectrum(beta, A, from, to);
|
||||
// NBkgSpectrum spectrum = new NBkgSpectrum(sp);
|
||||
//
|
||||
// return new XYModel(spectrum, getAdapter(an));
|
||||
// });
|
||||
|
||||
manager.addModel("scatter") { context, an ->
|
||||
val A = an.getDouble("resolution", 8.3e-5)!!//8.3e-5
|
||||
val from = an.getDouble("from", 0.0)!!
|
||||
val to = an.getDouble("to", 0.0)!!
|
||||
|
||||
val sp: ModularSpectrum
|
||||
if (from == to) {
|
||||
sp = ModularSpectrum(GaussSourceSpectrum(), A)
|
||||
} else {
|
||||
sp = ModularSpectrum(GaussSourceSpectrum(), A, from, to)
|
||||
}
|
||||
|
||||
val spectrum = NBkgSpectrum(sp)
|
||||
|
||||
XYModel(spectrum, getAdapter(an))
|
||||
}
|
||||
|
||||
manager.addModel("scatter-empiric") { context, an ->
|
||||
val eGun = an.getDouble("eGun", 19005.0)!!
|
||||
|
||||
val interpolator = buildInterpolator(context, an, eGun)
|
||||
|
||||
val loss = EmpiricalLossSpectrum(interpolator, eGun + 5)
|
||||
val spectrum = NBkgSpectrum(loss)
|
||||
|
||||
val weightReductionFactor = an.getDouble("weightReductionFactor", 2.0)!!
|
||||
|
||||
WeightedXYModel(spectrum, getAdapter(an)) { dp -> weightReductionFactor }
|
||||
}
|
||||
|
||||
manager.addModel("scatter-empiric-variable") { context, an ->
|
||||
val eGun = an.getDouble("eGun", 19005.0)!!
|
||||
|
||||
//builder transmisssion with given data, annotation and smoothing
|
||||
val interpolator = buildInterpolator(context, an, eGun)
|
||||
|
||||
val loss = VariableLossSpectrum.withData(interpolator, eGun + 5)
|
||||
|
||||
val tritiumBackground = an.getDouble("tritiumBkg", 0.0)!!
|
||||
|
||||
val spectrum: NBkgSpectrum
|
||||
if (tritiumBackground == 0.0) {
|
||||
spectrum = NBkgSpectrum(loss)
|
||||
} else {
|
||||
spectrum = CustomNBkgSpectrum.tritiumBkgSpectrum(loss, tritiumBackground)
|
||||
}
|
||||
|
||||
val weightReductionFactor = an.getDouble("weightReductionFactor", 2.0)!!
|
||||
|
||||
val res = WeightedXYModel(spectrum, getAdapter(an)) { dp -> weightReductionFactor }
|
||||
res.meta = an
|
||||
res
|
||||
}
|
||||
|
||||
manager.addModel("scatter-analytic-variable") { context, an ->
|
||||
val eGun = an.getDouble("eGun", 19005.0)!!
|
||||
|
||||
val loss = VariableLossSpectrum.withGun(eGun + 5)
|
||||
|
||||
val tritiumBackground = an.getDouble("tritiumBkg", 0.0)!!
|
||||
|
||||
val spectrum: NBkgSpectrum
|
||||
if (tritiumBackground == 0.0) {
|
||||
spectrum = NBkgSpectrum(loss)
|
||||
} else {
|
||||
spectrum = CustomNBkgSpectrum.tritiumBkgSpectrum(loss, tritiumBackground)
|
||||
}
|
||||
|
||||
XYModel(spectrum, getAdapter(an))
|
||||
}
|
||||
|
||||
manager.addModel("scatter-empiric-experimental") { context, an ->
|
||||
val eGun = an.getDouble("eGun", 19005.0)!!
|
||||
|
||||
//builder transmisssion with given data, annotation and smoothing
|
||||
val interpolator = buildInterpolator(context, an, eGun)
|
||||
|
||||
val smoothing = an.getDouble("lossSmoothing", 0.3)!!
|
||||
|
||||
val loss = ExperimentalVariableLossSpectrum.withData(interpolator, eGun + 5, smoothing)
|
||||
|
||||
val spectrum = NBkgSpectrum(loss)
|
||||
|
||||
val weightReductionFactor = an.getDouble("weightReductionFactor", 2.0)!!
|
||||
|
||||
val res = WeightedXYModel(spectrum, getAdapter(an)) { dp -> weightReductionFactor }
|
||||
res.meta = an
|
||||
res
|
||||
}
|
||||
|
||||
manager.addModel("sterile") { context, meta ->
|
||||
val sp = SterileNeutrinoSpectrum(context, meta)
|
||||
val spectrum = NBkgSpectrum(sp)
|
||||
|
||||
XYModel(spectrum, getAdapter(meta))
|
||||
}
|
||||
|
||||
manager.addModel("gun") { context, an ->
|
||||
val gsp = GunSpectrum()
|
||||
|
||||
val tritiumBackground = an.getDouble("tritiumBkg", 0.0)!!
|
||||
|
||||
val spectrum: NBkgSpectrum
|
||||
if (tritiumBackground == 0.0) {
|
||||
spectrum = NBkgSpectrum(gsp)
|
||||
} else {
|
||||
spectrum = CustomNBkgSpectrum.tritiumBkgSpectrum(gsp, tritiumBackground)
|
||||
}
|
||||
|
||||
XYModel(spectrum, getAdapter(an))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun buildInterpolator(context: Context, an: Meta, eGun: Double): TransmissionInterpolator {
|
||||
val transXName = an.getString("transXName", "Uset")
|
||||
val transYName = an.getString("transYName", "CR")
|
||||
|
||||
val stitchBorder = an.getDouble("stitchBorder", eGun - 7)!!
|
||||
val nSmooth = an.getInt("nSmooth", 15)!!
|
||||
|
||||
val w = an.getDouble("w", 0.8)!!
|
||||
|
||||
if (an.hasValue("transFile")) {
|
||||
val transmissionFile = an.getString("transFile")
|
||||
|
||||
return TransmissionInterpolator
|
||||
.fromFile(context, transmissionFile, transXName, transYName, nSmooth, w, stitchBorder)
|
||||
} else if (an.hasMeta("transBuildAction")) {
|
||||
val transBuild = an.getMeta("transBuildAction")
|
||||
try {
|
||||
return TransmissionInterpolator.fromAction(context,
|
||||
transBuild, transXName, transYName, nSmooth, w, stitchBorder)
|
||||
} catch (ex: InterruptedException) {
|
||||
throw RuntimeException("Transmission builder failed")
|
||||
}
|
||||
|
||||
} else {
|
||||
throw RuntimeException("Transmission declaration not found")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAdapter(an: Meta): XYAdapter {
|
||||
return if (an.hasMeta(ValuesAdapter.ADAPTER_KEY)) {
|
||||
XYAdapter(an.getMeta(ValuesAdapter.ADAPTER_KEY))
|
||||
} else {
|
||||
XYAdapter(NumassPoint.HV_KEY, NumassAnalyzer.COUNT_RATE_KEY, NumassAnalyzer.COUNT_RATE_ERROR_KEY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a JFreeChart plot frame in a separate stage window
|
||||
*
|
||||
* @param title
|
||||
* @param width
|
||||
* @param height
|
||||
* @return
|
||||
*/
|
||||
@JvmOverloads fun displayJFreeChart(title: String, width: Double = 800.0, height: Double = 600.0, meta: Meta = Meta.empty()): JFreeChartFrame {
|
||||
val frame = JFreeChartFrame(meta)
|
||||
frame.configureValue("title", title)
|
||||
PlotContainer.display(frame, title, width, height)
|
||||
return frame
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package inr.numass
|
||||
|
||||
import hep.dataforge.context.Context
|
||||
import hep.dataforge.data.DataNode
|
||||
import hep.dataforge.data.DataSet
|
||||
import hep.dataforge.io.envelopes.DefaultEnvelopeType
|
||||
@ -26,7 +27,11 @@ import hep.dataforge.io.markup.SimpleMarkupRenderer
|
||||
import hep.dataforge.meta.Meta
|
||||
import hep.dataforge.meta.MetaBuilder
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||
import hep.dataforge.tables.ListTable
|
||||
import hep.dataforge.tables.Table
|
||||
import hep.dataforge.tables.ValueMap
|
||||
import hep.dataforge.values.Values
|
||||
import inr.numass.data.api.NumassAnalyzer
|
||||
import inr.numass.data.api.NumassPoint
|
||||
import inr.numass.data.api.NumassSet
|
||||
import inr.numass.utils.ExpressionUtils
|
||||
@ -190,3 +195,29 @@ fun addSetMarkers(frame: JFreeChartFrame, sets: Collection<NumassSet>) {
|
||||
runLater { jfcPlot.addDomainMarker(marker) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtract one energy spectrum from the other one
|
||||
*/
|
||||
fun subtract(context: Context, merge: Table, empty: Table): Table {
|
||||
val builder = ListTable.Builder(merge.format)
|
||||
merge.rows.forEach { point ->
|
||||
val pointBuilder = ValueMap.Builder(point)
|
||||
val referencePoint = empty.rows
|
||||
.filter { p -> Math.abs(p.getDouble(NumassPoint.HV_KEY)!! - point.getDouble(NumassPoint.HV_KEY)!!) < 0.1 }.findFirst()
|
||||
if (referencePoint.isPresent) {
|
||||
pointBuilder.putValue(
|
||||
NumassAnalyzer.COUNT_RATE_KEY,
|
||||
Math.max(0.0, point.getDouble(NumassAnalyzer.COUNT_RATE_KEY)!! - referencePoint.get().getDouble(NumassAnalyzer.COUNT_RATE_KEY)!!)
|
||||
)
|
||||
pointBuilder.putValue(
|
||||
NumassAnalyzer.COUNT_RATE_ERROR_KEY,
|
||||
Math.sqrt(Math.pow(point.getDouble(NumassAnalyzer.COUNT_RATE_ERROR_KEY)!!, 2.0) + Math.pow(referencePoint.get().getDouble(NumassAnalyzer.COUNT_RATE_ERROR_KEY)!!, 2.0)))
|
||||
} else {
|
||||
context.logger.warn("No reference point found for voltage = {}", point.getDouble(NumassPoint.HV_KEY))
|
||||
}
|
||||
builder.row(pointBuilder.build())
|
||||
}
|
||||
|
||||
return builder.build()
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
package inr.numass.tasks
|
||||
|
||||
import hep.dataforge.data.CustomDataFilter
|
||||
import hep.dataforge.data.DataSet
|
||||
import hep.dataforge.data.DataTree
|
||||
import hep.dataforge.data.DataUtils
|
||||
import hep.dataforge.description.ValueDef
|
||||
import hep.dataforge.io.ColumnedDataWriter
|
||||
import hep.dataforge.kodex.configure
|
||||
import hep.dataforge.kodex.fx.plots.PlotManager
|
||||
import hep.dataforge.kodex.fx.plots.plus
|
||||
@ -11,21 +16,26 @@ import hep.dataforge.plots.jfreechart.JFreeChartFrame
|
||||
import hep.dataforge.tables.ListTable
|
||||
import hep.dataforge.tables.Table
|
||||
import hep.dataforge.tables.XYAdapter
|
||||
import hep.dataforge.values.ValueType
|
||||
import inr.numass.NumassUtils
|
||||
import inr.numass.actions.MergeDataAction
|
||||
import inr.numass.actions.MergeDataAction.MERGE_NAME
|
||||
import inr.numass.addSetMarkers
|
||||
import inr.numass.data.analyzers.SmartAnalyzer
|
||||
import inr.numass.data.api.NumassSet
|
||||
import inr.numass.subtract
|
||||
|
||||
val selectDataTask = task("select") {
|
||||
model { meta ->
|
||||
data("*")
|
||||
configure(meta.getMetaOrEmpty("data"))
|
||||
}
|
||||
transform { data ->
|
||||
transform<NumassSet, NumassSet> { data ->
|
||||
CustomDataFilter(meta).filter<NumassSet>(data.checked(NumassSet::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
@ValueDef(name = "showPlot", type = arrayOf(ValueType.BOOLEAN), info = "Show plot after complete")
|
||||
val monitorTableTask = task("monitor") {
|
||||
model { meta ->
|
||||
dependsOn("select", meta)
|
||||
@ -45,22 +55,24 @@ val monitorTableTask = task("monitor") {
|
||||
.map { it -> analyzer.analyzePoint(it, analyzerMeta) }
|
||||
).build()
|
||||
|
||||
context.provide("plots", PlotManager::class.java).ifPresent {
|
||||
it.display(stage = "monitor") {
|
||||
configure {
|
||||
"xAxis.title" to "time"
|
||||
"xAxis.type" to "time"
|
||||
"yAxis.title" to "Count rate"
|
||||
"yAxis.units" to "Hz"
|
||||
}
|
||||
plots + DataPlot.plot(name, XYAdapter("timestamp", "cr", "crErr"), res)
|
||||
}.also { frame ->
|
||||
if (frame is JFreeChartFrame) {
|
||||
//add set markers
|
||||
addSetMarkers(frame, data.values)
|
||||
}
|
||||
context.io().out("numass.monitor", name, "dfp").use {
|
||||
NumassUtils.writeEnvelope(it, PlotFrame.Wrapper().wrap(frame))
|
||||
if (meta.getBoolean("showPlot", true)) {
|
||||
context.provide("plots", PlotManager::class.java).ifPresent {
|
||||
it.display(stage = "monitor") {
|
||||
configure {
|
||||
"xAxis.title" to "time"
|
||||
"xAxis.type" to "time"
|
||||
"yAxis.title" to "Count rate"
|
||||
"yAxis.units" to "Hz"
|
||||
}
|
||||
plots + DataPlot.plot(name, XYAdapter("timestamp", "cr", "crErr"), res)
|
||||
}.also { frame ->
|
||||
if (frame is JFreeChartFrame) {
|
||||
//add set markers
|
||||
addSetMarkers(frame, data.values)
|
||||
}
|
||||
context.io().out("numass.monitor", name, "dfp").use {
|
||||
NumassUtils.writeEnvelope(it, PlotFrame.Wrapper().wrap(frame))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -72,4 +84,79 @@ val monitorTableTask = task("monitor") {
|
||||
return@result res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val analyzeTask = task("analyze") {
|
||||
model { meta ->
|
||||
dependsOn("select", meta);
|
||||
configure(meta.getMetaOrEmpty("analyzer"))
|
||||
}
|
||||
pipe<NumassSet, Table> {
|
||||
result { set ->
|
||||
SmartAnalyzer().analyzeSet(set, meta).also { res ->
|
||||
context.io().out("numass.analyze", name).use {
|
||||
NumassUtils.write(it, meta, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val mergeTask = task("merge") {
|
||||
model { meta ->
|
||||
dependsOn("analyze", meta)
|
||||
configure(meta.getMetaOrEmpty("merge"))
|
||||
}
|
||||
action<Table, Table>(MergeDataAction())
|
||||
}
|
||||
|
||||
val mergeEmptyTask = task("empty") {
|
||||
model { meta ->
|
||||
if (!meta.hasMeta("empty")) {
|
||||
throw RuntimeException("Empty source data not found ");
|
||||
}
|
||||
//replace data node by "empty" node
|
||||
val newMeta = meta.builder
|
||||
.removeNode("data")
|
||||
.removeNode("empty")
|
||||
.setNode("data", meta.getMeta("empty"))
|
||||
.setValue(MERGE_NAME, meta.getString(MERGE_NAME, "") + "_empty");
|
||||
dependsOn("merge", newMeta)
|
||||
}
|
||||
transform<Table, Table> { data ->
|
||||
val builder = DataSet.builder(Table::class.java)
|
||||
data.forEach {
|
||||
builder.putData(it.name + "_empty", it.anonymize());
|
||||
}
|
||||
builder.build()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val subtractEmptyTask = task("dif") {
|
||||
model { meta ->
|
||||
dependsOn("merge", meta, "data")
|
||||
dependsOn("empty", meta, "empty")
|
||||
}
|
||||
transform<Table,Table> { data ->
|
||||
val builder = DataTree.builder(Table::class.java)
|
||||
val rootNode = data.getCheckedNode<Table>("data", Table::class.java)
|
||||
val empty = data.getCheckedNode<Table>("empty", Table::class.java).data
|
||||
rootNode.forEachData(Table::class.java, { input ->
|
||||
val res = DataUtils.combine(input, empty, Table::class.java, input.meta()) { mergeData, emptyData ->
|
||||
subtract(context, mergeData, emptyData)
|
||||
}
|
||||
|
||||
res.goal.onComplete { r, _ ->
|
||||
if (r != null) {
|
||||
val out = context.io().out("numass.merge", input.name + "_subtract")
|
||||
ColumnedDataWriter.writeTable(out, r,
|
||||
input.meta().builder.setNode("empty", empty.meta()).toString())
|
||||
}
|
||||
}
|
||||
|
||||
builder.putData(input.name, res)
|
||||
})
|
||||
builder.build()
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
package inr.numass.models;
|
||||
|
||||
import hep.dataforge.stat.fit.ParamSet;
|
||||
import inr.numass.NumassPlugin;
|
||||
import inr.numass.NumassPluginKt;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -36,6 +36,6 @@ public class PlotScatter {
|
||||
+ "'ionW' = 11.33 ± 0.43\n"
|
||||
+ "'exIonRatio' = 4.83 ± 0.36"
|
||||
);
|
||||
LossCalculator.plotScatter(NumassPlugin.displayJFreeChart("Loss function"), pars);
|
||||
LossCalculator.plotScatter(NumassPluginKt.displayJFreeChart("Loss function"), pars);
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ package inr.numass.models;
|
||||
import hep.dataforge.maths.integration.GaussRuleIntegrator;
|
||||
import hep.dataforge.plots.PlotFrame;
|
||||
import hep.dataforge.plots.data.XYFunctionPlot;
|
||||
import inr.numass.NumassPlugin;
|
||||
import inr.numass.NumassPluginKt;
|
||||
import org.apache.commons.math3.analysis.UnivariateFunction;
|
||||
|
||||
/**
|
||||
@ -32,7 +32,7 @@ public class TestNeLossParametrisation {
|
||||
* @param args the command line arguments
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
PlotFrame frame = NumassPlugin.displayJFreeChart("Loss parametrisation test");
|
||||
PlotFrame frame = NumassPluginKt.displayJFreeChart("Loss parametrisation test");
|
||||
//JFreeChartFrame.drawFrame("Loss parametrisation test", null);
|
||||
UnivariateFunction oldFunction = LossCalculator.getSingleScatterFunction();
|
||||
UnivariateFunction newFunction = getSingleScatterFunction(12.86, 16.78, 1.65, 12.38, 4.79);
|
||||
@ -41,8 +41,8 @@ public class TestNeLossParametrisation {
|
||||
|
||||
System.out.println(norm);
|
||||
|
||||
frame.add(XYFunctionPlot.plotFunction("old", x->oldFunction.value(x), 0, 30, 300));
|
||||
frame.add(XYFunctionPlot.plotFunction("new", x->newFunction.value(x), 0, 30, 300));
|
||||
frame.add(XYFunctionPlot.plotFunction("old", oldFunction::value, 0, 30, 300));
|
||||
frame.add(XYFunctionPlot.plotFunction("new", newFunction::value, 0, 30, 300));
|
||||
}
|
||||
|
||||
public static UnivariateFunction getSingleScatterFunction(
|
||||
|
@ -19,7 +19,7 @@ import hep.dataforge.context.Global;
|
||||
import hep.dataforge.plots.data.DataPlot;
|
||||
import hep.dataforge.plots.data.XYFunctionPlot;
|
||||
import hep.dataforge.plots.jfreechart.JFreeChartFrame;
|
||||
import inr.numass.NumassPlugin;
|
||||
import inr.numass.NumassPluginKt;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -28,7 +28,7 @@ import inr.numass.NumassPlugin;
|
||||
public class TransmissionInterpolatorTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
JFreeChartFrame frame = NumassPlugin.displayJFreeChart("TransmissionInterpolatorTest");
|
||||
JFreeChartFrame frame = NumassPluginKt.displayJFreeChart("TransmissionInterpolatorTest");
|
||||
//JFreeChartFrame.drawFrame("TransmissionInterpolatorTest", null);
|
||||
TransmissionInterpolator interpolator = TransmissionInterpolator.fromFile(Global.instance(),
|
||||
"d:\\sterile-new\\loss2014-11\\.dataforge\\merge\\empty_sum.onComplete", "Uset", "CR", 15, 0.8, 19002d);
|
||||
|
Loading…
Reference in New Issue
Block a user