Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Maintenance - Mise à jour mensuelle Lundi 6 Février entre 7h00 et 9h00
Open sidebar
Gauthier Quesnel
irritator
Commits
f9480ad0
Commit
f9480ad0
authored
Apr 24, 2020
by
Gauthier Quesnel
Browse files
gui: enable file, plot or both model observations
parent
f29559f9
Pipeline
#11572
passed with stage
in 45 seconds
Changes
3
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
app/gui/node-editor.cpp
View file @
f9480ad0
...
...
@@ -30,18 +30,28 @@ enum class simulation_status
struct
observation_output
{
enum
class
type
{
none
,
plot
,
file
,
both
};
observation_output
()
=
default
;
observation_output
(
const
char
*
name_
)
:
name
(
name_
)
{}
std
::
ofstream
ofs
;
const
char
*
name
=
nullptr
;
array
<
float
>
data
;
double
tl
=
0.0
;
float
min
=
-
1.
f
;
float
max
=
+
1.
f
;
int
id
=
0
;
type
observation_type
=
type
::
none
;
};
static
void
...
...
@@ -52,11 +62,26 @@ observation_output_initialize(const irt::observer& obs,
return
;
auto
*
output
=
reinterpret_cast
<
observation_output
*>
(
obs
.
user_data
);
std
::
fill_n
(
output
->
data
.
data
(),
output
->
data
.
size
(),
0.0
f
);
output
->
tl
=
t
;
output
->
min
=
-
1.
f
;
output
->
max
=
+
1.
f
;
output
->
id
=
0
;
if
(
output
->
observation_type
==
observation_output
::
type
::
plot
||
output
->
observation_type
==
observation_output
::
type
::
both
)
{
std
::
fill_n
(
output
->
data
.
data
(),
output
->
data
.
size
(),
0.0
f
);
output
->
tl
=
t
;
output
->
min
=
-
1.
f
;
output
->
max
=
+
1.
f
;
output
->
id
=
0
;
}
if
(
output
->
observation_type
==
observation_output
::
type
::
file
||
output
->
observation_type
==
observation_output
::
type
::
both
)
{
if
(
!
output
->
ofs
.
is_open
())
{
if
(
output
->
observation_type
==
observation_output
::
type
::
both
)
output
->
observation_type
=
observation_output
::
type
::
plot
;
else
output
->
observation_type
=
observation_output
::
type
::
none
;
}
else
output
->
ofs
<<
"t,"
<<
output
->
name
<<
'\n'
;
}
}
static
void
...
...
@@ -68,18 +93,40 @@ observation_output_observe(const irt::observer& obs,
return
;
auto
*
output
=
reinterpret_cast
<
observation_output
*>
(
obs
.
user_data
);
const
auto
value
=
static_cast
<
float
>
(
msg
.
to_real_64
(
0
));
auto
value
=
static_cast
<
float
>
(
msg
.
to_real_64
(
0
));
output
->
min
=
std
::
min
(
output
->
min
,
value
);
output
->
max
=
std
::
max
(
output
->
max
,
value
);
if
(
output
->
observation_type
==
observation_output
::
type
::
plot
||
output
->
observation_type
==
observation_output
::
type
::
both
)
{
output
->
min
=
std
::
min
(
output
->
min
,
value
);
output
->
max
=
std
::
max
(
output
->
max
,
value
);
for
(
double
to_fill
=
output
->
tl
;
to_fill
<
t
;
to_fill
+=
obs
.
time_step
)
if
(
static_cast
<
size_t
>
(
output
->
id
)
<
output
->
data
.
size
())
output
->
data
[
output
->
id
++
]
=
value
;
for
(
double
to_fill
=
output
->
tl
;
to_fill
<
t
;
to_fill
+=
obs
.
time_step
)
if
(
static_cast
<
size_t
>
(
output
->
id
)
<
output
->
data
.
size
())
output
->
data
[
output
->
id
++
]
=
value
;
}
if
(
output
->
observation_type
==
observation_output
::
type
::
file
||
output
->
observation_type
==
observation_output
::
type
::
both
)
{
output
->
ofs
<<
t
<<
','
<<
value
<<
'\n'
;
}
output
->
tl
=
t
;
}
static
void
observation_output_free
(
const
irt
::
observer
&
obs
,
const
irt
::
time
t
)
noexcept
{
if
(
!
obs
.
user_data
)
return
;
auto
*
output
=
reinterpret_cast
<
observation_output
*>
(
obs
.
user_data
);
if
(
output
->
observation_type
==
observation_output
::
type
::
file
||
output
->
observation_type
==
observation_output
::
type
::
both
)
{
output
->
ofs
.
close
();
}
}
static
void
run_simulation
(
simulation
&
sim
,
double
begin
,
...
...
@@ -128,10 +175,14 @@ struct editor
bool
stop
=
false
;
vector
<
observation_output
>
observation_outputs
;
array
<
observation_output
::
type
>
observation_types
;
std
::
filesystem
::
path
observation_directory
;
void
clear
()
{
observation_outputs
.
clear
();
observation_types
.
clear
();
observation_directory
.
clear
();
sim
.
clear
();
}
...
...
@@ -187,7 +238,8 @@ struct editor
status
initialize
(
u32
id
)
noexcept
{
if
(
is_bad
(
sim
.
init
(
1024u
,
32768u
))
||
is_bad
(
observation_outputs
.
init
(
sim
.
models
.
capacity
())))
is_bad
(
observation_outputs
.
init
(
sim
.
models
.
capacity
()))
||
is_bad
(
observation_types
.
init
(
sim
.
models
.
capacity
())))
return
status
::
gui_not_enough_memory
;
auto
sz
=
...
...
@@ -427,30 +479,48 @@ struct editor
void
show_model_dynamics
(
model
&
mdl
)
{
auto
*
obs
=
sim
.
observers
.
try_to_get
(
mdl
.
obs_id
);
bool
open
=
obs
!=
nullptr
;
ImGui
::
PushItemWidth
(
100.0
f
);
if
(
ImGui
::
Checkbox
(
"observation"
,
&
open
))
{
if
(
open
)
{
if
(
auto
*
old
=
sim
.
observers
.
try_to_get
(
mdl
.
obs_id
);
old
)
sim
.
observers
.
free
(
*
old
);
auto
&
o
=
sim
.
observers
.
alloc
(
0.01
,
mdl
.
name
.
c_str
(),
nullptr
);
mdl
.
obs_id
=
sim
.
observers
.
get_id
(
o
);
}
else
{
if
(
auto
*
old
=
sim
.
observers
.
try_to_get
(
mdl
.
obs_id
);
old
)
sim
.
observers
.
free
(
*
old
);
mdl
.
obs_id
=
static_cast
<
observer_id
>
(
0
);
{
const
char
*
items
[]
=
{
"none"
,
"plot"
,
"file"
,
"both"
};
int
current_item
=
0
;
/* Default show none */
auto
*
obs
=
sim
.
observers
.
try_to_get
(
mdl
.
obs_id
);
if
(
obs
)
current_item
=
static_cast
<
int
>
(
observation_types
[
get_index
(
mdl
.
obs_id
)]);
if
(
ImGui
::
Combo
(
"observation"
,
&
current_item
,
items
,
IM_ARRAYSIZE
(
items
)))
{
if
(
current_item
==
0
)
{
if
(
obs
)
{
observation_types
[
get_index
(
mdl
.
obs_id
)]
=
observation_output
::
type
::
none
;
sim
.
observers
.
free
(
*
obs
);
mdl
.
obs_id
=
static_cast
<
observer_id
>
(
0
);
}
}
else
{
if
(
!
obs
)
{
auto
&
o
=
sim
.
observers
.
alloc
(
0.01
,
mdl
.
name
.
c_str
(),
nullptr
);
sim
.
observe
(
mdl
,
o
);
}
observation_types
[
get_index
(
mdl
.
obs_id
)]
=
current_item
==
1
?
observation_output
::
type
::
plot
:
current_item
==
2
?
observation_output
::
type
::
file
:
observation_output
::
type
::
both
;
}
if
(
auto
*
o
=
sim
.
observers
.
try_to_get
(
mdl
.
obs_id
);
o
)
{
float
v
=
static_cast
<
float
>
(
o
->
time_step
);
if
(
ImGui
::
InputFloat
(
"freq."
,
&
v
,
0.001
f
,
0.1
f
,
"%.3f"
,
0
))
o
->
time_step
=
static_cast
<
double
>
(
v
);
}
}
}
if
(
auto
*
o
=
sim
.
observers
.
try_to_get
(
mdl
.
obs_id
);
o
)
{
float
v
=
static_cast
<
float
>
(
o
->
time_step
);
if
(
ImGui
::
InputFloat
(
"freq."
,
&
v
,
0.001
f
,
0.1
f
,
"%.3f"
,
0
))
o
->
time_step
=
static_cast
<
double
>
(
v
);
}
ImGui
::
PopItemWidth
();
switch
(
mdl
.
type
)
{
...
...
@@ -860,7 +930,8 @@ struct editor
ImGui
::
OpenPopup
(
"Context menu"
);
if
(
ImGui
::
BeginPopup
(
"Context menu"
))
{
// ImVec2 click_pos = ImGui::GetMousePosOnOpeningCurrentPopup();
// ImVec2 click_pos =
// ImGui::GetMousePosOnOpeningCurrentPopup();
if
(
ImGui
::
MenuItem
(
"none"
))
{
if
(
sim
.
none_models
.
can_alloc
(
1u
)
&&
sim
.
models
.
can_alloc
(
1u
))
{
...
...
@@ -1086,10 +1157,11 @@ struct editor
/*
if (ImGui::IsKeyReleased(SDL_SCANCODE_A) &&
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)) {
const int node_id = ++editor.current_id;
imnodes::SetNodeScreenSpacePos(node_id, ImGui::GetMousePos());
editor.nodes.push_back(Node{ node_id, 0.f });
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows))
{ const int node_id = ++editor.current_id;
imnodes::SetNodeScreenSpacePos(node_id,
ImGui::GetMousePos()); editor.nodes.push_back(Node{ node_id, 0.f
});
}
*/
...
...
@@ -1178,17 +1250,41 @@ show_simulation_box(bool* show_simulation)
ed
->
observation_outputs
.
clear
();
observer
*
obs
=
nullptr
;
while
(
ed
->
sim
.
observers
.
next
(
obs
))
{
ed
->
observation_outputs
.
emplace_back
(
obs
->
name
.
c_str
());
auto
*
output
=
ed
->
observation_outputs
.
emplace_back
(
obs
->
name
.
c_str
());
const
auto
type
=
ed
->
observation_types
[
get_index
(
ed
->
sim
.
observers
.
get_id
(
*
obs
))];
const
auto
diff
=
ed
->
simulation_end
-
ed
->
simulation_begin
;
const
auto
freq
=
diff
/
obs
->
time_step
;
const
size_t
lenght
=
static_cast
<
size_t
>
(
freq
);
const
auto
length
=
static_cast
<
size_t
>
(
freq
);
output
->
observation_type
=
type
;
if
(
type
==
observation_output
::
type
::
plot
||
type
==
observation_output
::
type
::
both
)
{
output
->
data
.
init
(
length
);
}
if
(
!
obs
->
name
.
empty
())
{
const
std
::
filesystem
::
path
obs_file_path
=
ed
->
observation_directory
/
obs
->
name
.
c_str
();
if
(
type
==
observation_output
::
type
::
file
||
type
==
observation_output
::
type
::
both
)
{
if
(
output
->
ofs
.
open
(
obs_file_path
);
!
output
->
ofs
.
is_open
())
log_w
.
log
(
4
,
"Fail to open observation file: %s in %s
\n
"
,
obs
->
name
.
c_str
(),
ed
->
observation_directory
.
u8string
().
c_str
());
}
}
ed
->
observation_outputs
.
back
().
data
.
init
(
lenght
);
obs
->
initialize
=
&
observation_output_initialize
;
obs
->
observe
=
&
observation_output_observe
;
obs
->
user_data
=
static_cast
<
void
*>
(
&
ed
->
observation_outputs
.
back
()
);
obs
->
free
=
&
observation_output_free
;
obs
->
user_data
=
static_cast
<
void
*>
(
output
);
}
ed
->
st
=
simulation_status
::
running
;
...
...
@@ -1218,15 +1314,22 @@ show_simulation_box(bool* show_simulation)
const
double
fraction
=
elapsed
/
duration
;
ImGui
::
ProgressBar
(
static_cast
<
float
>
(
fraction
));
for
(
const
auto
&
obs
:
ed
->
observation_outputs
)
ImGui
::
PlotLines
(
obs
.
name
,
obs
.
data
.
data
(),
static_cast
<
int
>
(
obs
.
data
.
size
()),
0
,
nullptr
,
obs
.
min
,
obs
.
max
,
ImVec2
(
0.
f
,
50.
f
));
for
(
const
auto
&
obs
:
ed
->
observation_outputs
)
{
if
(
obs
.
observation_type
==
observation_output
::
type
::
plot
||
obs
.
observation_type
==
observation_output
::
type
::
both
)
ImGui
::
PlotLines
(
obs
.
name
,
obs
.
data
.
data
(),
static_cast
<
int
>
(
obs
.
data
.
size
()),
0
,
nullptr
,
obs
.
min
,
obs
.
max
,
ImVec2
(
0.
f
,
50.
f
));
if
(
obs
.
observation_type
==
observation_output
::
type
::
file
||
obs
.
observation_type
==
observation_output
::
type
::
both
)
ImGui
::
Text
(
"%s: output file"
,
obs
.
name
);
}
}
}
...
...
lib/include/irritator/core.hpp
View file @
f9480ad0
...
...
@@ -2875,15 +2875,34 @@ struct observer
{
observer
()
noexcept
=
default
;
observer
(
const
time
time_step_
,
const
char
*
name_
,
void
*
user_data_
)
observer
(
const
time
time_step_
,
const
char
*
name_
,
void
*
user_data_
)
noexcept
:
time_step
(
std
::
clamp
(
time_step_
,
0.0
,
time_domain
<
time
>::
infinity
))
,
name
(
name_
)
,
user_data
(
user_data_
)
{}
observer
(
const
time
time_step_
,
const
char
*
name_
,
void
*
user_data_
,
void
(
*
initialize_
)(
const
observer
&
obs
,
const
time
t
)
noexcept
,
void
(
*
observe_
)(
const
observer
&
obs
,
const
time
t
,
const
message
&
msg
)
noexcept
,
void
(
*
free_
)(
const
observer
&
obs
,
const
time
t
)
noexcept
)
:
time_step
(
std
::
clamp
(
time_step_
,
0.0
,
time_domain
<
time
>::
infinity
))
,
name
(
name_
)
,
user_data
(
user_data_
)
,
initialize
(
initialize_
)
,
observe
(
observe_
)
,
free
(
free_
)
{}
double
tl
=
0.0
;
double
time_step
=
0.0
;
small_string
<
8
>
name
;
model_id
model
=
static_cast
<
model_id
>
(
0
);
void
*
user_data
=
nullptr
;
...
...
@@ -4713,6 +4732,12 @@ public:
return
status
::
success
;
}
void
observe
(
model
&
mdl
,
observer
&
obs
)
noexcept
{
mdl
.
obs_id
=
observers
.
get_id
(
obs
);
obs
.
model
=
models
.
get_id
(
mdl
);
}
status
deallocate
(
model_id
id
)
{
auto
*
mdl
=
models
.
try_to_get
(
id
);
...
...
lib/test/public-api.cpp
View file @
f9480ad0
...
...
@@ -1017,18 +1017,25 @@ main()
file_output
fo_a
(
"lotka-volterra_a.csv"
);
file_output
fo_b
(
"lotka-volterra_b.csv"
);
auto
&
obs_a
=
sim
.
observers
.
alloc
(
0.01
,
"A"
,
static_cast
<
void
*>
(
&
fo_a
));
auto
&
obs_b
=
sim
.
observers
.
alloc
(
0.01
,
"B"
,
static_cast
<
void
*>
(
&
fo_b
));
obs_a
.
initialize
=
&
file_output_initialize
;
obs_a
.
observe
=
&
file_output_observe
;
obs_b
.
initialize
=
&
file_output_initialize
;
obs_b
.
observe
=
&
file_output_observe
;
sim
.
models
.
get
(
integrator_a
.
id
).
obs_id
=
sim
.
observers
.
get_id
(
obs_a
);
sim
.
models
.
get
(
integrator_b
.
id
).
obs_id
=
sim
.
observers
.
get_id
(
obs_b
);
expect
(
fo_a
.
os
!=
nullptr
);
expect
(
fo_b
.
os
!=
nullptr
);
auto
&
obs_a
=
sim
.
observers
.
alloc
(
0.01
,
"A"
,
static_cast
<
void
*>
(
&
fo_a
),
file_output_initialize
,
&
file_output_observe
,
nullptr
);
auto
&
obs_b
=
sim
.
observers
.
alloc
(
0.01
,
"B"
,
static_cast
<
void
*>
(
&
fo_b
),
file_output_initialize
,
&
file_output_observe
,
nullptr
);
sim
.
observe
(
sim
.
models
.
get
(
integrator_a
.
id
),
obs_a
);
sim
.
observe
(
sim
.
models
.
get
(
integrator_b
.
id
),
obs_b
);
irt
::
time
t
=
0.0
;
expect
(
sim
.
initialize
(
t
)
==
irt
::
status
::
success
);
...
...
@@ -1196,18 +1203,26 @@ main()
dw
(
sim
);
file_output
fo_a
(
"izhikevitch_a.csv"
);
file_output
fo_b
(
"izhikevitch_b.csv"
);
auto
&
obs_a
=
sim
.
observers
.
alloc
(
0.01
,
"A"
,
static_cast
<
void
*>
(
&
fo_a
));
auto
&
obs_b
=
sim
.
observers
.
alloc
(
0.01
,
"B"
,
static_cast
<
void
*>
(
&
fo_b
));
obs_a
.
initialize
=
&
file_output_initialize
;
obs_a
.
observe
=
&
file_output_observe
;
obs_b
.
initialize
=
&
file_output_initialize
;
obs_b
.
observe
=
&
file_output_observe
;
sim
.
models
.
get
(
integrator_a
.
id
).
obs_id
=
sim
.
observers
.
get_id
(
obs_a
);
sim
.
models
.
get
(
integrator_b
.
id
).
obs_id
=
sim
.
observers
.
get_id
(
obs_b
);
expect
(
fo_a
.
os
!=
nullptr
);
auto
&
obs_a
=
sim
.
observers
.
alloc
(
0.01
,
"A"
,
static_cast
<
void
*>
(
&
fo_a
),
&
file_output_initialize
,
&
file_output_observe
,
nullptr
);
file_output
fo_b
(
"izhikevitch_b.csv"
);
expect
(
fo_b
.
os
!=
nullptr
);
auto
&
obs_b
=
sim
.
observers
.
alloc
(
0.01
,
"B"
,
static_cast
<
void
*>
(
&
fo_b
),
&
file_output_initialize
,
&
file_output_observe
,
nullptr
);
sim
.
observe
(
sim
.
models
.
get
(
integrator_a
.
id
),
obs_a
);
sim
.
observe
(
sim
.
models
.
get
(
integrator_b
.
id
),
obs_b
);
irt
::
time
t
=
0.0
;
...
...
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