Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Kirill Terekhov
INMOST
Commits
831bfd7c
Commit
831bfd7c
authored
Aug 05, 2014
by
Alexander Danilov
Browse files
Merge branch 'master' of inmost-github
parents
f3e4e583
5452e1ea
Changes
45
Hide whitespace changes
Inline
Side-by-side
CMakeLists.txt
View file @
831bfd7c
...
...
@@ -31,7 +31,7 @@ set(HEADER inmost.h
container.hpp
io.hpp
solver_ilu2.hpp
#
solver_ddpqiluc2.hpp
solver_ddpqiluc2.hpp
solver_bcgsl.hpp
solver_prototypes.hpp
)
...
...
@@ -56,7 +56,7 @@ option(USE_PARTITIONER_PARMETIS "Use ParMetis partitioner" OFF)
option
(
USE_PARTITIONER_ZOLTAN
"Use Zoltan partitioner"
OFF
)
option
(
USE_SOLVER_PETSC
"Use PETSc solver"
OFF
)
option
(
USE_AUTODIFF_OPENCL
"Use OpenCL for automatic differentiation (under work)"
OFF
)
option
(
USE_AUTODIFF_ASMJIT
"Use AsmJit for automatic differentiation"
O
N
)
option
(
USE_AUTODIFF_ASMJIT
"Use AsmJit for automatic differentiation"
O
FF
)
option
(
USE_AUTODIFF_EXPRESSION_TEMPLATES
"Use c++ expression templates for automatic differentiation"
OFF
)
set
(
CMAKE_MODULE_PATH
${
CMAKE_MODULE_PATH
}
"
${
CMAKE_SOURCE_DIR
}
/cmake_find/"
)
...
...
autodiff.cpp
View file @
831bfd7c
...
...
@@ -13,14 +13,216 @@
namespace
INMOST
{
#if defined(NEW_VERSION)
//! returns offset from the end of precomputed z
void
Automatizator
::
DerivativeFill
(
expr
&
var
,
INMOST_DATA_ENUM_TYPE
element
,
INMOST_DATA_ENUM_TYPE
parent
,
Solver
::
Row
&
entries
,
INMOST_DATA_REAL_TYPE
multval
,
void
*
user_data
)
{
INMOST_DATA_ENUM_TYPE
voffset
=
var
.
values_offset
(
element
),
doffset
=
var
.
derivatives_offset
(
element
);
INMOST_DATA_ENUM_TYPE
k
=
var
.
data
.
size
()
-
1
;
Storage
*
e
=
var
.
current_stencil
[
element
].
first
;
INMOST_DATA_REAL_TYPE
lval
,
rval
,
ret
;
var
.
values
[
doffset
+
k
]
=
multval
;
expr
::
expr_data
*
arr
=
&
var
.
data
[
0
],
*
it
;
//for (expr::data_type::reverse_iterator it = var.data.rbegin(); it != var.data.rend(); ++it)
do
{
it
=
arr
+
k
;
switch
(
it
->
op
)
{
case
AD_EXT
:
assert
(
parent
!=
ENUMUNDEF
);
it
->
left
.
e
->
values
[
it
->
left
.
e
->
derivatives_offset
(
parent
)
+
it
->
right
.
i
]
+=
var
.
values
[
doffset
+
k
];
break
;
case
AD_COND
:
{
expr
&
next
=
var
.
values
[
voffset
+
it
->
left
.
i
]
>
0.0
?
*
it
->
right
.
q
->
left
.
e
:
*
it
->
right
.
q
->
right
.
e
;
DerivativeFill
(
next
,
0
,
element
,
entries
,
var
.
values
[
doffset
+
k
],
user_data
);
}
break
;
case
AD_PLUS
:
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
var
.
values
[
doffset
+
k
];
var
.
values
[
doffset
+
it
->
right
.
i
]
+=
var
.
values
[
doffset
+
k
];
break
;
case
AD_MINUS
:
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
var
.
values
[
doffset
+
k
];
var
.
values
[
doffset
+
it
->
right
.
i
]
-=
var
.
values
[
doffset
+
k
];
break
;
case
AD_MULT
:
rval
=
var
.
values
[
voffset
+
it
->
right
.
i
];
lval
=
var
.
values
[
voffset
+
it
->
left
.
i
];
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
var
.
values
[
doffset
+
k
]
*
rval
;
var
.
values
[
doffset
+
it
->
right
.
i
]
+=
var
.
values
[
doffset
+
k
]
*
lval
;
break
;
case
AD_DIV
:
rval
=
var
.
values
[
voffset
+
it
->
right
.
i
];
lval
=
var
.
values
[
voffset
+
it
->
left
.
i
];
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
var
.
values
[
doffset
+
k
]
/
rval
;
var
.
values
[
doffset
+
it
->
right
.
i
]
-=
var
.
values
[
doffset
+
k
]
*
lval
/
(
rval
*
rval
);
break
;
case
AD_POW
:
ret
=
var
.
values
[
voffset
+
k
];
rval
=
var
.
values
[
voffset
+
it
->
right
.
i
];
lval
=
var
.
values
[
voffset
+
it
->
left
.
i
];
var
.
values
[
doffset
+
it
->
right
.
i
]
+=
var
.
values
[
doffset
+
k
]
*
::
log
(
lval
);
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
var
.
values
[
doffset
+
k
]
*
ret
*
rval
/
lval
;
break
;
case
AD_SQRT
:
ret
=
var
.
values
[
voffset
+
k
];
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
0.5
*
var
.
values
[
doffset
+
k
]
/
ret
;
break
;
case
AD_ABS
:
lval
=
var
.
values
[
voffset
+
it
->
left
.
i
];
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
var
.
values
[
doffset
+
k
]
*
(
lval
>
0.0
?
1.0
:
-
1.0
);
break
;
case
AD_EXP
:
ret
=
var
.
values
[
voffset
+
k
];
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
var
.
values
[
doffset
+
k
]
*
ret
;
break
;
case
AD_LOG
:
lval
=
var
.
values
[
voffset
+
it
->
left
.
i
];
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
var
.
values
[
doffset
+
k
]
/
lval
;
break
;
case
AD_SIN
:
lval
=
var
.
values
[
voffset
+
it
->
left
.
i
];
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
var
.
values
[
doffset
+
k
]
*
::
cos
(
lval
);
break
;
case
AD_COS
:
lval
=
var
.
values
[
voffset
+
it
->
left
.
i
];
var
.
values
[
doffset
+
it
->
left
.
i
]
-=
var
.
values
[
doffset
+
k
]
*
::
sin
(
lval
);
break
;
case
AD_COND_MARK
:
break
;
case
AD_COND_TYPE
:
break
;
case
AD_CONST
:
break
;
case
AD_MES
:
break
;
case
AD_VAL
:
{
expr
&
next
=
*
it
->
right
.
e
;
next
.
current_stencil
.
resize
(
1
);
next
.
current_stencil
[
0
]
=
stencil_pair
(
e
,
1.0
);
next
.
resize_for_stencil
();
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
var
.
values
[
doffset
+
k
]
*
EvaluateSub
(
next
,
0
,
element
,
user_data
);
break
;
}
default:
if
(
it
->
op
>=
AD_FUNC
)
{}
else
if
(
it
->
op
>=
AD_TABLE
)
{
lval
=
var
.
values
[
voffset
+
it
->
left
.
i
];
var
.
values
[
doffset
+
it
->
left
.
i
]
+=
var
.
values
[
doffset
+
k
]
*
reg_tables
[
it
->
op
]
->
get_derivative
(
lval
);
}
else
if
(
it
->
op
>=
AD_STNCL
)
{
for
(
INMOST_DATA_ENUM_TYPE
j
=
0
;
j
<
it
->
left
.
e
->
current_stencil
.
size
();
++
j
)
if
(
it
->
left
.
e
->
current_stencil
[
j
].
first
!=
NULL
)
{
DerivativeFill
(
*
it
->
left
.
e
,
j
,
ENUMUNDEF
,
entries
,
var
.
values
[
doffset
+
k
]
*
it
->
left
.
e
->
current_stencil
[
j
].
second
,
user_data
);
}
}
else
if
(
it
->
op
>=
AD_CTAG
)
{}
else
if
(
it
->
op
>=
AD_TAG
)
{
if
(
isDynamicValid
(
e
,
it
->
op
))
{
entries
[
GetDynamicIndex
(
e
,
it
->
op
,
it
->
left
.
i
)]
+=
var
.
values
[
doffset
+
k
];
}
}
else
assert
(
false
);
}
}
while
(
k
--
!=
0
);
}
INMOST_DATA_REAL_TYPE
Automatizator
::
EvaluateSub
(
expr
&
var
,
INMOST_DATA_ENUM_TYPE
element
,
INMOST_DATA_ENUM_TYPE
parent
,
void
*
user_data
)
{
INMOST_DATA_ENUM_TYPE
k
=
0
,
offset
=
var
.
values_offset
(
element
);
Storage
*
e
=
var
.
current_stencil
[
element
].
first
;
expr
::
expr_data
*
arr
=
&
var
.
data
[
0
],
*
it
;
//for (expr::data_type::iterator it = var.data.begin(); it != var.data.end(); ++it)
do
{
it
=
arr
+
k
;
switch
(
it
->
op
)
{
case
AD_EXT
:
assert
(
parent
!=
ENUMUNDEF
);
var
.
values
[
offset
+
k
]
=
it
->
left
.
e
->
values
[
it
->
left
.
e
->
values_offset
(
parent
)
+
it
->
right
.
i
];
break
;
case
AD_COND
:
{
expr
&
next
=
var
.
values
[
offset
+
it
->
left
.
i
]
>
0.0
?
*
it
->
right
.
q
->
left
.
e
:
*
it
->
right
.
q
->
right
.
e
;
next
.
current_stencil
.
resize
(
1
);
next
.
current_stencil
[
0
]
=
stencil_pair
(
e
,
1.0
);
next
.
resize_for_stencil
();
var
.
values
[
offset
+
k
]
=
EvaluateSub
(
next
,
0
,
element
,
user_data
);
}
break
;
case
AD_PLUS
:
var
.
values
[
offset
+
k
]
=
var
.
values
[
offset
+
it
->
left
.
i
]
+
var
.
values
[
offset
+
it
->
right
.
i
];
break
;
case
AD_MINUS
:
var
.
values
[
offset
+
k
]
=
var
.
values
[
offset
+
it
->
left
.
i
]
-
var
.
values
[
offset
+
it
->
right
.
i
];
break
;
case
AD_MULT
:
var
.
values
[
offset
+
k
]
=
var
.
values
[
offset
+
it
->
left
.
i
]
*
var
.
values
[
offset
+
it
->
right
.
i
];
break
;
case
AD_DIV
:
var
.
values
[
offset
+
k
]
=
var
.
values
[
offset
+
it
->
left
.
i
]
/
var
.
values
[
offset
+
it
->
right
.
i
];
break
;
case
AD_POW
:
var
.
values
[
offset
+
k
]
=
::
pow
(
var
.
values
[
offset
+
it
->
left
.
i
],
var
.
values
[
offset
+
it
->
right
.
i
]);
break
;
case
AD_SQRT
:
var
.
values
[
offset
+
k
]
=
::
sqrt
(
var
.
values
[
offset
+
it
->
left
.
i
]);
break
;
case
AD_ABS
:
var
.
values
[
offset
+
k
]
=
::
fabs
(
var
.
values
[
offset
+
it
->
left
.
i
]);
break
;
case
AD_EXP
:
var
.
values
[
offset
+
k
]
=
::
exp
(
var
.
values
[
offset
+
it
->
left
.
i
]);
break
;
case
AD_LOG
:
var
.
values
[
offset
+
k
]
=
::
log
(
var
.
values
[
offset
+
it
->
left
.
i
]);
break
;
case
AD_SIN
:
var
.
values
[
offset
+
k
]
=
::
sin
(
var
.
values
[
offset
+
it
->
left
.
i
]);
break
;
case
AD_COS
:
var
.
values
[
offset
+
k
]
=
::
cos
(
var
.
values
[
offset
+
it
->
left
.
i
]);
break
;
case
AD_CONST
:
var
.
values
[
offset
+
k
]
=
it
->
left
.
r
;
break
;
case
AD_COND_TYPE
:
var
.
values
[
offset
+
k
]
=
((
e
->
GetElementType
()
&
it
->
left
.
i
)
?
1.0
:
-
1.0
);
break
;
case
AD_COND_MARK
:
var
.
values
[
offset
+
k
]
=
e
->
GetMarker
(
it
->
left
.
i
)
?
1.0
:
-
1.0
;
break
;
case
AD_MES
:
assert
(
!
(
e
->
GetElementType
()
&
(
ESET
|
MESH
)));
m
->
GetGeometricData
(
static_cast
<
Element
*>
(
e
),
MEASURE
,
&
var
.
values
[
offset
+
k
]);
break
;
case
AD_VAL
:
var
.
values
[
offset
+
k
]
=
var
.
values
[
offset
+
it
->
left
.
i
];
break
;
default:
if
(
it
->
op
>=
AD_FUNC
)
var
.
values
[
offset
+
k
]
=
reg_funcs
[
it
->
op
].
func
(
e
,
user_data
);
else
if
(
it
->
op
>=
AD_TABLE
)
var
.
values
[
offset
+
k
]
=
reg_tables
[
it
->
op
]
->
get_value
(
var
.
values
[
offset
+
it
->
left
.
i
]);
else
if
(
it
->
op
>=
AD_STNCL
)
{
it
->
left
.
e
->
current_stencil
.
clear
();
GetStencil
(
it
->
op
,
e
,
user_data
,
it
->
left
.
e
->
current_stencil
);
it
->
left
.
e
->
resize_for_stencil
();
var
.
values
[
offset
+
k
]
=
0.0
;
for
(
INMOST_DATA_ENUM_TYPE
j
=
0
;
j
<
it
->
left
.
e
->
current_stencil
.
size
();
++
j
)
if
(
it
->
left
.
e
->
current_stencil
[
j
].
first
!=
NULL
)
var
.
values
[
offset
+
k
]
+=
EvaluateSub
(
*
it
->
left
.
e
,
j
,
ENUMUNDEF
,
user_data
)
*
it
->
left
.
e
->
current_stencil
[
j
].
second
;
}
else
if
(
it
->
op
>=
AD_CTAG
)
var
.
values
[
offset
+
k
]
=
GetStaticValue
(
e
,
it
->
op
,
it
->
left
.
i
);
else
if
(
it
->
op
>=
AD_TAG
)
var
.
values
[
offset
+
k
]
=
GetDynamicValue
(
e
,
it
->
op
,
it
->
left
.
i
);
else
assert
(
false
);
}
//k++;
}
while
(
++
k
!=
var
.
data
.
size
());
return
var
.
values
[
offset
+
var
.
data
.
size
()
-
1
];
}
INMOST_DATA_REAL_TYPE
Automatizator
::
Evaluate
(
expr
&
var
,
Storage
*
e
,
void
*
user_data
)
{
var
.
current_stencil
.
resize
(
1
);
var
.
current_stencil
[
0
]
=
stencil_pair
(
e
,
1.0
);
var
.
resize_for_stencil
();
return
EvaluateSub
(
var
,
0
,
ENUMUNDEF
,
user_data
);
}
INMOST_DATA_REAL_TYPE
Automatizator
::
Derivative
(
expr
&
var
,
Storage
*
e
,
Solver
::
Row
&
out
,
Storage
::
real
multiply
,
void
*
user_data
)
{
INMOST_DATA_REAL_TYPE
ret
;
var
.
current_stencil
.
resize
(
1
);
var
.
current_stencil
[
0
]
=
stencil_pair
(
e
,
1.0
);
var
.
resize_for_stencil
();
ret
=
EvaluateSub
(
var
,
0
,
ENUMUNDEF
,
user_data
);
DerivativeFill
(
var
,
0
,
ENUMUNDEF
,
out
,
multiply
,
user_data
);
return
ret
*
multiply
;
}
#else
INMOST_DATA_REAL_TYPE
Automatizator
::
DerivativePrecompute
(
const
expr
&
var
,
Storage
*
e
,
precomp_values_t
&
values
,
void
*
user_data
)
{
/*
assert
(
var
.
op
!=
AD_NONE
);
INMOST_DATA_REAL_TYPE
lval
,
rval
,
ret
=
0.0
;
switch
(
var
.
op
)
{
case
AD_COND_TYPE
:
lval
=
(
e
->
GetElementType
()
&
reinterpret_cast
<
ElementType
>
(
var
.
left
))
?
1.0
:
-
1.0
;
return
lval
;
case
AD_COND_MARK
:
lval
=
e
->
GetMarker
(
reinterpret_cast
<
MIDType
>
(
var
.
left
))
?
1.0
:
-
1.0
;
return
lval
;
case
AD_COND
:
lval
=
Evaluate
(
*
var
.
left
,
e
,
user_data
);
rval
=
DerivativePrecompute
(
*
(
lval
>
0.0
?
var
.
right
->
left
:
var
.
right
->
right
),
e
,
values
,
user_data
);
...
...
@@ -54,6 +256,11 @@ namespace INMOST
ret
=
::
pow
(
lval
,
rval
);
values
.
push_back
(
ret
);
return
ret
*
var
.
coef
;
case
AD_SQRT
:
lval
=
DerivativePrecompute
(
*
var
.
left
,
e
,
values
,
user_data
);
ret
=
::
sqrt
(
lval
);
values
.
push_back
(
ret
);
return
ret
*
var
.
coef
;
case
AD_INV
:
lval
=
DerivativePrecompute
(
*
var
.
left
,
e
,
values
,
user_data
);
values
.
push_back
(
lval
);
...
...
@@ -85,6 +292,11 @@ namespace INMOST
assert
(
!
(
e
->
GetElementType
()
&
(
ESET
|
MESH
)));
m
->
GetGeometricData
(
static_cast
<
Element
*>
(
e
),
MEASURE
,
&
ret
);
return
ret
*
var
.
coef
;
case
AD_VAL
:
lval
=
DerivativePrecompute
(
*
var
.
left
,
e
,
values
,
user_data
);
rval
=
Evaluate
(
*
var
.
left
,
e
,
user_data
);
values
.
push_back
(
rval
);
return
lval
*
var
.
coef
;
}
if
(
var
.
op
>=
AD_FUNC
)
{
...
...
@@ -100,14 +312,14 @@ namespace INMOST
}
else
if
(
var
.
op
>=
AD_STNCL
)
{
stencil_kind_domain st = reg_stencils[var.op];
stencil_kind_domain
&
st
=
reg_stencils
[
var
.
op
];
assert
(
st
.
domainmask
==
0
||
e
->
GetMarker
(
st
.
domainmask
));
if
(
st
.
kind
==
0
)
{
Storage
::
reference_array
elems
=
e
->
ReferenceArray
(
static_cast
<
stencil_tag
*>
(
st
.
link
)
->
elements
);
Storage
::
real_array
coefs
=
e
->
RealArray
(
static_cast
<
stencil_tag
*>
(
st
.
link
)
->
coefs
);
assert
(
elems
.
size
()
==
coefs
.
size
());
for (INMOST_DATA_ENUM_TYPE k = 0; k < elems.size(); ++k)
for
(
INMOST_DATA_ENUM_TYPE
k
=
0
;
k
<
elems
.
size
();
++
k
)
if
(
elems
[
k
]
!=
NULL
)
{
lval
=
DerivativePrecompute
(
*
var
.
left
,
elems
[
k
],
values
,
user_data
);
ret
+=
lval
*
coefs
[
k
];
...
...
@@ -117,7 +329,7 @@ namespace INMOST
{
stencil_pairs
get_st
;
reinterpret_cast
<
stencil_callback
>
(
st
.
link
)(
e
,
get_st
,
user_data
);
for (INMOST_DATA_ENUM_TYPE k = 0; k < get_st.size(); ++k)
for
(
INMOST_DATA_ENUM_TYPE
k
=
0
;
k
<
get_st
.
size
();
++
k
)
if
(
get_st
[
k
].
first
!=
NULL
)
{
lval
=
DerivativePrecompute
(
*
var
.
left
,
get_st
[
k
].
first
,
values
,
user_data
);
ret
+=
lval
*
get_st
[
k
].
second
;
...
...
@@ -138,17 +350,18 @@ namespace INMOST
return
ret
*
var
.
coef
;
}
assert
(
false
);
*/
return
0.0
;
}
//! returns offset from the end of precomputed values
void
Automatizator
::
DerivativeFill
(
const
expr
&
var
,
Storage
*
e
,
Solver
::
Row
&
entries
,
precomp_values_t
&
values
,
INMOST_DATA_REAL_TYPE
multval
,
void
*
user_data
)
{
/*
assert
(
var
.
op
!=
AD_NONE
);
INMOST_DATA_REAL_TYPE
lval
,
rval
,
ret
;
switch
(
var
.
op
)
{
case
AD_COND_MARK
:
case
AD_COND_TYPE
:
return
;
case
AD_COND
:
lval
=
values
.
back
();
values
.
pop_back
();
DerivativeFill
(
*
(
lval
>
0.0
?
var
.
right
->
left
:
var
.
right
->
right
),
e
,
entries
,
values
,
multval
*
var
.
coef
,
user_data
);
...
...
@@ -180,6 +393,10 @@ namespace INMOST
DerivativeFill
(
*
var
.
right
,
e
,
entries
,
values
,
multval
*
ret
*
::
log
(
lval
)
*
var
.
coef
,
user_data
);
DerivativeFill
(
*
var
.
left
,
e
,
entries
,
values
,
multval
*
ret
*
rval
/
lval
*
var
.
coef
,
user_data
);
return
;
case
AD_SQRT
:
ret
=
values
.
back
();
values
.
pop_back
();
DerivativeFill
(
*
var
.
left
,
e
,
entries
,
values
,
0.5
*
multval
/
ret
*
var
.
coef
,
user_data
);
return
;
case
AD_INV
:
lval
=
values
.
back
();
values
.
pop_back
();
DerivativeFill
(
*
var
.
left
,
e
,
entries
,
values
,
-
multval
/
(
lval
*
lval
)
*
var
.
coef
,
user_data
);
...
...
@@ -206,6 +423,10 @@ namespace INMOST
return
;
case
AD_CONST
:
return
;
case
AD_MES
:
return
;
case
AD_VAL
:
rval
=
values
.
back
();
values
.
pop_back
();
DerivativeFill
(
*
var
.
left
,
e
,
entries
,
values
,
multval
*
var
.
coef
*
rval
,
user_data
);
return
;
}
if
(
var
.
op
>=
AD_FUNC
)
{
...
...
@@ -219,21 +440,21 @@ namespace INMOST
}
else
if
(
var
.
op
>=
AD_STNCL
)
{
stencil_kind_domain st = reg_stencils[var.op];
stencil_kind_domain
&
st
=
reg_stencils
[
var
.
op
];
assert
(
st
.
domainmask
==
0
||
e
->
GetMarker
(
st
.
domainmask
));
if
(
st
.
kind
==
0
)
{
Storage
::
reference_array
elems
=
e
->
ReferenceArray
(
static_cast
<
stencil_tag
*>
(
st
.
link
)
->
elements
);
Storage
::
real_array
coefs
=
e
->
RealArray
(
static_cast
<
stencil_tag
*>
(
st
.
link
)
->
coefs
);
assert
(
elems
.
size
()
==
coefs
.
size
());
for (INMOST_DATA_ENUM_TYPE k = elems.size(); k > 0; --k)
for
(
INMOST_DATA_ENUM_TYPE
k
=
elems
.
size
();
k
>
0
;
--
k
)
if
(
elems
[
k
-
1
]
!=
NULL
)
DerivativeFill
(
*
var
.
left
,
elems
[
k
-
1
],
entries
,
values
,
var
.
coef
*
coefs
[
k
-
1
]
*
multval
,
user_data
);
}
else
if
(
st
.
kind
==
1
)
{
stencil_pairs
get_st
;
reinterpret_cast
<
stencil_callback
>
(
st
.
link
)(
e
,
get_st
,
user_data
);
for (INMOST_DATA_ENUM_TYPE k = get_st.size(); k > 0; --k)
for
(
INMOST_DATA_ENUM_TYPE
k
=
get_st
.
size
();
k
>
0
;
--
k
)
if
(
get_st
[
k
-
1
].
first
!=
NULL
)
DerivativeFill
(
*
var
.
left
,
get_st
[
k
-
1
].
first
,
entries
,
values
,
var
.
coef
*
get_st
[
k
-
1
].
second
*
multval
,
user_data
);
}
return
;
...
...
@@ -244,74 +465,76 @@ namespace INMOST
if
(
isDynamicValid
(
e
,
var
.
op
))
{
INMOST_DATA_ENUM_TYPE
ind
=
GetDynamicIndex
(
e
,
var
.
op
,
*
(
INMOST_DATA_ENUM_TYPE
*
)(
&
var
.
left
));
std::cout << ind << ", " << multval*var.coef << std::endl;
entries
[
ind
]
+=
multval
*
var
.
coef
;
}
return
;
}
assert
(
false
);
*/
return
;
}
INMOST_DATA_REAL_TYPE
Automatizator
::
Evaluate
(
const
expr
&
var
,
Storage
*
e
,
void
*
user_data
)
{
return
EvaluateSub
(
var
,
e
,
user_data
,
NULL
);
}
INMOST_DATA_REAL_TYPE
Automatizator
::
EvaluateSub
(
const
expr
&
var
,
Storage
*
e
,
void
*
user_data
,
values_container
*
parent_values
)
{
values_container
values
(
var
.
data
.
size
());
INMOST_DATA_ENUM_TYPE
k
=
0
;
for
(
expr
::
data_type
::
const_iterator
it
=
var
.
data
.
begin
();
it
!=
var
.
data
.
end
();
++
it
)
assert
(
var
.
op
!=
AD_NONE
);
switch
(
var
.
op
)
{
switch
(
it
->
op
)
case
AD_COND_MARK
:
return
e
->
GetMarker
(
reinterpret_cast
<
MIDType
>
(
var
.
left
))
?
1.0
:
-
1.0
;
case
AD_COND_TYPE
:
return
(
e
->
GetElementType
()
&
reinterpret_cast
<
ElementType
>
(
var
.
left
))
?
1.0
:
-
1.0
;
case
AD_COND
:
return
Evaluate
(
*
(
Evaluate
(
*
var
.
left
,
e
,
user_data
)
>
0.0
?
var
.
right
->
left
:
var
.
right
->
right
),
e
,
user_data
)
*
var
.
coef
;
case
AD_PLUS
:
return
(
Evaluate
(
*
var
.
left
,
e
,
user_data
)
+
Evaluate
(
*
var
.
right
,
e
,
user_data
))
*
var
.
coef
;
case
AD_MINUS
:
return
(
Evaluate
(
*
var
.
left
,
e
,
user_data
)
-
Evaluate
(
*
var
.
right
,
e
,
user_data
))
*
var
.
coef
;
case
AD_MULT
:
return
(
Evaluate
(
*
var
.
left
,
e
,
user_data
)
*
Evaluate
(
*
var
.
right
,
e
,
user_data
))
*
var
.
coef
;
case
AD_DIV
:
return
(
Evaluate
(
*
var
.
left
,
e
,
user_data
)
/
Evaluate
(
*
var
.
right
,
e
,
user_data
))
*
var
.
coef
;
case
AD_INV
:
return
var
.
coef
/
Evaluate
(
*
var
.
left
,
e
,
user_data
);
case
AD_POW
:
return
::
pow
(
Evaluate
(
*
var
.
left
,
e
,
user_data
),
Evaluate
(
*
var
.
right
,
e
,
user_data
))
*
var
.
coef
;
case
AD_SQRT
:
return
::
sqrt
(
Evaluate
(
*
var
.
left
,
e
,
user_data
))
*
var
.
coef
;
case
AD_ABS
:
return
::
fabs
(
Evaluate
(
*
var
.
left
,
e
,
user_data
))
*
var
.
coef
;
case
AD_EXP
:
return
::
exp
(
Evaluate
(
*
var
.
left
,
e
,
user_data
))
*
var
.
coef
;
case
AD_LOG
:
return
::
log
(
Evaluate
(
*
var
.
left
,
e
,
user_data
))
*
var
.
coef
;
case
AD_SIN
:
return
::
sin
(
Evaluate
(
*
var
.
left
,
e
,
user_data
))
*
var
.
coef
;
case
AD_COS
:
return
::
cos
(
Evaluate
(
*
var
.
left
,
e
,
user_data
))
*
var
.
coef
;
case
AD_CONST
:
return
var
.
coef
;
case
AD_MES
:
assert
(
!
(
e
->
GetElementType
()
&
(
ESET
|
MESH
)));
Storage
::
real
ret
;
m
->
GetGeometricData
(
static_cast
<
Element
*>
(
e
),
MEASURE
,
&
ret
);
return
ret
*
var
.
coef
;
case
AD_VAL
:
return
Evaluate
(
*
var
.
left
,
e
,
user_data
)
*
var
.
coef
;
}
if
(
var
.
op
>=
AD_FUNC
)
return
reg_funcs
[
var
.
op
].
func
(
e
,
user_data
);
if
(
var
.
op
>=
AD_TABLE
)
return
reg_tables
[
var
.
op
]
->
get_value
(
Evaluate
(
*
var
.
left
,
e
,
user_data
))
*
var
.
coef
;
if
(
var
.
op
>=
AD_STNCL
)
{
INMOST_DATA_REAL_TYPE
ret
=
0.0
;
stencil_kind_domain
&
st
=
reg_stencils
[
var
.
op
];
assert
(
st
.
domainmask
==
0
||
e
->
GetMarker
(
st
.
domainmask
));
if
(
st
.
kind
==
0
)
{
case
AD_EXT
:
values
[
k
]
=
(
*
parent_values
)[
it
->
right
.
i
];
break
;
case
AD_COND
:
if
(
values
[
it
->
left
.
i
]
>
0.0
)
values
[
k
]
=
EvaluateSub
(
*
it
->
right
.
q
->
left
.
e
,
e
,
user_data
,
&
values
);
else
values
[
k
]
=
EvaluateSub
(
*
it
->
right
.
q
->
right
.
e
,
e
,
user_data
,
&
values
);
break
;
case
AD_PLUS
:
values
[
k
]
=
values
[
it
->
left
.
i
]
+
values
[
it
->
right
.
i
];
break
;
case
AD_MINUS
:
values
[
k
]
=
values
[
it
->
left
.
i
]
-
values
[
it
->
right
.
i
];
break
;
case
AD_MULT
:
values
[
k
]
=
values
[
it
->
left
.
i
]
*
values
[
it
->
right
.
i
];
break
;
case
AD_DIV
:
values
[
k
]
=
values
[
it
->
left
.
i
]
/
values
[
it
->
right
.
i
];
break
;
case
AD_POW
:
values
[
k
]
=
::
pow
(
values
[
it
->
left
.
i
],
values
[
it
->
right
.
i
]);
break
;
case
AD_ABS
:
values
[
k
]
=
::
fabs
(
values
[
it
->
left
.
i
]);
break
;
case
AD_EXP
:
values
[
k
]
=
::
exp
(
values
[
it
->
left
.
i
]);
break
;
case
AD_LOG
:
values
[
k
]
=
::
log
(
values
[
it
->
left
.
i
]);
break
;
case
AD_SIN
:
values
[
k
]
=
::
sin
(
values
[
it
->
left
.
i
]);
break
;
case
AD_COS
:
values
[
k
]
=
::
cos
(
values
[
it
->
left
.
i
]);
break
;
case
AD_CONST
:
values
[
k
]
=
it
->
left
.
r
;
break
;
case
AD_MES
:
assert
(
!
(
e
->
GetElementType
()
&
(
ESET
|
MESH
)));
m
->
GetGeometricData
(
static_cast
<
Element
*>
(
e
),
MEASURE
,
&
values
[
k
]);
break
;
default:
if
(
it
->
op
>=
AD_FUNC
)
values
[
k
]
=
reg_funcs
[
it
->
op
].
func
(
e
,
user_data
);
else
if
(
it
->
op
>=
AD_TABLE
)
values
[
k
]
=
reg_tables
[
it
->
op
]
->
get_value
(
values
[
it
->
left
.
i
]);
else
if
(
it
->
op
>=
AD_STNCL
)
{
stencil_pairs
get_st
;
GetStencil
(
it
->
op
,
e
,
user_data
,
get_st
);
values
[
k
]
=
0.0
;
for
(
INMOST_DATA_ENUM_TYPE
k
=
0
;
k
<
get_st
.
size
();
++
k
)
values
[
k
]
+=
EvaluateSub
(
*
it
->
left
.
e
,
get_st
[
k
].
first
,
user_data
,
NULL
)
*
get_st
[
k
].
second
;
}
else
if
(
it
->
op
>=
AD_CTAG
)
values
[
k
]
=
GetStaticValue
(
e
,
it
->
op
,
it
->
left
.
i
);
else
if
(
it
->
op
>=
AD_TAG
)
values
[
k
]
=
GetDynamicValue
(
e
,
it
->
op
,
it
->
left
.
i
);
else
assert
(
false
);
Storage
::
reference_array
elems
=
e
->
ReferenceArray
(
static_cast
<
stencil_tag
*>
(
st
.
link
)
->
elements
);
Storage
::
real_array
coefs
=
e
->
RealArray
(
static_cast
<
stencil_tag
*>
(
st
.
link
)
->
coefs
);
assert
(
elems
.
size
()
==
coefs
.
size
());
for
(
INMOST_DATA_ENUM_TYPE
k
=
0
;
k
<
elems
.
size
();
++
k
)
if
(
elems
[
k
]
!=
NULL
)
ret
+=
var
.
coef
*
Evaluate
(
*
var
.
left
,
elems
[
k
],
user_data
)
*
coefs
[
k
];
}
k
++
;
else
if
(
st
.
kind
==
1
)
{
stencil_pairs
get_st
;
reinterpret_cast
<
stencil_callback
>
(
st
.
link
)(
e
,
get_st
,
user_data
);
for
(
INMOST_DATA_ENUM_TYPE
k
=
0
;
k
<
get_st
.
size
();
++
k
)
if
(
get_st
[
k
].
first
!=
NULL
)
ret
+=
var
.
coef
*
Evaluate
(
*
var
.
left
,
get_st
[
k
].
first
,
user_data
)
*
get_st
[
k
].
second
;
}
return
ret
;
}
return
values
[
var
.
data
.
size
()
-
1
];
if
(
var
.
op
>=
AD_CTAG
)
return
GetStaticValue
(
e
,
var
.
op
,
*
(
INMOST_DATA_ENUM_TYPE
*
)(
&
var
.
left
))
*
var
.
coef
;
if
(
var
.
op
>=
AD_TAG
)
return
GetDynamicValue
(
e
,
var
.
op
,
*
(
INMOST_DATA_ENUM_TYPE
*
)(
&
var
.
left
))
*
var
.
coef
;
assert
(
false
);
return
0.0
;
}
INMOST_DATA_REAL_TYPE
Automatizator
::
Derivative
(
const
expr
&
var
,
Storage
*
e
,
Solver
::
Row
&
out
,
void
*
user_data
)
INMOST_DATA_REAL_TYPE
Automatizator
::
Derivative
(
const
expr
&
var
,
Storage
*
e
,
Solver
::
Row
&
out
,
Storage
::
real
multiply
,
void
*
user_data
)
{
INMOST_DATA_REAL_TYPE
ret
;
precomp_values_t
values
;
ret
=
DerivativePrecompute
(
var
,
e
,
values
,
user_data
);
DerivativeFill
(
var
,
e
,
out
,
values
,
1.0
,
user_data
);
return
ret
;
DerivativeFill
(
var
,
e
,
out
,
values
,
multiply
,
user_data
);
return
ret
*
multiply
;
}
#endif
Automatizator
::
Automatizator
(
Mesh
*
m
)
:
first_num
(
0
),
last_num
(
0
),
m
(
m
)
{}
Automatizator
::~
Automatizator
()
{
...
...
@@ -400,80 +623,23 @@ namespace INMOST
{
first_num
=
last_num
=
0
;
const
ElementType
paralleltypes
=
NODE
|
EDGE
|
FACE
|
CELL
;
for
(
index_enum
::
iterator
it
=
index_tags
.
begin
();
it
!=
index_tags
.
end
();
++
it
)
for
(
ElementType
etype
=
NODE
;
etype
<=
MESH
;
etype
=
etype
<<
1
)
if
(
it
->
indices
.
isDefined
(
etype
)
&&
it
->
indices
.
isSparse
(
etype
))
for
(
Mesh
::
base_iterator
jt
=
m
->
Begin
(
etype
);
jt
!=
m
->
End
();
++
jt
)
jt
->
DelData
(
it
->
indices
);
for
(
index_enum
::
iterator
it
=
index_tags
.
begin
();
it
!=
index_tags
.
end
();
++
it
)
{
for
(
ElementType
etype
=
NODE
;
etype
<=
MESH
;
etype
=
etype
<<
1
)
if
(
it
->
indices
.
isDefined
(
etype
))
{
if
(
it
->
indices
.
GetSize
()
==
ENUMUNDEF
)
if
(
it
->
indices
.
isDefined
(
etype
)
&&
it
->
indices
.
isSparse
(
etype
))
{
if
(
!
it
->
indices
.
isSparse
(
etype
))
{
for
(
Mesh
::
base_iterator
jt
=
m
->
Begin
(
etype
);
jt
!=
m
->
End
();
++
jt
)
if
(((
etype
&
paralleltypes
)
&&
static_cast
<
Element
*>
(
&*
jt
)
->
GetStatus
()
!=
Element
::
Ghost
)
&&
(
it
->
d
.
domain_mask
==
0
||
jt
->
GetMarker
(
it
->
d
.
domain_mask
)))
{
Storage
::
integer_array
indarr
=
jt
->
IntegerArray
(
it
->
indices
);
indarr
.
resize
(
jt
->
RealArray
(
it
->
d
.
t
).
size
());
for
(
Storage
::
integer_array
::
iterator
qt
=
indarr
.
begin
();
qt
!=
indarr
.
end
();
++
qt
)
*
qt
=
last_num
++
;
}
}
else
{
for
(
Mesh
::
base_iterator
jt
=
m
->
Begin
(
etype
);
jt
!=
m
->
End
();
++
jt
)
if
(((
etype
&
paralleltypes
)
&&
static_cast
<
Element
*>
(
&*
jt
)
->
GetStatus
()
!=
Element
::
Ghost
)
&&
(
jt
->
HaveData
(
it
->
d
.
t
)
&&
(
it
->
d
.
domain_mask
==
0
||
jt
->
GetMarker
(
it
->
d
.
domain_mask
))))
{
Storage
::
integer_array
indarr
=
jt
->
IntegerArray
(
it
->
indices
);
indarr
.
resize
(
jt
->
RealArray
(
it
->
d
.
t
).
size
());
for
(
Storage
::
integer_array
::
iterator
qt
=
indarr
.
begin
();
qt
!=
indarr
.
end
();
++
qt
)
*
qt
=
last_num
++
;
}
}
}
else
{
if
(
!
it
->
indices
.
isSparse
(
etype
))
{
for
(
Mesh
::
base_iterator
jt
=
m
->
Begin
(
etype
);
jt
!=
m
->
End
();
++
jt
)
if
(((
etype
&
paralleltypes
)
&&
static_cast
<
Element
*>
(
&*
jt
)
->
GetStatus
()
!=
Element
::
Ghost
)
&&
(
it
->
d
.
domain_mask
==
0
||
jt
->
GetMarker
(
it
->
d
.
domain_mask
)))
{
Storage
::
integer_array
indarr
=
jt
->
IntegerArray
(
it
->
indices
);
for
(
Storage
::
integer_array
::
iterator
qt
=
indarr
.
begin
();
qt
!=
indarr
.
end
();
++
qt
)
*
qt
=
last_num
++
;
}
}
else
{
for
(
Mesh
::
base_iterator
jt
=
m
->
Begin
(
etype
);
jt
!=
m
->
End
();
++
jt
)
if
(((
etype
&
paralleltypes
)
&&
static_cast
<
Element
*>
(
&*
jt
)
->
GetStatus
()
!=
Element
::
Ghost
)
&&
(
jt
->
HaveData
(
it
->
d
.
t
)
&&
(
it
->
d
.
domain_mask
==
0
||
jt
->
GetMarker
(
it
->
d
.
domain_mask
))))
{
Storage
::
integer_array
indarr
=
jt
->
IntegerArray
(
it
->
indices
);
for
(
Storage
::
integer_array
::
iterator
qt
=
indarr
.
begin
();
qt
!=
indarr
.
end
();
++
qt
)
*
qt
=
last_num
++
;
}
}
for
(
Mesh
::
base_iterator
jt
=
m
->
Begin
(
etype
);
jt
!=
m
->
End
();
++
jt
)
jt
->
DelData
(
it
->
indices
);
}
}
}
#if defined(USE_MPI)
if
(
m
->
GetProcessorsNumber
()
>
1
)
for
(
index_enum
::
iterator
it
=
index_tags
.
begin
();
it
!=
index_tags
.
end
();
++
it
)
{
MPI_Scan
(
&
last_num
,
&
first_num
,
1
,
INMOST_MPI_DATA_ENUM_TYPE
,
MPI_SUM
,
m
->
GetCommunicator
());
first_num
-=
last_num
;
ElementType
exch_mask
=
NONE
;
if
(
first_num
>
0
)
for
(
index_enum
::
iterator
it
=
index_tags
.
begin
();
it
!=
index_tags
.
end
();
++
it
)
for
(
ElementType
etype
=
NODE
;
etype
<=
MESH
;
etype
=
etype
<<
1
)
{
for
(
ElementType
etype
=
NODE
;
etype
<=
MESH
;
etype
=
etype
<<
1
)
if
(
it
->
indices
.
isDefined
(
etype
))
{
exch_mask
|=
etype
;
if
(
it
->
indices
.
GetSize
()
==
ENUMUNDEF
)
{
if
(
!
it
->
indices
.
isSparse
(
etype
))
...
...
@@ -482,8 +648,9 @@ namespace INMOST