Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F91940175
statefield.hh
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Nov 15, 23:08
Size
22 KB
Mime Type
text/x-c
Expires
Sun, Nov 17, 23:08 (2 d)
Engine
blob
Format
Raw Data
Handle
22350784
Attached To
rMUSPECTRE µSpectre
statefield.hh
View Options
/**
* file statefield.hh
*
* @author Till Junge <till.junge@epfl.ch>
*
* @date 28 Feb 2018
*
* @brief A state field is an abstraction of a field that can hold
* current, as well as a chosen number of previous values. This is
* useful for instance for internal state variables in plastic laws,
* where a current, new, or trial state is computed based on its
* previous state, and at convergence, this new state gets cycled into
* the old, the old into the old-1 etc. The state field abstraction
* helps doing this safely (i.e. only const references to the old
* states are available, while the current state can be assigned
* to/modified), and efficiently (i.e., no need to copy values from
* new to old, we just cycle the labels). This file implements the
* state field as well as state maps using the Field, FieldCollection
* and FieldMap abstractions of µSpectre
*
* Copyright © 2018 Till Junge
*
* µSpectre is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3, or (at
* your option) any later version.
*
* µSpectre is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Emacs; see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef STATEFIELD_H
#define STATEFIELD_H
#include "common/field_helpers.hh"
#include "common/field.hh"
#include "common/utilities.hh"
#include <array>
#include <string>
#include <sstream>
namespace
muSpectre
{
/**
* Forward-declaration
*/
template
<
class
FieldCollection
,
typename
T
>
class
TypedField
;
/**
* Base class for state fields, useful for storing polymorphic references
*/
template
<
class
FieldCollection
>
class
StateFieldBase
{
public
:
//! get naming prefix
const
std
::
string
&
get_prefix
()
const
{
return
this
->
prefix
;}
//! get a ref to the `StateField` 's field collection
const
FieldCollection
&
get_collection
()
const
{
return
this
->
collection
;}
virtual
~
StateFieldBase
()
=
default
;
/**
* returns number of old states that are stored
*/
size_t
get_nb_memory
()
const
{
return
this
->
nb_memory
;}
//! return type_id of stored type
virtual
const
std
::
type_info
&
get_stored_typeid
()
const
=
0
;
/**
* cycle the fields (current becomes old, old becomes older,
* oldest becomes current)
*/
virtual
void
cycle
()
=
0
;
protected
:
//! constructor
StateFieldBase
(
std
::
string
unique_prefix
,
const
FieldCollection
&
collection
,
size_t
nb_memory
=
1
)
:
prefix
{
unique_prefix
},
nb_memory
{
nb_memory
},
collection
{
collection
}
{}
/**
* the unique prefix is used as the first part of the unique name
* of the subfields belonging to this state field
*/
std
::
string
prefix
;
/**
* number of old states to store, defaults to 1
*/
const
size_t
nb_memory
;
//! reference to the collection this statefield belongs to
const
FieldCollection
&
collection
;
};
/* ---------------------------------------------------------------------- */
template
<
class
FieldCollection
,
typename
T
>
class
TypedStateField
:
public
StateFieldBase
<
FieldCollection
>
{
public
:
//! Parent class
using
Parent
=
StateFieldBase
<
FieldCollection
>
;
//! Typed field
using
TypedField_t
=
TypedField
<
FieldCollection
,
T
>
;
//! returns a TypedField ref to the current value of this state field
virtual
TypedField_t
&
get_current_field
()
=
0
;
//! returns a const TypedField ref to an old value of this state field
virtual
const
TypedField_t
&
get_old_field
(
size_t
nb_steps_ago
=
1
)
const
=
0
;
//! return type_id of stored type
const
std
::
type_info
&
get_stored_typeid
()
const
override
final
{
return
typeid
(
T
);
};
virtual
~
TypedStateField
()
=
default
;
protected
:
//! constructor
TypedStateField
(
const
std
::
string
&
unique_prefix
,
const
FieldCollection
&
collection
,
size_t
nb_memory
)
:
Parent
{
unique_prefix
,
collection
,
nb_memory
}
{}
};
/* ---------------------------------------------------------------------- */
template
<
class
FieldCollection
,
size_t
nb_memory
,
typename
T
>
class
TypedSizedStateField
:
public
TypedStateField
<
FieldCollection
,
T
>
{
public
:
//! Parent class
using
Parent
=
TypedStateField
<
FieldCollection
,
T
>
;
//! the current (historically accurate) ordering of the fields
using
index_t
=
std
::
array
<
size_t
,
nb_memory
+
1
>
;
//! get the current ordering of the fields
inline
const
index_t
&
get_indices
()
const
{
return
this
->
indices
;}
//! destructor
virtual
~
TypedSizedStateField
()
=
default
;
protected
:
//! constructor
TypedSizedStateField
(
std
::
string
unique_prefix
,
const
FieldCollection
&
collection
,
index_t
indices
)
:
Parent
{
unique_prefix
,
collection
,
nb_memory
},
indices
{
indices
}{};
index_t
indices
;
///< these are cycled through
};
//! early declaration
template
<
class
FieldMap
,
size_t
nb_memory
>
class
StateFieldMap
;
namespace
internal
{
template
<
class
Field
,
size_t
size
,
size_t
...
I
>
inline
decltype
(
auto
)
build_fields_helper
(
std
::
string
prefix
,
typename
Field
::
Base
::
collection_t
&
collection
,
std
::
index_sequence
<
I
...
>
)
{
auto
get_field
{[
&
prefix
,
&
collection
](
size_t
i
)
->
Field
&
{
std
::
stringstream
name_stream
{};
name_stream
<<
prefix
<<
", sub_field index "
<<
i
;
return
make_field
<
Field
>
(
name_stream
.
str
(),
collection
);
}};
return
std
::
tie
(
get_field
(
I
)...);
}
/* ---------------------------------------------------------------------- */
template
<
size_t
size
,
size_t
...
I
>
inline
decltype
(
auto
)
build_indices
(
std
::
index_sequence
<
I
...
>
)
{
return
std
::
array
<
size_t
,
size
>
{(
size
-
I
)
%
size
...};
}
}
// internal
/**
* A statefield is an abstraction around a Field that can hold a
* current and `nb_memory` previous values. There are useful for
* history variables, for instance.
*/
template
<
class
Field_t
,
size_t
nb_memory
=
1
>
class
StateField
:
public
TypedSizedStateField
<
typename
Field_t
::
Base
::
collection_t
,
nb_memory
,
typename
Field_t
::
Scalar
>
{
public
:
//! the underlying field's collection type
using
FieldCollection_t
=
typename
Field_t
::
Base
::
collection_t
;
//! base type for fields
using
Scalar
=
typename
Field_t
::
Scalar
;
//! Base class for all state fields of same memory
using
Base
=
TypedSizedStateField
<
FieldCollection_t
,
nb_memory
,
Scalar
>
;
/**
* storage of field refs (can't be a `std::array`, because arrays
* of refs are explicitely forbidden
*/
using
Fields_t
=
tuple_array
<
Field_t
&
,
nb_memory
+
1
>
;
//! Typed field
using
TypedField_t
=
TypedField
<
FieldCollection_t
,
Scalar
>
;
//! Default constructor
StateField
()
=
delete
;
//! Copy constructor
StateField
(
const
StateField
&
other
)
=
delete
;
//! Move constructor
StateField
(
StateField
&&
other
)
=
delete
;
//! Destructor
virtual
~
StateField
()
=
default
;
//! Copy assignment operator
StateField
&
operator
=
(
const
StateField
&
other
)
=
delete
;
//! Move assignment operator
StateField
&
operator
=
(
StateField
&&
other
)
=
delete
;
//! get (modifiable) current field
inline
Field_t
&
current
()
{
return
this
->
fields
[
this
->
indices
[
0
]];
}
//! get (constant) previous field
template
<
size_t
nb_steps_ago
=
1
>
inline
const
Field_t
&
old
()
{
static_assert
(
nb_steps_ago
<=
nb_memory
,
"you can't go that far inte the past"
);
static_assert
(
nb_steps_ago
>
0
,
"Did you mean to call current()?"
);
return
this
->
fields
[
this
->
indices
.
at
(
nb_steps_ago
)];
}
//! returns a TypedField ref to the current value of this state field
TypedField_t
&
get_current_field
()
override
final
{
return
this
->
current
();
}
//! returns a const TypedField ref to an old value of this state field
const
TypedField_t
&
get_old_field
(
size_t
nb_steps_ago
=
1
)
const
override
final
{
return
this
->
fields
[
this
->
indices
.
at
(
nb_steps_ago
)];
}
//! factory function
template
<
class
StateFieldType
,
class
CollectionType
>
friend
StateFieldType
&
make_statefield
(
const
std
::
string
&
unique_prefix
,
CollectionType
&
collection
);
//! returns a `StateField` reference if `other is a compatible state field
inline
static
StateField
&
check_ref
(
Base
&
other
)
{
// the following triggers and exception if the fields are incompatible
Field_t
::
check_ref
(
other
.
fields
[
0
]);
return
static_cast
<
StateField
&>
(
other
);
}
//! returns a const `StateField` reference if `other` is a compatible state field
inline
static
const
StateField
&
check_ref
(
const
Base
&
other
)
{
// the following triggers and exception if the fields are incompatible
Field_t
::
check_ref
(
other
.
fields
[
0
]);
return
static_cast
<
const
StateField
&>
(
other
);
}
//! get a ref to the `StateField` 's fields
Fields_t
&
get_fields
()
{
return
this
->
fields
;
}
/**
* Pure convenience functions to get a MatrixFieldMap of
* appropriate dimensions mapped to this field. You can also
* create other types of maps, as long as they have the right
* fundamental type (T), the correct size (nbComponents), and
* memory (nb_memory).
*/
inline
decltype
(
auto
)
get_map
()
{
using
FieldMap
=
decltype
(
std
::
get
<
0
>
(
this
->
fields
).
get_map
());
return
StateFieldMap
<
FieldMap
,
nb_memory
>
(
*
this
);
}
/**
* Pure convenience functions to get a MatrixFieldMap of
* appropriate dimensions mapped to this field. You can also
* create other types of maps, as long as they have the right
* fundamental type (T), the correct size (nbComponents), and
* memory (nb_memory).
*/
inline
decltype
(
auto
)
get_const_map
()
{
using
FieldMap
=
decltype
(
std
::
get
<
0
>
(
this
->
fields
).
get_const_map
());
return
StateFieldMap
<
FieldMap
,
nb_memory
>
(
*
this
);
}
/**
* cycle the fields (current becomes old, old becomes older,
* oldest becomes current)
*/
inline
void
cycle
()
override
final
{
for
(
auto
&
val:
this
->
indices
)
{
val
=
(
val
+
1
)
%
(
nb_memory
+
1
);
}
}
protected
:
/**
* Constructor. @param unique_prefix is used to create the names
* of the fields that this abstraction creates in the background
* @param collection is the field collection in which the
* subfields will be stored
*/
inline
StateField
(
const
std
::
string
&
unique_prefix
,
FieldCollection_t
&
collection
)
:
Base
{
unique_prefix
,
collection
,
internal
::
build_indices
<
nb_memory
+
1
>
(
std
::
make_index_sequence
<
nb_memory
+
1
>
{})},
fields
{
internal
::
build_fields_helper
<
Field_t
,
nb_memory
+
1
>
(
unique_prefix
,
collection
,
std
::
make_index_sequence
<
nb_memory
+
1
>
{})}
{}
Fields_t
fields
;
//!< container for the states
private
:
};
namespace
internal
{
template
<
class
FieldMap
,
size_t
size
,
class
Fields
,
size_t
...
I
>
inline
decltype
(
auto
)
build_maps_helper
(
Fields
&
fields
,
std
::
index_sequence
<
I
...
>
)
{
return
std
::
array
<
FieldMap
,
size
>
{
FieldMap
(
std
::
get
<
I
>
(
fields
))...};
}
}
// internal
/* ---------------------------------------------------------------------- */
template
<
class
StateFieldType
,
class
CollectionType
>
inline
StateFieldType
&
make_statefield
(
const
std
::
string
&
unique_prefix
,
CollectionType
&
collection
)
{
std
::
unique_ptr
<
StateFieldType
>
ptr
{
new
StateFieldType
(
unique_prefix
,
collection
)};
auto
&
retref
{
*
ptr
};
collection
.
register_statefield
(
std
::
move
(
ptr
));
return
retref
;
}
/**
* extends the StateField <-> Field equivalence to StateFieldMap <-> FieldMap
*/
template
<
class
FieldMap
,
size_t
nb_memory
=
1
>
class
StateFieldMap
{
public
:
/**
* iterates over all pixels in the `muSpectre::FieldCollection` and
* dereferences to a proxy giving access to the appropriate iterates
* of the underlying `FieldMap` type.
*/
class
iterator
;
//! stl conformance
using
reference
=
typename
iterator
::
reference
;
//! stl conformance
using
value_type
=
typename
iterator
::
value_type
;
//! stl conformance
using
size_type
=
typename
iterator
::
size_type
;
//! field collection type where this state field can be stored
using
FieldCollection_t
=
typename
FieldMap
::
Field
::
collection_t
;
//! Fundamental type stored
using
Scalar
=
typename
FieldMap
::
Scalar
;
//! base class (must be at least sized)
using
TypedSizedStateField_t
=
TypedSizedStateField
<
FieldCollection_t
,
nb_memory
,
Scalar
>
;
//! for traits access
using
FieldMap_t
=
FieldMap
;
//! for traits access
using
ConstFieldMap_t
=
typename
FieldMap
::
ConstMap
;
//! Default constructor
StateFieldMap
()
=
delete
;
//! constructor using a StateField
template
<
class
StateField
>
StateFieldMap
(
StateField
&
statefield
)
:
collection
{
statefield
.
get_collection
()},
statefield
{
statefield
},
maps
{
internal
::
build_maps_helper
<
FieldMap
,
nb_memory
+
1
>
(
statefield
.
get_fields
(),
std
::
make_index_sequence
<
nb_memory
+
1
>
{})},
const_maps
{
internal
::
build_maps_helper
<
ConstFieldMap_t
,
nb_memory
+
1
>
(
statefield
.
get_fields
(),
std
::
make_index_sequence
<
nb_memory
+
1
>
{})}
{
static_assert
(
std
::
is_base_of
<
TypedSizedStateField_t
,
StateField
>::
value
,
"Not the right type of StateField ref"
);
}
//! Copy constructor
StateFieldMap
(
const
StateFieldMap
&
other
)
=
delete
;
//! Move constructor
StateFieldMap
(
StateFieldMap
&&
other
)
=
default
;
//! Destructor
virtual
~
StateFieldMap
()
=
default
;
//! Copy assignment operator
StateFieldMap
&
operator
=
(
const
StateFieldMap
&
other
)
=
delete
;
//! Move assignment operator
StateFieldMap
&
operator
=
(
StateFieldMap
&&
other
)
=
delete
;
//! access the wrapper to a given pixel directly
value_type
operator
[](
size_type
index
)
{
return
*
iterator
(
*
this
,
index
);
}
/**
* return a ref to the current field map. useful for instance for
* initialisations of `StateField` instances
*/
FieldMap
&
current
()
{
return
this
->
maps
[
this
->
statefield
.
get_indices
()[
0
]];
}
//! stl conformance
iterator
begin
()
{
return
iterator
(
*
this
,
0
);}
//! stl conformance
iterator
end
()
{
return
iterator
(
*
this
,
this
->
collection
.
size
());}
protected
:
const
FieldCollection_t
&
collection
;
//!< collection holding the field
TypedSizedStateField_t
&
statefield
;
//!< ref to the field itself
std
::
array
<
FieldMap
,
nb_memory
+
1
>
maps
;
//!< refs to the addressable maps;
//! const refs to the addressable maps;
std
::
array
<
ConstFieldMap_t
,
nb_memory
+
1
>
const_maps
;
private
:
};
/**
* Iterator class used by the `StateFieldMap`
*/
template
<
class
FieldMap
,
size_t
nb_memory
>
class
StateFieldMap
<
FieldMap
,
nb_memory
>::
iterator
{
public
:
class
StateWrapper
;
using
Ccoord
=
typename
FieldMap
::
Ccoord
;
//!< cell coordinates type
using
value_type
=
StateWrapper
;
//!< stl conformance
using
const_value_type
=
value_type
;
//!< stl conformance
using
pointer_type
=
value_type
*
;
//!< stl conformance
using
difference_type
=
std
::
ptrdiff_t
;
//!< stl conformance
using
size_type
=
size_t
;
//!< stl conformance
using
iterator_category
=
std
::
random_access_iterator_tag
;
//!< stl conformance
using
reference
=
StateWrapper
;
//!< stl conformance
//! Default constructor
iterator
()
=
delete
;
//! constructor
iterator
(
StateFieldMap
&
map
,
size_t
index
=
0
)
:
index
{
index
},
map
{
map
}
{};
//! Copy constructor
iterator
(
const
iterator
&
other
)
=
default
;
//! Move constructor
iterator
(
iterator
&&
other
)
=
default
;
//! Destructor
virtual
~
iterator
()
=
default
;
//! Copy assignment operator
iterator
&
operator
=
(
const
iterator
&
other
)
=
default
;
//! Move assignment operator
iterator
&
operator
=
(
iterator
&&
other
)
=
default
;
//! pre-increment
inline
iterator
&
operator
++
()
{
this
->
index
++
;
return
*
this
;}
//! post-increment
inline
iterator
operator
++
(
int
)
{
iterator
curr
{
*
this
};
this
->
index
++
;
return
curr
;}
//! dereference
inline
value_type
operator
*
()
{
return
value_type
(
*
this
);}
//! pre-decrement
inline
iterator
&
operator
--
()
{
this
->
index
--
;
return
*
this
;}
//! post-decrement
inline
iterator
operator
--
(
int
)
{
iterator
curr
{
*
this
};
this
->
index
--
;
return
curr
;}
//! access subscripting
inline
value_type
operator
[](
difference_type
diff
)
{
return
value_type
{
iterator
{
this
->
map
,
this
->
index
+
diff
}};}
//! equality
inline
bool
operator
==
(
const
iterator
&
other
)
const
{
return
this
->
index
==
other
.
index
;
}
//! inequality
inline
bool
operator
!=
(
const
iterator
&
other
)
const
{
return
this
->
index
!=
other
.
index
;}
//! div. comparisons
inline
bool
operator
<
(
const
iterator
&
other
)
const
{
return
this
->
index
<
other
.
index
;
}
//! div. comparisons
inline
bool
operator
<=
(
const
iterator
&
other
)
const
{
return
this
->
index
<=
other
.
index
;
}
//! div. comparisons
inline
bool
operator
>
(
const
iterator
&
other
)
const
{
return
this
->
index
>
other
.
index
;
}
//! div. comparisons
inline
bool
operator
>=
(
const
iterator
&
other
)
const
{
return
this
->
index
>=
other
.
index
;
}
//! additions, subtractions and corresponding assignments
inline
iterator
operator
+
(
difference_type
diff
)
const
{
return
iterator
{
this
->
map
,
this
-
index
+
diff
};
}
//! additions, subtractions and corresponding assignments
inline
iterator
operator
-
(
difference_type
diff
)
const
{
return
iterator
{
this
->
map
,
this
-
index
-
diff
};}
//! additions, subtractions and corresponding assignments
inline
iterator
&
operator
+=
(
difference_type
diff
)
{
this
->
index
+=
diff
;
return
*
this
;}
//! additions, subtractions and corresponding assignments
inline
iterator
&
operator
-=
(
difference_type
diff
)
{
this
->
index
-=
diff
;
return
*
this
;
}
//! get pixel coordinates
inline
Ccoord
get_ccoord
()
const
{
return
this
->
map
.
collection
.
get_ccoord
(
this
->
index
);
}
//! access the index
inline
const
size_t
&
get_index
()
const
{
return
this
->
index
;}
protected
:
size_t
index
;
//!< current pixel this iterator refers to
StateFieldMap
&
map
;
//!< map over with `this` iterates
private
:
};
namespace
internal
{
//! FieldMap is an `Eigen::Map` or `Eigen::TensorMap` here
template
<
class
FieldMap
,
size_t
size
,
size_t
...
I
,
class
iterator
,
class
maps_t
,
class
indices_t
>
inline
decltype
(
auto
)
build_old_vals_helper
(
iterator
&
it
,
maps_t
&
maps
,
indices_t
&
indices
,
std
::
index_sequence
<
I
...
>
)
{
return
tuple_array
<
FieldMap
,
size
>
(
std
::
forward_as_tuple
(
maps
[
indices
[
I
+
1
]][
it
.
get_index
()]...));
}
template
<
class
FieldMap
,
size_t
size
,
class
iterator
,
class
maps_t
,
class
indices_t
>
inline
decltype
(
auto
)
build_old_vals
(
iterator
&
it
,
maps_t
&
maps
,
indices_t
&
indices
)
{
return
tuple_array
<
FieldMap
,
size
>
{
build_old_vals_helper
<
FieldMap
,
size
>
(
it
,
maps
,
indices
,
std
::
make_index_sequence
<
size
>
{})};
}
}
// internal
/**
* Light-weight resource-handle representing the current and old
* values of a field at a given pixel identified by an iterator
* pointing to it
*/
template
<
class
FieldMap
,
size_t
nb_memory
>
class
StateFieldMap
<
FieldMap
,
nb_memory
>::
iterator
::
StateWrapper
{
public
:
//! short-hand
using
iterator
=
typename
StateFieldMap
::
iterator
;
//! short-hand
using
Ccoord
=
typename
iterator
::
Ccoord
;
//! short-hand
using
Map
=
typename
FieldMap
::
reference
;
//! short-hand
using
ConstMap
=
typename
FieldMap
::
const_reference
;
//! Default constructor
StateWrapper
()
=
delete
;
//! Copy constructor
StateWrapper
(
const
StateWrapper
&
other
)
=
default
;
//! Move constructor
StateWrapper
(
StateWrapper
&&
other
)
=
default
;
//! construct with `StateFieldMap::iterator`
StateWrapper
(
iterator
&
it
)
:
it
{
it
},
current_val
{
it
.
map
.
maps
[
it
.
map
.
statefield
.
get_indices
()[
0
]][
it
.
index
]},
old_vals
(
internal
::
build_old_vals
<
ConstMap
,
nb_memory
>
(
it
,
it
.
map
.
const_maps
,
it
.
map
.
statefield
.
get_indices
()))
{
}
//! Destructor
virtual
~
StateWrapper
()
=
default
;
//! Copy assignment operator
StateWrapper
&
operator
=
(
const
StateWrapper
&
other
)
=
default
;
//! Move assignment operator
StateWrapper
&
operator
=
(
StateWrapper
&&
other
)
=
default
;
//! returns reference to the currectly mapped value
inline
Map
&
current
()
{
return
this
->
current_val
;
}
//! recurnts reference the the value that was current `nb_steps_ago` ago
template
<
size_t
nb_steps_ago
=
1
>
inline
const
ConstMap
&
old
()
const
{
static_assert
(
nb_steps_ago
<=
nb_memory
,
"You have not stored that time step"
);
static_assert
(
nb_steps_ago
>
0
,
"Did you mean to access the current value? If so, use "
"current()"
);
return
std
::
get
<
nb_steps_ago
-
1
>
(
this
->
old_vals
);
}
//! read the coordinates of the current pixel
inline
Ccoord
get_ccoord
()
const
{
return
this
->
it
.
get_ccoord
();
}
protected
:
iterator
&
it
;
//!< ref to the iterator that dereferences to `this`
Map
current_val
;
//!< current value
tuple_array
<
ConstMap
,
nb_memory
>
old_vals
;
//!< all stored old values
private
:
};
}
// muSpectre
#endif
/* STATEFIELD_H */
Event Timeline
Log In to Comment