diff --git a/Documentation/content/index.jade b/Documentation/content/index.jade
index 76caa5c..f0d2744 100644
--- a/Documentation/content/index.jade
+++ b/Documentation/content/index.jade
@@ -51,7 +51,10 @@ ul#intro-feature-list(style="position:relative;margin-top:0;padding-top:0;")
VeraInView is a standalone Web application that visualizes the geometry from VERAin simulation input files. The
a(href="users_guide/").link user's guide
span.
- can get you started.
+ can get you started. Sample files can be found in the
+ a(href="https://github.com/CASL/VERAin/tree/master/verain/Progression_Problems/GOLD") VERAin testing
+ span.
+ folder.
li.intro-feature-wrap
.intro-feature
diff --git a/src/EditView.js b/src/EditView.js
index 24c2e67..8041c51 100644
--- a/src/EditView.js
+++ b/src/EditView.js
@@ -87,10 +87,10 @@ const TEMPLATES = {
};
const GROUP_TYPES = [
- { label: 'Assembly', group: 'assemblies' },
- { label: 'Insert', group: 'inserts' },
- { label: 'Control', group: 'controls' },
- { label: 'Detector', group: 'detectors' },
+ { label: 'Assembly', group: 'assemblies', coremap: 'assm_map' },
+ { label: 'Insert', group: 'inserts', coremap: 'insert_map' },
+ { label: 'Control', group: 'controls', coremap: 'crd_map' },
+ { label: 'Detector', group: 'detectors', coremap: 'det_map' },
];
// todo get from vtk-js
@@ -211,13 +211,15 @@ export default class EditView extends React.Component {
onMenuNew(type, group) {
// create a new item based on the currently selected one.
- // state.content holds the current item.
+ // state.content holds the current item. Might be null for coremaps.
const base =
capitalize(type) !== this.state.path[0]
? TEMPLATES[type]
- : this.state.content;
+ : this.state.content || TEMPLATES[type];
const newItem = EDITORS[capitalize(type)].createNew(base);
newItem.group = group;
+ // need to override ID for coremaps so they are selectable in the menu
+ if (type === 'coremaps') newItem.id = `${newItem.group}-1`;
if (newItem.label !== undefined) {
newItem.label = uniqueLabel(newItem.label, this.state[type]);
if (newItem.labelToUse !== undefined) {
@@ -385,9 +387,15 @@ export default class EditView extends React.Component {
labelMap[assembly.id] = assembly;
});
+ let foundSomething = false;
groupList.forEach((group) => {
if (newState[group]) {
newState[group].forEach((assembly) => {
+ // inserts only set num_pins, not ppitch
+ if (assembly.num_pins && assembly.ppitch) {
+ params.numPins = Math.max(params.numPins, assembly.num_pins);
+ params.pinPitch = Math.max(params.pinPitch, assembly.ppitch);
+ }
let count = assembly.layout.length;
while (count--) {
const layout = assembly.layout[count];
@@ -396,16 +404,9 @@ export default class EditView extends React.Component {
const numPins = assembly.num_pins;
layout.numPins = numPins;
layout.group = group;
- const map = [];
- for (let i = 0; i < numPins; ++i) {
- map.push(
- layout.cell_map
- .slice(i * numPins, (i + 1) * numPins)
- .join(' ')
- );
- }
- layout.cellMap = map.join('\n');
+ InpHelper.setSymmetry(layout, params);
newLayout.unshift(layout);
+ foundSomething = true;
labelMap[layout.id] = layout;
}
}
@@ -413,25 +414,45 @@ export default class EditView extends React.Component {
if (!labelMap[assembly.id]) {
assembly.group = group;
newAssemblies.unshift(assembly);
+ foundSomething = true;
labelMap[assembly.id] = assembly;
}
- // inserts only set num_pins, not ppitch
- if (assembly.num_pins && assembly.ppitch) {
- params.numPins = Math.max(params.numPins, assembly.num_pins);
- params.pinPitch = Math.max(params.pinPitch, assembly.ppitch);
- }
- });
- if (newState.core) {
- params.numAssemblies = newState.core.numAssemblies;
- params.assemblyPitch = newState.core.assemblyPitch;
- }
- this.setState({
- rodmaps: newLayout,
- assemblies: newAssemblies,
- params,
});
}
});
+ if (foundSomething) {
+ this.setState({
+ rodmaps: newLayout,
+ assemblies: newAssemblies,
+ params,
+ });
+ }
+ if (newState.core) {
+ params.numAssemblies = newState.core.numAssemblies;
+ params.assemblyPitch = newState.core.assemblyPitch;
+ params.coreShapeMap = newState.core.shape;
+ const coremaps = [];
+ GROUP_TYPES.forEach((info) => {
+ const coremap = newState.core[info.coremap];
+ if (coremap) {
+ const newMap = {
+ id: `${info.group}-1`,
+ type: 'coremaps',
+ label: info.label,
+ cell_map: coremap,
+ group: info.group,
+ };
+ InpHelper.setSymmetry(newMap, params);
+ console.log(newMap);
+ coremaps.push(newMap);
+ }
+ });
+
+ this.setState({
+ params,
+ coremaps,
+ });
+ }
console.log('editor', newState);
});
return false;
@@ -540,30 +561,25 @@ export default class EditView extends React.Component {
const coremaps = this.state.coremaps.filter(
(a) => a.group === info.group
);
+ // menu item key must match ID of the single coremap per type.
return (
-
this.onMenuNew('coremaps', info.group)
- }
- />
- }
- >
- {coremaps.map((a) => (
-
-
-
- {a.labelToUse || a.label}
-
-
- ))}
-
+
+
+
+ {`${info.label} Map`}
+
+ {coremaps.length === 0 && (
+
+
);
}
return null;
diff --git a/src/MainView.js b/src/MainView.js
index d3fea3b..307492f 100644
--- a/src/MainView.js
+++ b/src/MainView.js
@@ -11,6 +11,7 @@ import macro from 'vtk.js/Sources/macro';
import Color from './widgets/Color';
import ImageRenderer from './widgets/ImageRenderer';
import VTKRenderer from './widgets/VTKRenderer';
+import CellTip from './widgets/CellTip';
import ModelHelper from './utils/ModelHelper';
import ImageGenerator from './utils/ImageGenerator';
@@ -172,15 +173,11 @@ export default class MainView extends React.Component {
const { item } = this.getSelectionByKey(this.state.lastKey);
if (this.state.has3D && this.state.has3D.type === 'layout') {
const { cell } = ImageGenerator.getLayoutCell(item, posx, posy);
- return cell;
+ return `Cell: ${cell}`;
}
if (this.state.has3D && this.state.has3D.type === 'cell') {
const mat = ImageGenerator.getCellMaterial(item, posx, posy);
- return mat ? (
-
- {mat.radius} cm
{mat.mat}
-
- ) : null;
+ return mat ? : null;
}
return null;
}
diff --git a/src/utils/ColorManager.js b/src/utils/ColorManager.js
index 2490fd7..93ed963 100644
--- a/src/utils/ColorManager.js
+++ b/src/utils/ColorManager.js
@@ -45,7 +45,11 @@ function createColorManager(palette = PALETTE) {
// if all have been used.
let minLengthSeen = 1000;
Object.keys(colorInfo).forEach((infoRGBA) => {
- if (!rgba || colorInfo[infoRGBA].names.length < minLengthSeen) {
+ // avoid assigning colors with a '0' alpha
+ if (
+ colorInfo[infoRGBA].color[3] > 0 &&
+ (!rgba || colorInfo[infoRGBA].names.length < minLengthSeen)
+ ) {
rgba = infoRGBA;
minLengthSeen = colorInfo[infoRGBA].names.length;
}
diff --git a/src/utils/ImageGenerator.js b/src/utils/ImageGenerator.js
index 1b08c46..90e2d97 100644
--- a/src/utils/ImageGenerator.js
+++ b/src/utils/ImageGenerator.js
@@ -516,9 +516,11 @@ function updateItemWithLayoutImages(
}
// ----------------------------------------------------------------------------
-// key will be "ASSEMBLIES;1:" if not present at this elevation,
+// return will be "ASSEMBLIES;1:" if not present at this elevation,
// or "ASSEMBLIES;1:PLEN" if present.
-function getElevationKey(map, key, elevation) {
+function getElevationKey(map, itemMap, itemMapkey, elevation) {
+ if (!itemMap) return ':';
+ const key = itemMap[itemMapkey];
const layoutItem = map[key];
if (!layoutItem) {
return `${map.__category};${key}:`.replace(/-/g, '');
@@ -668,9 +670,9 @@ function computeCoreColorsAt(elevation, core) {
const lastColorManager = colorManagerByElevation[lastElevation];
lastElevation = elevation;
- assemMap.forEach((tag) => {
+ assemMap.forEach((tag, i) => {
const assemKey = assemMap
- ? getElevationKey(LAYOUT_MAP.ASSEMBLIES, tag, elevation)
+ ? getElevationKey(LAYOUT_MAP.ASSEMBLIES, assemMap, i, elevation)
: ':';
// assign a color only if there's a tag for a cellmap.
if (assemKey.split(':')[1].length) {
@@ -695,8 +697,10 @@ function computeCoreColorsAt(elevation, core) {
];
processingList.forEach((entry) => {
const [container, keyMap] = entry;
- keyMap.forEach((tag) => {
- const key = keyMap ? getElevationKey(container, tag, elevation) : ':';
+ keyMap.forEach((tag, i) => {
+ const key = keyMap
+ ? getElevationKey(container, keyMap, i, elevation)
+ : ':';
if (key.split(':')[1].length) {
let prevColor = null;
if (lastColorManager) {
@@ -814,31 +818,43 @@ function computeCore2ImageAt(elevation, core, size = 1500, edge = 250) {
if (coreShape[i + j * coreSize]) {
// if the coremap has an assembly at this location, tag comes before the ':'
// if the assembly has a cellmap at this elevation, tag comes after ':'
- const assemKey = assemMap
- ? getElevationKey(LAYOUT_MAP.ASSEMBLIES, assemMap[pidx], elevation)
- : ':';
+ const assemKey = getElevationKey(
+ LAYOUT_MAP.ASSEMBLIES,
+ assemMap,
+ pidx,
+ elevation
+ );
// assign a color only if there's a tag for a cellmap.
const assemColor = assemKey.split(':')[1].length
? localColorManager.getColorRGBA(assemKey)
: null;
- const ctrKey = ctrlMap
- ? getElevationKey(LAYOUT_MAP.CONTROLS, ctrlMap[pidx], elevation)
- : ':';
+ const ctrKey = getElevationKey(
+ LAYOUT_MAP.CONTROLS,
+ ctrlMap,
+ pidx,
+ elevation
+ );
const ctrColor = ctrKey.split(':')[1].length
? localColorManager.getColorRGBA(ctrKey)
: null;
- const detKey = detMap
- ? getElevationKey(LAYOUT_MAP.DETECTORS, detMap[pidx], elevation)
- : ':';
+ const detKey = getElevationKey(
+ LAYOUT_MAP.DETECTORS,
+ detMap,
+ pidx,
+ elevation
+ );
const detColor = detKey.split(':')[1].length
? localColorManager.getColorRGBA(detKey)
: null;
- const insKey = insMap
- ? getElevationKey(LAYOUT_MAP.INSERTS, insMap[pidx], elevation)
- : ':';
+ const insKey = getElevationKey(
+ LAYOUT_MAP.INSERTS,
+ insMap,
+ pidx,
+ elevation
+ );
const insColor = insKey.split(':')[1].length
? localColorManager.getColorRGBA(insKey)
: null;
diff --git a/src/utils/InpHelper.js b/src/utils/InpHelper.js
index 35c623b..26cb311 100644
--- a/src/utils/InpHelper.js
+++ b/src/utils/InpHelper.js
@@ -37,9 +37,9 @@ function getFullMap(rodmap, params) {
// Verify items in the cellMap. Unrecognized cells are empty.
const symmetry = rodmap.symmetry || 'none';
const numPins = getNumPins(rodmap, params);
- let cellMap = rodmap.cellMap.trim();
- if (cellMap !== '') cellMap = cellMap.split(/[\n]+/);
- else cellMap = [];
+ let cellMap = [];
+ if (rodmap.cellMap) cellMap = rodmap.cellMap.split(/[\n]+/);
+
cellMap.forEach((row, i) => {
cellMap[i] = row.trim().split(/[,\s]+/);
cellMap[i].forEach((c, j) => {
@@ -89,10 +89,27 @@ function getFullMap(rodmap, params) {
return cellMap.reduce((p, row) => p.concat(row));
}
+function padCellMap(rodmap, params) {
+ // if a coremap hasn't been initialized, it will
+ // have short rows where core_shape is zero. Pad with '-'
+ const numPins = getNumPins(rodmap, params);
+ if (params.coreShapeMap && rodmap.cell_map.length !== numPins * numPins) {
+ let pidx = 0;
+ const newMap = params.coreShapeMap.map((occupied, i) => {
+ if (!occupied) return '-';
+ return rodmap.cell_map[pidx++];
+ });
+ rodmap.cell_map = newMap;
+ }
+}
+
// rodmaps from xml don't have their symmetry set -
// test and set symmetry and text map.
function setSymmetry(rodmap, params) {
if (rodmap.symmetry === undefined) {
+ if (rodmap.type === 'coremaps') {
+ padCellMap(rodmap, params);
+ }
const saveTextMap = rodmap.cellMap;
rodmap.symmetry = 'oct';
rodmap.cellMap = getTextMap(rodmap, params);
@@ -112,8 +129,8 @@ function setSymmetry(rodmap, params) {
true
)
) {
- rodmap.cellMap = saveTextMap;
rodmap.symmetry = 'none';
+ rodmap.cellMap = saveTextMap || getTextMap(rodmap, params);
}
}
}
@@ -121,6 +138,20 @@ function setSymmetry(rodmap, params) {
const labelCompare = (a, b) => a.label.localeCompare(b.label);
+// anywhere the core map has zero, strip '-' from the text map.
+function stripCoreZeros(textMap, coreMap) {
+ const coreRows = coreMap
+ .split('\n')
+ .map((line) => line.trim().split(/[,\s]+/));
+ const lines = textMap.split('\n').map((line, i) => {
+ const row = line.trim().split(/[,\s]+/);
+ return row
+ .map((cell, j) => (coreRows[i][j] === '0' ? ' ' : cell))
+ .join(' ');
+ // .trim();
+ });
+ return lines.join('\n');
+}
// inverse of 'parseFile' - take a state, and write as much as
// we can to .inp format, as a string.
function writeToInp(state, GROUP_TYPES) {
@@ -135,9 +166,49 @@ function writeToInp(state, GROUP_TYPES) {
result.push(` apitch ${state.params.assemblyPitch}`);
const groupTitles = {};
+ let coreShapeMap = null;
+ // set title, build a core_shape array.
+ // Set locations occupied in any map to 1, empty to 0
state.coremaps.forEach((cm) => {
groupTitles[cm.group] = cm.label;
+ if (!coreShapeMap) coreShapeMap = cm.cell_map.map((c) => 0);
+ cm.cell_map.forEach((cell, i) => {
+ if (cell !== '-') coreShapeMap[i] = 1;
+ });
});
+ if (coreShapeMap) {
+ const coreShape = {
+ type: 'coremaps',
+ symmetry: 'none',
+ cell_map: coreShapeMap,
+ };
+ const coreText = getTextMap(coreShape, state.params);
+ result.push('\n core_shape');
+ coreText.split('\n').forEach((line) => {
+ result.push(` ${line}`);
+ });
+
+ // get symmetry text maps for comparison with assemblies.
+ const coreMaps = {
+ none: coreText,
+ oct: (coreShape.symmetry = 'oct') && getTextMap(coreShape, state.params),
+ quad:
+ (coreShape.symmetry = 'quad') && getTextMap(coreShape, state.params),
+ };
+ GROUP_TYPES.forEach((info) => {
+ const mapList = state.coremaps.filter((a) => a.group === info.group);
+ if (!mapList.length) return;
+ const assemMap = mapList[0];
+ result.push(`\n ${info.coremap}`);
+ setSymmetry(assemMap, state.params);
+ let textMap = getTextMap(assemMap, state.params);
+ // strips locations that are '0' in coreShape map.
+ textMap = stripCoreZeros(textMap, coreMaps[assemMap.symmetry]);
+ textMap.split('\n').forEach((line) => {
+ result.push(` ${line}`);
+ });
+ });
+ }
GROUP_TYPES.forEach((info) => {
const isAssembly = info.label === 'Assembly';
@@ -226,5 +297,6 @@ export default {
getNumPins,
getTextMap,
getFullMap,
+ setSymmetry,
writeToInp,
};
diff --git a/src/utils/ModelHelper.js b/src/utils/ModelHelper.js
index d356ff0..cda0623 100644
--- a/src/utils/ModelHelper.js
+++ b/src/utils/ModelHelper.js
@@ -508,6 +508,18 @@ function parseFile(file, imageSize, updateFn) {
core.stack.has3D.stroke = controls[0].stroke;
core.stack.has3D.maxstep = controls[0].maxstep;
}
+ // add maps for editor
+ [
+ 'assm_map',
+ 'crd_map',
+ 'det_map',
+ 'insert_map',
+ 'crd_bank',
+ 'shape',
+ ].forEach((mapName) => {
+ const map = dataModel.CASEID.CORE[mapName];
+ if (map) core[mapName] = [].concat(map);
+ });
count = elevations.length - 1;
while (count--) {
diff --git a/src/widgets/AssemblyLayoutEditor.js b/src/widgets/AssemblyLayoutEditor.js
index bb1442a..3a5109c 100644
--- a/src/widgets/AssemblyLayoutEditor.js
+++ b/src/widgets/AssemblyLayoutEditor.js
@@ -332,7 +332,7 @@ export default class AssemblyLayoutEditor extends React.Component {
posx,
posy
);
- return cell;
+ return `${cell}`;
}}
onClick={this.on2DClick}
/>
diff --git a/src/widgets/CellEditor.js b/src/widgets/CellEditor.js
index c4417d7..5b9a653 100644
--- a/src/widgets/CellEditor.js
+++ b/src/widgets/CellEditor.js
@@ -2,11 +2,12 @@ import React from 'react';
import PropTypes from 'prop-types';
// import ReactCursorPosition from 'react-cursor-position';
-import { Form, Input, Button, Select, Row, Col } from 'antd';
+import { Form, Input, InputNumber, Button, Select, Row, Col } from 'antd';
// import macro from 'vtk.js/Sources/macro';
import DualRenderer from './DualRenderer';
import ImageGenerator from '../utils/ImageGenerator';
+import CellTip from './CellTip';
import style from '../assets/vera.mcss';
@@ -55,7 +56,9 @@ export default class CellEditor extends React.Component {
this.onFieldUpdate = this.onFieldUpdate.bind(this);
this.addNew = this.addNew.bind(this);
- this.onRadiiUpdate = this.onRadiiUpdate.bind(this);
+ // this.onRadiiUpdate = this.onRadiiUpdate.bind(this);
+ this.onRadiiAdd = this.onRadiiAdd.bind(this);
+ this.onRadiiDelete = this.onRadiiDelete.bind(this);
this.onMaterialUpdate = this.onMaterialUpdate.bind(this);
this.update3D = this.update3D.bind(this);
}
@@ -77,11 +80,17 @@ export default class CellEditor extends React.Component {
this.update3D();
}
- onRadiiUpdate(e) {
- const radii = e.target.value
- .split(/[,\s]+/)
- .map((s) => s.trim())
- .map((s) => Number(s));
+ onRadiiUpdate(id, value) {
+ // const id = e.target.dataset.id;
+ // const newRadii = e.target.value
+ // .split(/[,\s]+/)
+ // .map((s) => s.trim())
+ // .map((s) => Number(s));
+ const radii = [].concat(this.props.content.radii);
+
+ // radii.splice(id, 1, ...newRadii);
+ radii[id] = value;
+ console.log(radii);
const numRings = radii.length;
const mats = [].concat(this.props.content.mats);
if (numRings > 0 && mats.length === 0) {
@@ -93,13 +102,32 @@ export default class CellEditor extends React.Component {
while (mats.length > numRings) {
mats.pop();
}
- this.props.content.radiiStr = e.target.value;
+ // this.props.content.radiiStr = e.target.value;
this.props.content.radii = radii;
this.props.content.num_rings = numRings;
this.props.content.mats = mats;
this.update3D();
}
+ onRadiiAdd(e) {
+ const id = e.target.dataset.id;
+ this.props.content.radii.splice(id, 0, this.props.content.radii[id]);
+ console.log(id, this.props.content.radii);
+ this.props.content.mats.splice(id, 0, this.props.content.mats[id]);
+ this.props.content.num_rings += 1;
+ this.update3D();
+ }
+ onRadiiDelete(e) {
+ const id = e.target.dataset.id;
+ if (this.props.content.num_rings > 1) {
+ this.props.content.radii.splice(id, 1);
+ console.log(id, this.props.content.radii);
+ this.props.content.mats.splice(id, 1);
+ this.props.content.num_rings -= 1;
+ this.update3D();
+ }
+ }
+
onMaterialUpdate(value) {
const [idx, name] = value.split('::');
this.props.content.mats[Number(idx)] = name;
@@ -130,7 +158,7 @@ export default class CellEditor extends React.Component {
}
render() {
- /* eslint-disable react/no-array-index-key */
+ /* eslint-disable react/no-array-index-key, react/jsx-no-bind */
return (
diff --git a/src/widgets/CellTip.js b/src/widgets/CellTip.js
new file mode 100644
index 0000000..f0c357a
--- /dev/null
+++ b/src/widgets/CellTip.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default function cellTip(props) {
+ return props.mat ? (
+
+
+ Radius:
+ Material:
+
+
+ {props.mat.radius} cm
+ {props.mat.mat}
+
+
+ ) : null;
+}
+
+cellTip.propTypes = {
+ mat: PropTypes.object,
+};
+
+cellTip.defaultProps = {
+ mat: null,
+};
diff --git a/src/widgets/ImageRenderer.js b/src/widgets/ImageRenderer.js
index a89c67c..a24328f 100644
--- a/src/widgets/ImageRenderer.js
+++ b/src/widgets/ImageRenderer.js
@@ -29,6 +29,7 @@ export default class ImageRenderer extends React.Component {
elementDimensions: { width = 0, height = 0 } = {},
position: { x = 0, y = 0 } = {},
} = this.props;
+ // console.log(x, y);
// pass position as 0 -> 1
const posx = (x - this.props.pad) / (width - 2 * this.props.pad);
@@ -48,6 +49,7 @@ export default class ImageRenderer extends React.Component {
delayShow={50}
scrollHide
getContent={this.getTooltip}
+ isCapture
ref={(c) => {
this.tooltipRef = c;
}}