Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Gauthier Quesnel
irritator
Commits
7090552a
Commit
7090552a
authored
May 11, 2020
by
Gauthier Quesnel
Browse files
core: reorder model components
parent
3a9b0bae
Changes
1
Hide whitespace changes
Inline
Side-by-side
lib/include/irritator/core.hpp
View file @
7090552a
...
...
@@ -3019,1143 +3019,1143 @@ using has_init_port_t = decltype(&T::init);
struct
simulation
;
template
<
size_t
PortNumber
>
struct
adder
struct
none
{
static_assert
(
PortNumber
>
1
,
"adder model need at least two input port"
);
model_id
id
;
time
sigma
=
time_domain
<
time
>::
infinity
;
};
struct
integrator
{
model_id
id
;
input_port_id
x
[
PortNumber
];
input_port_id
x
[
3
];
output_port_id
y
[
1
];
time
sigma
;
double
default_values
[
PortNumber
];
double
default_input_coeffs
[
PortNumber
];
double
values
[
PortNumber
];
double
input_coeffs
[
PortNumber
];
time
sigma
=
time_domain
<
time
>::
zero
;
adder
()
noexcept
enum
port_name
{
std
::
fill_n
(
std
::
begin
(
default_values
),
PortNumber
,
1.0
/
static_cast
<
double
>
(
PortNumber
));
std
::
fill_n
(
std
::
begin
(
default_input_coeffs
),
PortNumber
,
0.0
);
}
port_quanta
,
port_x_dot
,
port_reset
};
status
initialize
(
data_array
<
message
,
message_id
>&
/*init*/
)
noexcept
enum
class
state
{
std
::
copy_n
(
std
::
begin
(
default_values
),
PortNumber
,
std
::
begin
(
values
));
init
,
wait_for_quanta
,
wait_for_x_dot
,
wait_for_both
,
running
};
std
::
copy_n
(
std
::
begin
(
default_input_coeffs
),
PortNumber
,
std
::
begin
(
input_coeffs
))
;
double
default_current_value
=
0.0
;
double
default_reset_value
=
0.0
;
flat_double_list
<
record
>
archive
;
sigma
=
time_domain
<
time
>::
infinity
;
double
current_value
=
0.0
;
double
reset_value
=
0.0
;
double
up_threshold
=
0.0
;
double
down_threshold
=
0.0
;
double
last_output_value
=
0.0
;
double
expected_value
=
0.0
;
bool
reset
=
false
;
state
st
=
state
::
init
;
return
status
::
success
;
}
integrator
()
=
default
;
status
lambda
(
data_array
<
output_port
,
output_port_id
>&
output_ports
)
noexcept
{
double
to_send
=
0.0
;
integrator
(
const
integrator
&
other
)
noexcept
:
default_current_value
(
other
.
default_current_value
)
,
default_reset_value
(
other
.
default_reset_value
)
,
archive
(
other
.
archive
.
get_allocator
())
,
current_value
(
other
.
current_value
)
,
reset_value
(
other
.
reset_value
)
,
up_threshold
(
other
.
up_threshold
)
,
down_threshold
(
other
.
down_threshold
)
,
last_output_value
(
other
.
last_output_value
)
,
expected_value
(
other
.
expected_value
)
,
reset
(
other
.
reset
)
,
st
(
other
.
st
)
{}
if
(
auto
*
port
=
output_ports
.
try_to_get
(
y
[
0
]);
port
)
{
for
(
size_t
i
=
0
;
i
!=
PortNumber
;
++
i
)
to_send
+=
input_coeffs
[
i
]
*
values
[
i
];
status
initialize
(
data_array
<
message
,
message_id
>&
/*init*/
)
noexcept
{
current_value
=
default_current_value
;
reset_value
=
default_reset_value
;
up_threshold
=
0.0
;
down_threshold
=
0.0
;
last_output_value
=
0.0
;
expected_value
=
0.0
;
reset
=
false
;
archive
.
clear
();
st
=
state
::
init
;
port
->
messages
.
emplace_front
(
to_send
);
}
sigma
=
time_domain
<
time
>::
zero
;
return
status
::
success
;
}
status
transition
(
data_array
<
input_port
,
input_port_id
>&
input_ports
,
time
/*t*/
,
time
/*e*/
,
time
/*r*/
)
noexcept
status
external
(
input_port
&
port_quanta
,
input_port
&
port_x_dot
,
input_port
&
port_reset
,
time
t
)
noexcept
{
bool
have_message
=
false
;
for
(
const
auto
&
msg
:
port_quanta
.
messages
)
{
irt_return_if_fail
(
msg
.
type
==
value_type
::
real_64
&&
msg
.
size
()
==
2
,
status
::
model_integrator_bad_external_message
);
for
(
size_t
i
=
0
;
i
!=
PortNumber
;
++
i
)
{
if
(
auto
*
port
=
input_ports
.
try_to_get
(
x
[
i
]);
port
)
{
for
(
const
auto
&
msg
:
port
->
messages
)
{
irt_return_if_fail
(
msg
.
type
==
value_type
::
real_64
,
status
::
model_adder_bad_external_message
);
irt_return_if_fail
(
msg
.
size
()
==
1
,
status
::
model_adder_bad_external_message
);
up_threshold
=
msg
.
to_real_64
(
0
);
down_threshold
=
msg
.
to_real_64
(
1
);
values
[
i
]
=
msg
.
to_real_64
(
0
);
if
(
st
==
state
::
wait_for_quanta
)
st
=
state
::
running
;
have_message
=
true
;
}
}
if
(
st
==
state
::
wait_for_both
)
st
=
state
::
wait_for_x_dot
;
}
sigma
=
have_message
?
time_domain
<
time
>::
zero
:
time_domain
<
time
>::
infinity
;
return
status
::
success
;
}
for
(
const
auto
&
msg
:
port_x_dot
.
messages
)
{
irt_return_if_fail
(
msg
.
type
==
value_type
::
real_64
&&
msg
.
size
()
==
1
,
status
::
model_integrator_bad_external_message
);
message
observation
(
time
/*t*/
)
const
noexcept
{
double
ret
=
0.0
;
archive
.
emplace_back
(
msg
.
to_real_64
(
0
),
t
);
for
(
size_t
i
=
0
;
i
!=
PortNumber
;
++
i
)
re
t
+
=
input_coeffs
[
i
]
*
values
[
i
]
;
if
(
st
==
state
::
wait_for_x_dot
)
s
t
=
state
::
running
;
return
message
(
ret
);
}
}
;
if
(
st
==
state
::
wait_for_both
)
st
=
state
::
wait_for_quanta
;
}
template
<
size_t
PortNumber
>
struct
mult
{
static_assert
(
PortNumber
>
1
,
"mult model need at least two input port"
);
for
(
const
auto
&
msg
:
port_reset
.
messages
)
{
irt_return_if_fail
(
msg
.
type
==
value_type
::
real_64
&&
msg
.
size
()
==
1
,
status
::
model_integrator_bad_external_message
);
model_id
id
;
input_port_id
x
[
PortNumber
];
output_port_id
y
[
1
];
time
sigma
;
reset_value
=
msg
.
to_real_64
(
0
);
reset
=
true
;
}
double
default_values
[
PortNumber
];
double
default_input_coeffs
[
PortNumber
];
if
(
st
==
state
::
running
)
{
current_value
=
compute_current_value
(
t
);
expected_value
=
compute_expected_value
();
}
double
values
[
PortNumber
]
;
double
input_coeffs
[
PortNumber
];
return
status
::
success
;
}
mult
(
)
noexcept
status
internal
(
time
t
)
noexcept
{
std
::
fill_n
(
std
::
begin
(
default_values
),
PortNumber
,
1.0
);
std
::
fill_n
(
std
::
begin
(
default_input_coeffs
),
PortNumber
,
0.0
);
switch
(
st
)
{
case
state
::
running
:
{
last_output_value
=
expected_value
;
const
double
last_derivative_value
=
archive
.
back
().
x_dot
;
archive
.
clear
();
archive
.
emplace_back
(
last_derivative_value
,
t
);
current_value
=
expected_value
;
st
=
state
::
wait_for_quanta
;
return
status
::
success
;
}
case
state
::
init
:
st
=
state
::
wait_for_both
;
last_output_value
=
current_value
;
return
status
::
success
;
default:
return
status
::
model_integrator_internal_error
;
}
}
status
initialize
(
data_array
<
message
,
message_id
>&
/*init*/
)
noexcept
status
transition
(
data_array
<
input_port
,
input_port_id
>&
input_ports
,
time
t
,
time
/*e*/
,
time
r
)
noexcept
{
std
::
copy_n
(
std
::
begin
(
default_values
),
PortNumber
,
std
::
begin
(
values
));
auto
*
port_1
=
input_ports
.
try_to_get
(
x
[
port_quanta
]);
auto
*
port_2
=
input_ports
.
try_to_get
(
x
[
port_x_dot
]);
auto
*
port_3
=
input_ports
.
try_to_get
(
x
[
port_reset
]);
std
::
copy_n
(
std
::
begin
(
default_input_coeffs
),
PortNumber
,
std
::
begin
(
input_coeffs
));
if
(
port_1
->
messages
.
empty
()
&&
port_2
->
messages
.
empty
()
&&
port_3
->
messages
.
empty
())
{
irt_return_if_bad
(
internal
(
t
));
}
else
{
if
(
time_domain
<
time
>::
is_zero
(
r
))
irt_return_if_bad
(
internal
(
t
));
sigma
=
time_domain
<
time
>::
infinity
;
irt_return_if_bad
(
external
(
*
port_1
,
*
port_2
,
*
port_3
,
t
));
}
return
s
ta
tus
::
success
;
return
ta
()
;
}
status
lambda
(
data_array
<
output_port
,
output_port_id
>&
output_ports
)
noexcept
{
double
to_send
=
1.0
;
if
(
auto
*
port
=
output_ports
.
try_to_get
(
y
[
0
]);
port
)
{
for
(
size_t
i
=
0
;
i
!=
PortNumber
;
++
i
)
to_send
*=
std
::
pow
(
values
[
i
],
input_coeffs
[
i
]);
port
->
messages
.
emplace_front
(
to_send
);
switch
(
st
)
{
case
state
::
running
:
port
->
messages
.
emplace_front
(
expected_value
);
return
status
::
success
;
case
state
::
init
:
port
->
messages
.
emplace_front
(
current_value
);
return
status
::
success
;
default:
return
status
::
model_integrator_output_error
;
}
}
return
status
::
success
;
}
status
transition
(
data_array
<
input_port
,
input_port_id
>&
input_ports
,
time
/*t*/
,
time
/*e*/
,
time
/*r*/
)
noexcept
message
observation
(
time
/*t*/
)
const
noexcept
{
bool
have_message
=
false
;
for
(
size_t
i
=
0
;
i
!=
PortNumber
;
++
i
)
{
if
(
auto
*
port
=
input_ports
.
try_to_get
(
x
[
i
]);
port
)
{
for
(
const
auto
&
msg
:
port
->
messages
)
{
irt_return_if_fail
(
msg
.
type
==
value_type
::
real_64
,
status
::
model_mult_bad_external_message
);
irt_return_if_fail
(
msg
.
size
()
==
1
,
status
::
model_mult_bad_external_message
);
values
[
i
]
=
msg
.
to_real_64
(
0
);
have_message
=
true
;
}
}
}
return
message
(
last_output_value
);
}
sigma
=
have_message
?
time_domain
<
time
>::
zero
:
time_domain
<
time
>::
infinity
;
return
status
::
success
;
}
message
observation
(
time
/*t*/
)
const
noexcept
{
double
ret
=
1.0
;
for
(
size_t
i
=
0
;
i
!=
PortNumber
;
++
i
)
ret
*=
std
::
pow
(
values
[
i
],
input_coeffs
[
i
]);
return
message
(
ret
);
}
};
template
<
size_t
PortNumber
>
struct
accumulator
{
model_id
id
;
input_port_id
x
[
2
*
PortNumber
];
time
sigma
;
double
number
;
double
numbers
[
PortNumber
];
status
initialize
(
data_array
<
message
,
message_id
>&
/*init_messages*/
)
noexcept
status
ta
()
noexcept
{
number
=
0.0
;
std
::
fill_n
(
numbers
,
PortNumber
,
0.0
);
if
(
st
==
state
::
running
)
{
irt_return_if_fail
(
!
archive
.
empty
(),
status
::
model_integrator_running_without_x_dot
);
sigma
=
time_domain
<
time
>::
infinity
;
const
auto
current_derivative
=
archive
.
back
().
x_dot
;
return
status
::
success
;
}
if
(
current_derivative
==
time_domain
<
time
>::
zero
)
{
sigma
=
time_domain
<
time
>::
infinity
;
return
status
::
success
;
}
status
transition
(
data_array
<
input_port
,
input_port_id
>&
input_ports
,
time
/*t*/
,
time
/*e*/
,
time
/*r*/
)
noexcept
{
if
(
current_derivative
>
0
)
{
irt_return_if_fail
((
up_threshold
-
current_value
)
>=
0
,
status
::
model_integrator_ta_with_bad_x_dot
);
for
(
size_t
i
=
0
;
i
!=
PortNumber
;
++
i
)
{
if
(
auto
*
port
=
input_ports
.
try_to_get
(
x
[
i
+
PortNumber
]);
port
)
{
for
(
const
auto
&
msg
:
port
->
messages
)
{
irt_return_if_fail
(
msg
.
type
==
value_type
::
real_64
,
status
::
model_accumulator_bad_external_message
);
irt_return_if_fail
(
msg
.
size
()
==
1
,
status
::
model_accumulator_bad_external_message
);
numbers
[
i
]
=
msg
.
to_real_64
(
0
);
}
sigma
=
(
up_threshold
-
current_value
)
/
current_derivative
;
return
status
::
success
;
}
}
for
(
size_t
i
=
0
;
i
!=
PortNumber
;
++
i
)
{
if
(
auto
*
port
=
input_ports
.
try_to_get
(
x
[
i
]);
port
)
{
for
(
const
auto
&
msg
:
port
->
messages
)
{
irt_return_if_fail
(
msg
.
type
==
value_type
::
real_64
,
status
::
model_accumulator_bad_external_message
);
irt_return_if_fail
(
msg
.
size
()
==
1
,
status
::
model_accumulator_bad_external_message
);
irt_return_if_fail
((
down_threshold
-
current_value
)
<=
0
,
status
::
model_integrator_ta_with_bad_x_dot
);
if
(
msg
.
to_real_64
(
0
)
!=
0.0
)
{
number
+=
numbers
[
i
];
}
}
}
sigma
=
(
down_threshold
-
current_value
)
/
current_derivative
;
return
status
::
success
;
}
sigma
=
time_domain
<
time
>::
infinity
;
return
status
::
success
;
}
};
using
adder_2
=
adder
<
2
>
;
using
adder_3
=
adder
<
3
>
;
using
adder_4
=
adder
<
4
>
;
double
compute_current_value
(
time
t
)
const
noexcept
{
if
(
archive
.
empty
())
return
reset
?
reset_value
:
last_output_value
;
using
mult_2
=
mult
<
2
>
;
using
mult_3
=
mult
<
3
>
;
using
mult_4
=
mult
<
4
>
;
auto
val
=
reset
?
reset_value
:
last_output_value
;
auto
end
=
archive
.
end
();
auto
it
=
archive
.
begin
();
auto
next
=
archive
.
begin
();
using
accumulator_2
=
accumulator
<
2
>
;
if
(
next
!=
end
)
++
next
;
struct
counter
{
model_id
id
;
input_port_id
x
[
1
];
time
sigma
;
i64
number
;
for
(;
next
!=
end
;
it
=
next
++
)
val
+=
(
next
->
date
-
it
->
date
)
*
it
->
x_dot
;
status
initialize
(
data_array
<
message
,
message_id
>&
/*init_messages*/
)
noexcept
{
number
=
{
0
};
sigma
=
time_domain
<
time
>::
infinity
;
val
+=
(
t
-
archive
.
back
().
date
)
*
archive
.
back
().
x_dot
;
return
status
::
success
;
return
up_threshold
<
val
?
reset_value
:
val
;
}
status
transition
(
data_array
<
input_port
,
input_port_id
>&
input_ports
,
time
/*t*/
,
time
/*e*/
,
time
/*r*/
)
noexcept
double
compute_expected_value
()
const
noexcept
{
std
::
ptrdiff_t
diff
{
0
};
if
(
auto
*
port
=
input_ports
.
try_to_get
(
x
[
0
]);
port
)
diff
+=
std
::
distance
(
std
::
begin
(
port
->
messages
),
std
::
end
(
port
->
messages
));
const
auto
current_derivative
=
archive
.
back
().
x_dot
;
number
+=
static_cast
<
i64
>
(
diff
);
if
(
current_derivative
==
0
)
return
current_value
;
return
status
::
success
;
}
if
(
current_derivative
>
0
)
return
up_threshold
;
message
observation
(
time
/*t*/
)
const
noexcept
{
return
message
(
number
);
return
down_threshold
;
}
};
struct
generato
r
struct
quantifie
r
{
model_id
id
;
input_port_id
x
[
1
];
output_port_id
y
[
1
];
time
sigma
;
double
default_value
=
0.0
;
double
default_period
=
1.0
;
double
default_offset
=
1.0
;
double
value
=
0.0
;
double
period
=
1.0
;
double
offset
=
1.0
;
time
sigma
=
time_domain
<
time
>::
infinity
;
status
initialize
(
data_array
<
message
,
message_id
>&
/*init_messages*/
)
noexcept
enum
class
state
{
value
=
default_value
;
period
=
default_period
;
offset
=
default_offset
;
sigma
=
offset
;
init
,
idle
,
response
};
return
status
::
success
;
}
status
transition
(
data_array
<
input_port
,
input_port_id
>&
/*input_ports*/
,
time
/*t*/
,
time
/*e*/
,
time
/*r*/
)
noexcept
enum
class
adapt_state
{
sigma
=
period
;
return
status
::
success
;
}
impossible
,
possible
,
done
};
status
lambda
(
data_array
<
output_port
,
output_port_id
>&
output_ports
)
noexcept
enum
class
direction
{
output_ports
.
get
(
y
[
0
]).
messages
.
emplace_front
(
value
);
return
status
::
success
;
}
up
,
down
};
message
observation
(
time
/*t*/
)
const
noexcept
{
return
message
(
value
)
;
}
}
;
double
default_step_size
=
0.001
;
int
default_past_length
=
3
;
adapt_state
default_adapt_state
=
adapt_state
::
possible
;
bool
default_zero_init_offset
=
false
;
flat_double_list
<
record
>
archive
;
struct
constant
{
model_id
id
;
output_port_id
y
[
1
];
time
sigma
;
double
m_upthreshold
=
0.0
;
double
m_downthreshold
=
0.0
;
double
m_offset
=
0.0
;
double
m_step_size
=
0.0
;
int
m_step_number
=
0
;
int
m_past_length
=
0
;
bool
m_zero_init_offset
=
false
;
state
m_state
=
state
::
init
;
adapt_state
m_adapt_state
=
adapt_state
::
possible
;
double
default_value
=
0.0
;
quantifier
()
noexcept
=
default
;
double
value
=
0.0
;
quantifier
(
const
quantifier
&
other
)
noexcept
:
default_step_size
(
other
.
default_step_size
)
,
default_past_length
(
other
.
default_past_length
)
,
default_adapt_state
(
other
.
default_adapt_state
)
,
default_zero_init_offset
(
other
.
default_zero_init_offset
)
,
archive
(
other
.
archive
.
get_allocator
())
,
m_upthreshold
(
other
.
m_upthreshold
)
,
m_downthreshold
(
other
.
m_downthreshold
)
,
m_offset
(
other
.
m_offset
)
,
m_step_size
(
other
.
m_step_size
)
,
m_step_number
(
other
.
m_step_number
)
,
m_past_length
(
other
.
m_past_length
)
,
m_zero_init_offset
(
other
.
m_zero_init_offset
)
,
m_state
(
other
.
m_state
)
,
m_adapt_state
(
other
.
m_adapt_state
)
{}
status
initialize
(
data_array
<
message
,
message_id
>&
/*init*/
)
noexcept
{
sigma
=
time_domain
<
time
>::
zero
;
m_step_size
=
default_step_size
;
m_past_length
=
default_past_length
;
m_zero_init_offset
=
default_zero_init_offset
;
m_adapt_state
=
default_adapt_state
;
m_upthreshold
=
0.0
;
m_downthreshold
=
0.0
;
m_offset
=
0.0
;
m_step_number
=
0
;
archive
.
clear
();