Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
mantidproject
mantid
Commits
23888a17
Commit
23888a17
authored
Feb 22, 2017
by
Zhou, Wenduo
Browse files
Refs #12535. Checkpointing progress on refactoring FilterEvents.
parent
9db62ea2
Changes
3
Hide whitespace changes
Inline
Side-by-side
Framework/Algorithms/src/FilterEvents.cpp
View file @
23888a17
...
...
@@ -34,6 +34,9 @@ using namespace std;
const
int64_t
TOLERANCE
(
1000000
);
// splitter time tolerance in nano-second.
// this value has resolution to 10000Hz
/// (integer) splitting target for undefined region, which will be recorded in m_splitterGroup
const
uint32_t
UNDEFINED_SPLITTING_TARGET
(
0
);
namespace
Mantid
{
namespace
Algorithms
{
...
...
@@ -197,6 +200,7 @@ void FilterEvents::exec() {
if
(
m_useSplittersWorkspace
)
{
filterEventsBySplitters
(
progressamount
);
generateSplitterTSPalpha
(
split_tsp_vector
);
}
else
{
...
...
@@ -205,8 +209,10 @@ void FilterEvents::exec() {
}
// TODO:FIXME - assign split_tsp_vector to all the output workspaces!
mapSplitterTSPtoWorkspaces
(
split_tsp_vector
);
// Optional to group detector
// TODO:FIXME - move this part to a method
if
(
m_toGroupWS
)
{
m_progress
=
0.9
;
progress
(
m_progress
,
"Group workspaces"
);
...
...
@@ -224,6 +230,7 @@ void FilterEvents::exec() {
}
}
// TODO:FIXME - move this part to a method
// Form the names of output workspaces
std
::
vector
<
std
::
string
>
outputwsnames
;
std
::
map
<
int
,
DataObjects
::
EventWorkspace_sptr
>::
iterator
miter
;
...
...
@@ -240,6 +247,7 @@ void FilterEvents::exec() {
progress
(
m_progress
,
"Completed"
);
}
//----------------------------------------------------------------------------------------------
/** Process input properties
*/
void
FilterEvents
::
processAlgorithmProperties
()
{
...
...
@@ -360,8 +368,11 @@ void FilterEvents::processAlgorithmProperties() {
}
// END-IF: m_isSplitterRelativeTime
}
/** Examine whether any spectrum does not have detector
*/
//----------------------------------------------------------------------------------------------
/** Examine whether any spectrum does not have detector
* Warning message will be written out
* @brief FilterEvents::examineEventWS
*/
void
FilterEvents
::
examineEventWS
()
{
size_t
numhist
=
m_eventWS
->
getNumberHistograms
();
m_vecSkip
.
resize
(
numhist
,
false
);
...
...
@@ -369,9 +380,10 @@ void FilterEvents::examineEventWS() {
if
(
m_specSkipType
==
EventFilterSkipNoDetTOFCorr
&&
m_tofCorrType
==
NoneCorrect
)
{
// No TOF correction and skip spectrum only if TOF correction is required
g_log
.
notice
(
"By user's choice, No spectrum will be skipped even if it has "
g_log
.
warning
(
"By user's choice, No spectrum will be skipped even if it has "
"no detector."
);
}
else
{
// check detectors whether there is any of them that will be skipped
stringstream
msgss
;
size_t
numskipspec
=
0
;
size_t
numeventsskip
=
0
;
...
...
@@ -390,7 +402,6 @@ void FilterEvents::examineEventWS() {
else
msgss
<<
","
;
}
}
// ENDFOR
if
(
numskipspec
>
0
)
{
...
...
@@ -406,8 +417,11 @@ void FilterEvents::examineEventWS() {
}
}
// END-IF-ELSE
return
;
}
//----------------------------------------------------------------------------------------------
/** Purpose:
* Convert SplitterWorkspace object to TimeSplitterType (sorted vector)
* and create a map for all workspace group number
...
...
@@ -451,6 +465,7 @@ void FilterEvents::processSplittersWorkspace() {
}
}
//----------------------------------------------------------------------------------------------
/** Convert SplittersWorkspace to vector of time and vector of target (itarget)
* NOTE: This is designed to use a single vector/vector splitters for all types of inputs
* It is not used before vast experiment on speed comparison!
...
...
@@ -470,10 +485,10 @@ void FilterEvents::convertSplittersWorkspaceToVectors()
for
(
size_t
irow
=
0
;
irow
<
num_rows
;
++
irow
)
{
Kernel
::
SplittingInterval
splitter
=
m_splittersWorkspace
->
getSplitter
(
irow
);
if
(
m_vecSplitterTime
.
size
()
==
0
||
splitter
.
start
()
>
m_vecSplitterTime
.
end
())
if
(
m_vecSplitterTime
.
size
()
==
0
||
splitter
.
start
()
>
m_vecSplitterTime
.
back
())
{
m_vecSplitterTime
.
push_back
(
splitter
.
start
());
m_vecSplitterTime
.
push_back
(
splitter
.
stop
());
m_vecSplitterTime
.
push_back
(
splitter
.
start
()
.
totalNanoseconds
()
);
m_vecSplitterTime
.
push_back
(
splitter
.
stop
()
.
totalNanoseconds
()
);
// 0 stands for not defined
m_vecSplitterGroup
.
push_back
(
0
);
}
...
...
@@ -481,7 +496,14 @@ void FilterEvents::convertSplittersWorkspaceToVectors()
}
//----------------------------------------------------------------------------------------------
/** process the input splitters given by a TableWorkspace
* The method will transfer the start/stop time to "m_vecSplitterTime"
* and map the splitting target (in string) to "m_vecSplitterGroup".
* The mapping will be recorded in "m_targetIndexMap" and "m_wsGroupIndexTargetMap".
* Also, "m_maxTargetIndex" is set up to record the highest target group/index,
* i.e., max value of m_vecSplitterGroup
*
* @brief FilterEvents::processTableSplittersWorkspace
*/
void
FilterEvents
::
processTableSplittersWorkspace
()
{
...
...
@@ -524,7 +546,7 @@ void FilterEvents::processTableSplittersWorkspace() {
// -1
m_vecSplitterTime
.
push_back
(
start_64
);
// NOTE: use index = 0 for un-defined slot
m_vecSplitterGroup
.
push_back
(
0
);
m_vecSplitterGroup
.
push_back
(
UNDEFINED_SPLITTING_TARGET
);
found_undefined_splitter
=
true
;
}
else
if
(
abs
(
start_64
-
m_vecSplitterTime
.
back
())
<
TOLERANCE
)
{
// new splitter's start time is same (within tolerance) as the stop time
...
...
@@ -533,7 +555,7 @@ void FilterEvents::processTableSplittersWorkspace() {
}
else
{
// new splitter's start time is before the stop time of the last splitter.
throw
std
::
runtime_error
(
"Input table workspace does not have splitters set up in order."
);
"Input table workspace does not have splitters set up in order
, which is a requirement
."
);
}
// convert string-target to integer target
...
...
@@ -583,16 +605,22 @@ void FilterEvents::processTableSplittersWorkspace() {
return
;
}
//----------------------------------------------------------------------------------------------
/**
* @brief FilterEvents::processMatrixSplitterWorkspace
* Purpose:
* Convert the splitters in
m
atrix
w
orkspace to
a
vec
tor of s
plitter
s
* Convert the splitters in
M
atrix
W
orkspace to
m_
vec
SplitterTime and m_vecS
plitter
Group
* Requirements:
* m_matrixSplitterWS has valid value
* vecX's size must be one larger than and that of vecY of m_matrixSplitterWS
* Guarantees
* Splitters stored in m_matrixSpliterWS are transformed to
* m_vecSplitterTime and m_workGroupIndexes, which are of same size
* - Splitters stored in m_matrixSpliterWS are transformed to
* "m_vecSplitterTime" and "m_vecSplitterGroup", whose sizes differ by 1.
* - Y values are mapped to integer group index stored in "m_vecSplitterGroup".
* The mapping is recorded in "m_yIndexMap" and "m_wsGroupdYMap"
* "m_maxTargetIndex" is used to register the maximum group index
* Negative Y is defined as "undefined"
* Note: there is NO undefined split region here, while any NEGATIVE Y value is defined as "undefined splitter"
*/
void
FilterEvents
::
processMatrixSplitterWorkspace
()
{
// Check input workspace validity
...
...
@@ -625,12 +653,13 @@ void FilterEvents::processMatrixSplitterWorkspace() {
int
y_index
=
static_cast
<
int
>
(
Y
[
i
]);
// try to find Y[i] in m_yIndexMap
std
::
map
<
int
,
uint32_t
>::
iterator
mapiter
=
m_yIndexMap
.
find
(
y_index
);
if
(
mapiter
==
m_yIndexMap
.
end
())
{
uint32_t
int_target
=
0
;
// default to 0 as undefined slot. if well-defined, then use the current
// unused max_target_index
// new
// default to 0 as undefined slot.
uint32_t
int_target
=
UNDEFINED_SPLITTING_TARGET
;
// if well-defined, then use the current
if
(
y_index
>=
0
)
{
int_target
=
max_target_index
;
++
max_target_index
;
...
...
@@ -644,7 +673,7 @@ void FilterEvents::processMatrixSplitterWorkspace() {
m_wsGroupdYMap
.
emplace
(
int_target
,
y_index
);
m_targetWorkspaceIndexSet
.
insert
(
int_target
);
}
else
{
// this target Y-index has been registered
// this target Y-index has been registered
previously
uint32_t
target_index
=
mapiter
->
second
;
m_vecSplitterGroup
[
i
]
=
target_index
;
}
...
...
@@ -656,6 +685,127 @@ void FilterEvents::processMatrixSplitterWorkspace() {
return
;
}
//----------------------------------------------------------------------------------------------
/** Create a list of EventWorkspace for output in the case that splitters are given by
* SplittersWorkspace
*/
void
FilterEvents
::
createOutputWorkspaces
()
{
// Convert information workspace to map
std
::
map
<
int
,
std
::
string
>
infomap
;
if
(
m_hasInfoWS
)
{
for
(
size_t
ir
=
0
;
ir
<
m_informationWS
->
rowCount
();
++
ir
)
{
API
::
TableRow
row
=
m_informationWS
->
getRow
(
ir
);
infomap
.
emplace
(
row
.
Int
(
0
),
row
.
String
(
1
));
}
}
// Determine the minimum group index number
int
minwsgroup
=
INT_MAX
;
for
(
auto
wsgroup
:
m_targetWorkspaceIndexSet
)
{
if
(
wsgroup
<
minwsgroup
&&
wsgroup
>=
0
)
minwsgroup
=
wsgroup
;
}
g_log
.
debug
()
<<
"Min WS Group = "
<<
minwsgroup
<<
"
\n
"
;
bool
from1
=
getProperty
(
"OutputWorkspaceIndexedFrom1"
);
int
delta_wsindex
=
0
;
if
(
from1
)
{
delta_wsindex
=
1
-
minwsgroup
;
}
// Set up new workspaces
int
numoutputws
=
0
;
double
numnewws
=
static_cast
<
double
>
(
m_targetWorkspaceIndexSet
.
size
());
double
wsgindex
=
0.
;
for
(
auto
const
wsgroup
:
m_targetWorkspaceIndexSet
)
{
// Generate new workspace name
bool
add2output
=
true
;
std
::
stringstream
wsname
;
if
(
wsgroup
>=
0
)
{
wsname
<<
m_outputWSNameBase
<<
"_"
<<
(
wsgroup
+
delta_wsindex
);
}
else
{
wsname
<<
m_outputWSNameBase
<<
"_unfiltered"
;
if
(
from1
)
add2output
=
false
;
}
boost
::
shared_ptr
<
EventWorkspace
>
optws
=
create
<
DataObjects
::
EventWorkspace
>
(
*
m_eventWS
);
m_outputWorkspacesMap
.
emplace
(
wsgroup
,
optws
);
// Add information, including title and comment, to output workspace
if
(
m_hasInfoWS
)
{
std
::
string
info
;
if
(
wsgroup
<
0
)
{
info
=
"Events that are filtered out. "
;
}
else
{
std
::
map
<
int
,
std
::
string
>::
iterator
infoiter
;
infoiter
=
infomap
.
find
(
wsgroup
);
if
(
infoiter
!=
infomap
.
end
())
{
info
=
infoiter
->
second
;
}
else
{
info
=
"This workspace has no informatin provided. "
;
}
}
optws
->
setComment
(
info
);
optws
->
setTitle
(
info
);
}
// END-IF infor WS
// Add to output properties. There shouldn't be any workspace
// (non-unfiltered) skipped from group index
if
(
add2output
)
{
// Generate output property name
std
::
stringstream
propertynamess
;
if
(
wsgroup
==
-
1
)
{
propertynamess
<<
"OutputWorkspace_unfiltered"
;
}
else
{
propertynamess
<<
"OutputWorkspace_"
<<
wsgroup
;
}
// Inserted this pair to map
m_wsNames
.
push_back
(
wsname
.
str
());
// Set (property) to output workspace and set to ADS
declareProperty
(
Kernel
::
make_unique
<
API
::
WorkspaceProperty
<
DataObjects
::
EventWorkspace
>>
(
propertynamess
.
str
(),
wsname
.
str
(),
Direction
::
Output
),
"Output"
);
setProperty
(
propertynamess
.
str
(),
optws
);
AnalysisDataService
::
Instance
().
addOrReplace
(
wsname
.
str
(),
optws
);
++
numoutputws
;
g_log
.
debug
()
<<
"Created output Workspace of group = "
<<
wsgroup
<<
" Property Name = "
<<
propertynamess
.
str
()
<<
" Workspace name = "
<<
wsname
.
str
()
<<
" with Number of events = "
<<
optws
->
getNumberEvents
()
<<
"
\n
"
;
// Update progress report
m_progress
=
0.1
+
0.1
*
wsgindex
/
numnewws
;
progress
(
m_progress
,
"Creating output workspace"
);
wsgindex
+=
1.
;
}
// If add workspace to output
}
// ENDFOR
// Set output and do debug report
setProperty
(
"NumberOutputWS"
,
numoutputws
);
g_log
.
information
(
"Output workspaces are created. "
);
}
//----------------------------------------------------------------------------------------------
/** Create output EventWorkspaces in the case that the splitters are given by MatrixWorkspace
* Here is the list of class variables that will be updated:
* - m_outputWorkspacesMap: use (integer) group index to find output EventWorkspace
* - m_wsNames: vector of output workspaces
* @brief FilterEvents::createOutputWorkspacesMatrixCase
*/
void
FilterEvents
::
createOutputWorkspacesMatrixCase
()
{
// check condition
if
(
!
m_matrixSplitterWS
)
{
...
...
@@ -671,10 +821,12 @@ void FilterEvents::createOutputWorkspacesMatrixCase() {
size_t
wsgindex
=
0
;
for
(
auto
const
wsgroup
:
m_targetWorkspaceIndexSet
)
{
std
::
stringstream
wsname
;
if
(
wsgroup
<
0
)
throw
std
::
runtime_error
(
"It is not possible to have split-target group index < 0 in MatrixWorkspace case."
);
// workspace name
if
(
wsgroup
>=
0
)
{
std
::
stringstream
wsname
;
if
(
wsgroup
>
0
)
{
// std::string target_name = m_wsGroupIndexTargetMap[wsgroup];
int
target_name
=
m_wsGroupdYMap
[
wsgroup
];
wsname
<<
m_outputWSNameBase
<<
"_"
<<
target_name
;
...
...
@@ -682,7 +834,7 @@ void FilterEvents::createOutputWorkspacesMatrixCase() {
wsname
<<
m_outputWSNameBase
<<
"_unfiltered"
;
}
// create new workspace
// create new workspace
from input EventWorkspace and all the sample logs are copied to the new one
boost
::
shared_ptr
<
EventWorkspace
>
optws
=
create
<
DataObjects
::
EventWorkspace
>
(
*
m_eventWS
);
m_outputWorkspacesMap
.
emplace
(
wsgroup
,
optws
);
...
...
@@ -728,6 +880,13 @@ void FilterEvents::createOutputWorkspacesMatrixCase() {
return
;
}
//----------------------------------------------------------------------------------------------
/** Create output EventWorkspaces in the case that the splitters are given by TableWorkspace
* Here is the list of class variables that will be updated:
* - m_outputWorkspacesMap: use (integer) group index to find output EventWorkspace
* - m_wsNames: vector of output workspaces
* @brief FilterEvents::createOutputWorkspacesMatrixCase
*/
void
FilterEvents
::
createOutputWorkspacesTableSplitterCase
()
{
// check condition
if
(
!
m_useArbTableSplitters
)
{
...
...
@@ -741,10 +900,13 @@ void FilterEvents::createOutputWorkspacesTableSplitterCase() {
size_t
wsgindex
=
0
;
for
(
auto
const
wsgroup
:
m_targetWorkspaceIndexSet
)
{
std
::
stringstream
wsname
;
if
(
wsgroup
<
0
)
throw
std
::
runtime_error
(
"It is not possible to have split-target group index < 0 in TableWorkspace case."
);
// workspace name
if
(
wsgroup
>=
0
)
{
std
::
stringstream
wsname
;
if
(
wsgroup
>
0
)
{
// get target name via map
std
::
string
target_name
=
m_wsGroupIndexTargetMap
[
wsgroup
];
wsname
<<
m_outputWSNameBase
<<
"_"
<<
target_name
;
}
else
{
...
...
@@ -797,117 +959,6 @@ void FilterEvents::createOutputWorkspacesTableSplitterCase() {
return
;
}
/** Create a list of EventWorkspace for output
*/
void
FilterEvents
::
createOutputWorkspaces
()
{
// Convert information workspace to map
std
::
map
<
int
,
std
::
string
>
infomap
;
if
(
m_hasInfoWS
)
{
for
(
size_t
ir
=
0
;
ir
<
m_informationWS
->
rowCount
();
++
ir
)
{
API
::
TableRow
row
=
m_informationWS
->
getRow
(
ir
);
infomap
.
emplace
(
row
.
Int
(
0
),
row
.
String
(
1
));
}
}
// Determine the minimum group index number
int
minwsgroup
=
INT_MAX
;
for
(
auto
wsgroup
:
m_targetWorkspaceIndexSet
)
{
if
(
wsgroup
<
minwsgroup
&&
wsgroup
>=
0
)
minwsgroup
=
wsgroup
;
}
g_log
.
debug
()
<<
"Min WS Group = "
<<
minwsgroup
<<
"
\n
"
;
bool
from1
=
getProperty
(
"OutputWorkspaceIndexedFrom1"
);
int
delta_wsindex
=
0
;
if
(
from1
)
{
delta_wsindex
=
1
-
minwsgroup
;
}
// Set up new workspaces
int
numoutputws
=
0
;
double
numnewws
=
static_cast
<
double
>
(
m_targetWorkspaceIndexSet
.
size
());
double
wsgindex
=
0.
;
for
(
auto
const
wsgroup
:
m_targetWorkspaceIndexSet
)
{
// Generate new workspace name
bool
add2output
=
true
;
std
::
stringstream
wsname
;
if
(
wsgroup
>=
0
)
{
wsname
<<
m_outputWSNameBase
<<
"_"
<<
(
wsgroup
+
delta_wsindex
);
}
else
{
wsname
<<
m_outputWSNameBase
<<
"_unfiltered"
;
if
(
from1
)
add2output
=
false
;
}
boost
::
shared_ptr
<
EventWorkspace
>
optws
=
create
<
DataObjects
::
EventWorkspace
>
(
*
m_eventWS
);
m_outputWorkspacesMap
.
emplace
(
wsgroup
,
optws
);
// Add information, including title and comment, to output workspace
if
(
m_hasInfoWS
)
{
std
::
string
info
;
if
(
wsgroup
<
0
)
{
info
=
"Events that are filtered out. "
;
}
else
{
std
::
map
<
int
,
std
::
string
>::
iterator
infoiter
;
infoiter
=
infomap
.
find
(
wsgroup
);
if
(
infoiter
!=
infomap
.
end
())
{
info
=
infoiter
->
second
;
}
else
{
info
=
"This workspace has no informatin provided. "
;
}
}
optws
->
setComment
(
info
);
optws
->
setTitle
(
info
);
}
// END-IF infor WS
// Add to output properties. There shouldn't be any workspace
// (non-unfiltered) skipped from group index
if
(
add2output
)
{
// Generate output property name
std
::
stringstream
propertynamess
;
if
(
wsgroup
==
-
1
)
{
propertynamess
<<
"OutputWorkspace_unfiltered"
;
}
else
{
propertynamess
<<
"OutputWorkspace_"
<<
wsgroup
;
}
// Inserted this pair to map
m_wsNames
.
push_back
(
wsname
.
str
());
// Set (property) to output workspace and set to ADS
declareProperty
(
Kernel
::
make_unique
<
API
::
WorkspaceProperty
<
DataObjects
::
EventWorkspace
>>
(
propertynamess
.
str
(),
wsname
.
str
(),
Direction
::
Output
),
"Output"
);
setProperty
(
propertynamess
.
str
(),
optws
);
AnalysisDataService
::
Instance
().
addOrReplace
(
wsname
.
str
(),
optws
);
++
numoutputws
;
g_log
.
debug
()
<<
"Created output Workspace of group = "
<<
wsgroup
<<
" Property Name = "
<<
propertynamess
.
str
()
<<
" Workspace name = "
<<
wsname
.
str
()
<<
" with Number of events = "
<<
optws
->
getNumberEvents
()
<<
"
\n
"
;
// Update progress report
m_progress
=
0.1
+
0.1
*
wsgindex
/
numnewws
;
progress
(
m_progress
,
"Creating output workspace"
);
wsgindex
+=
1.
;
}
// If add workspace to output
}
// ENDFOR
// Set output and do debug report
setProperty
(
"NumberOutputWS"
,
numoutputws
);
g_log
.
information
(
"Output workspaces are created. "
);
}
/** Set up neutron event's TOF correction.
* It can be (1) parsed from TOF-correction table workspace to vectors,
* (2) created according to detector's position in instrument;
...
...
@@ -1468,6 +1519,7 @@ void FilterEvents::splitLog(EventWorkspace_sptr eventws, std::string logname,
/** Generate a vector of integer time series property for each splitter corresponding to each target (in integer)
* in each splitter-time-series-property, 1 stands for include and 0 stands for time for neutrons to be discarded.
* If there is no UN-DEFINED
* @brief FilterEvents::generateSplitterTSP
* @param split_tsp_vec
*/
...
...
Framework/Algorithms/test/FilterEventsTest.h
View file @
23888a17
...
...
@@ -544,7 +544,7 @@ public:
* (2) Count events in each output including "-1", the excluded/unselected
*events
*/
void
X
test_FilterRelativeTime
()
{
void
test_FilterRelativeTime
()
{
// Create EventWorkspace and SplittersWorkspace
int64_t
runstart_i64
=
20000000000
;
int64_t
pulsedt
=
100
*
1000
*
1000
;
...
...
@@ -806,8 +806,9 @@ public:
// add some arbitrary sample log for splitting or not splitting
eventWS
->
mutableRun
().
addProperty
(
new
Kernel
::
PropertyWithValue
<
std
::
string
>
(
"LogA"
,
"A"
));
// eventWS->mutableRun().addProperty("LogB", "B", true);
// eventWS->mutableRun().addProperty("Title", "Testing EventWorkspace");
eventWS
->
mutableRun
().
addProperty
(
new
Kernel
::
PropertyWithValue
<
std
::
string
>
(
"LogB"
,
"B"
));
eventWS
->
mutableRun
().
addProperty
(
new
Kernel
::
PropertyWithValue
<
std
::
string
>
(
"LogC"
,
"C"
),
true
);
eventWS
->
mutableRun
().
addProperty
(
new
Kernel
::
PropertyWithValue
<
std
::
string
>
(
"Title"
,
"Testing EventWorkspace"
));
// add an integer slow log
auto
int_tsp
=
Kernel
::
make_unique
<
Kernel
::
TimeSeriesProperty
<
int
>
>
(
"slow_int_log"
);
...
...
docs/source/algorithms/FilterEvents-v1.rst
View file @
23888a17
...
...
@@ -94,6 +94,25 @@ Comparing with other event filtering algorithms
Wiki page :ref:`EventFiltering` has a detailed introduction on event
filtering in MantidPlot.
Developer's Note
----------------
Splitters given by TableWorkspace
=================================
- The *start/stop* time is converted to **m_vecSplitterTime**.
- The *splitting target* (in string) is mapped to a set of continuous integers that are stored in **m_vecSplitterGroup**.
- The mapping will be recorded in **m_targetIndexMap** and **m_wsGroupIndexTargetMap**.
- Class variable **m_maxTargetIndex** is set up to record the highest target group/index,i.e., the max value of m_vecSplitterGroup
Undefined splitting target
==========================
Indexed as **0** in **m_vecSplitterGroup**.
Usage
-----
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment