Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c35cfed
Start on reading in new format of fixed comp BI
anne-glerum Apr 29, 2026
a83baa6
Use masks for each boundary indicator
anne-glerum May 1, 2026
d79e391
Track field masks and boundary ids per plugin instead
anne-glerum May 4, 2026
663c749
Fix other logic and astyle
anne-glerum May 4, 2026
c702796
Clean up and fix operators
anne-glerum May 5, 2026
0d54ced
Add bi to fixed_bi, add getter functions
anne-glerum May 6, 2026
260bee1
Make vector of masks vector and fix Asserts
anne-glerum May 6, 2026
7bb6abf
Add another getter
anne-glerum May 6, 2026
5e578f6
Limit calls to boundary composition to fixed fields
anne-glerum May 6, 2026
96cf059
Add getter, fix function, add checks, indent
anne-glerum May 7, 2026
6124bc2
Add todo
anne-glerum May 7, 2026
8257c44
Add tests
anne-glerum May 7, 2026
2b780fc
Update tests
anne-glerum May 11, 2026
d4660ba
Update function names, comments, todos, asserts
anne-glerum May 11, 2026
e077394
Make model operators boundary dependent as well
anne-glerum May 11, 2026
4a2e3e8
Update documentation
anne-glerum May 11, 2026
eca3d02
Add changelog
anne-glerum May 11, 2026
a5d45ba
Update input format
anne-glerum Jun 11, 2026
db132e3
Only specify box BC for fixed fields
anne-glerum Jun 11, 2026
47b5f8a
Only specify function BC for fixed fields
anne-glerum Jun 11, 2026
968c13f
Only specify spherical constant BC for fixed fields
anne-glerum Jun 12, 2026
b352969
Only specify ascii data BC for fixed fields
anne-glerum Jun 12, 2026
99f745f
Only specify two merged boxes BC for fixed fields
anne-glerum Jun 12, 2026
79e0341
Add test function boundary composition
anne-glerum Jun 12, 2026
aabf5e4
Update comments and remove unused function
anne-glerum Jun 15, 2026
6e994ac
Simplify code
anne-glerum Jun 15, 2026
22f70d3
Update parameters
anne-glerum Jun 15, 2026
9b48c2b
Return empty set instead of throwing
anne-glerum Jun 15, 2026
65af789
Update test result
anne-glerum Jun 16, 2026
ab57126
Add Assert
anne-glerum Jun 16, 2026
2e09539
Remove unused parameters
anne-glerum Jun 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Test data for ascii data boundary composition.
# Only next line is parsed in format: [nx] [ny] because of keyword "POINTS:"
# POINTS: 3 3
# Columns: x y composition_1 composition_2.
0. 0. 0. 0.
330000. 0. 0. 0.
660000. 0. 0. 0.
0. 330000. 1. 1.
330000. 330000. 1. 1.
660000. 330000. 1. 1.
0. 660000. 0. 0.
330000. 660000. 0. 0.
660000. 660000. 0. 0.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Test data for ascii data boundary composition.
# Only next line is parsed in format: [nx] [ny] because of keyword "POINTS:"
# POINTS: 3 3
# Columns: x z composition_1 composition_2.
0. 0. 0. 0.
330000. 0. 0. 0.
660000. 0. 0. 0.
0. 330000. 1. 1.
330000. 330000. 1. 1.
660000. 330000. 1. 1.
0. 660000. 0. 0.
330000. 660000. 0. 0.
660000. 660000. 0. 0.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Test data for ascii data boundary composition.
# Only next line is parsed in format: [nx] [ny] because of keyword "POINTS:"
# POINTS: 3 3
# Columns: x y composition_1 composition_2.
0. 0. 0. 0.
330000. 0. 0. 0.
660000. 0. 0. 0.
0. 330000. 1. 1.
330000. 330000. 1. 1.
660000. 330000. 1. 1.
0. 660000. 0. 0.
330000. 660000. 0. 0.
660000. 660000. 0. 0.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Test data for ascii data boundary composition.
# Only next line is parsed in format: [nx] [ny] because of keyword "POINTS:"
# POINTS: 3 3
# Columns: x z composition_1 composition_2.
0. 0. 0. 0.
330000. 0. 1. 1.
660000. 0. 0. 0.
0. 330000. 1. 1.
330000. 330000. 1. 1.
660000. 330000. 1. 1.
0. 660000. 0. 0.
330000. 660000. 1. 1.
660000. 660000. 0. 0.
13 changes: 13 additions & 0 deletions data/boundary-composition/ascii-data/test/box_3d_2fields_top.0.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Test data for ascii data boundary composition.
# Only next line is parsed in format: [nx] [ny] because of keyword "POINTS:"
# POINTS: 3 3
# Columns: x z composition_1 composition_2.
0. 0. 0. 0.
330000. 0. 0. 0.
660000. 0. 0. 0.
0. 330000. 1. 1.
330000. 330000. 1. 1.
660000. 330000. 1. 1.
0. 660000. 0. 0.
330000. 660000. 0. 0.
660000. 660000. 0. 0.
7 changes: 7 additions & 0 deletions doc/modules/changes/20260511_glerum
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
New: It is now possible to specify different boundary
composition plugins for different fields on different
boundaries. This means that not all fields need to be
prescribed and two prescribed fields can use different
plugins to compute the boundary composition.
<br>
(Anne Glerum 2026/05/11)
36 changes: 20 additions & 16 deletions doc/sphinx/parameters/Boundary_20composition_20model.md

Large diffs are not rendered by default.

92 changes: 89 additions & 3 deletions include/aspect/boundary_composition/interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,57 @@ namespace aspect
bool
allows_fixed_composition_on_outflow_boundaries() const;

/*
* Return whether on the given boundary the given field
* is fixed.
*/
bool
field_is_fixed_on_boundary(const types::boundary_id boundary_id,
const unsigned int compositional_field) const;

/*
* Return whether there are boundaries where only a subset
Comment thread
anne-glerum marked this conversation as resolved.
* of the compositional fields is prescribed. If false,
* either there are no fixed boundary compositions, or all fields
* are fixed on the fixed composition boundaries.
*/
bool
boundaries_with_fixed_subset_of_fields_exist() const;

/*
* Return a list of fields that are fixed on the given boundary.
*/
std::vector<unsigned int>
get_fixed_fields_on_boundary (const types::boundary_id boundary_id) const;
Comment thread
anne-glerum marked this conversation as resolved.

/*
* Return a set of boundary indicators on which the given field
* is fixed.
*/
std::set<types::boundary_id>
get_fixed_boundaries_for_field (const unsigned int compositional_field) const;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We often use "prescribed" instead of "fixed" I think. Think about which one makes more sense?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like prescribed more, but in the prm file and in the original plugin interface, fixed is used, e.g. Fixed composition boundary indicators and fixed_composition_boundary_indicators, so I stuck with that.


/*
* Return the set of compositional fields that are fixed
* for the given plugin name.
*/
std::set<unsigned int>
get_fixed_compositional_fields_for_plugin (const std::string plugin_name) const;

/*
* Return the set of compositional fields that are fixed
* for the given plugin name.
*/
std::set<unsigned int>
get_fixed_compositional_fields_for_plugin_on_boundary (const std::string plugin_name, const types::boundary_id boundary_id) const;

/*
* Return the set of boundary indicators for which fields are fixed
* for the given plugin name.
*/
std::set<types::boundary_id>
get_fixed_composition_boundaries_for_plugin (const std::string plugin_name) const;

/**
* For the current plugin subsystem, write a connection graph of all of the
* plugins we know about, in the format that the
Expand All @@ -235,25 +286,60 @@ namespace aspect
<< arg1
<< "> among the names of registered boundary composition objects.");
private:

/**
* A list of boundary indicators that indicate for
* each plugin in the list of plugin_objects which boundary ids
* it is responsible for. By default each plugin
* is active for all boundaries, but this list
* can be modified from the input file and by
* derived classes to limit the application
* of plugins to specific boundaries.
*/
std::vector <std::vector<types::boundary_id>> boundary_indicators;

/**
* A list of enums of boundary composition operators that have been
* A list of masks that specify for each plugin object
* for each boundary it applies to which compositional fields
* are prescribed (true) and which are not (false).
*/
std::vector <std::vector<ComponentMask>> masks_fields;

/**
* A list of enums of boundary composition operators for each
* boundary indicator associated with a boundary composition plugin that has been
* requested in the parameter file. Each name is associated
* with a model_name, and is used to modify the composition
* boundary with the values from the current plugin.
*/
std::vector<aspect::Utilities::Operator> model_operators;
std::vector <std::vector<aspect::Utilities::Operator>> model_operators;

/**
* A set of boundary ids on which the boundary_composition_objects
* will be applied.
* will be applied. This set does not distinguish between boundaries
* on which only a subset of the fields are fixed and boundaries on
* which all fields are fixed. Any boundary with at least one fixed
* field is included.
*/
std::set<types::boundary_id> fixed_composition_boundary_indicators;

/**
* A set of compositional field numbers that are fixed on any of the
* boundaries, i.e. potentially a subset of n_compositional_fields.
*/
std::set<unsigned int> fixed_compositional_fields;

/**
* Whether we allow the composition to be fixed on parts of the boundary
* where material flows out of the domain.
*/
bool allow_fixed_composition_on_outflow_boundaries;

/**
* Whether one or more boundaries only have fixed boundary conditions
* for a subset of fields, instead of all fields.
*/
bool do_boundaries_with_fixed_subset_of_fields_exist = false;
};


Expand Down
34 changes: 26 additions & 8 deletions source/boundary_composition/ascii_data.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ namespace aspect
void
AsciiData<dim>::initialize ()
{
Utilities::AsciiDataBoundary<dim>::initialize(this->get_fixed_composition_boundary_indicators(),
this->n_compositional_fields());
const unsigned int n_fixed_fields = this->get_boundary_composition_manager().get_fixed_compositional_fields_for_plugin("ascii data").size();
const std::set<types::boundary_id> fixed_boundary_indicators = this->get_boundary_composition_manager().get_fixed_composition_boundaries_for_plugin("ascii data");
Utilities::AsciiDataBoundary<dim>::initialize(fixed_boundary_indicators,
n_fixed_fields);
}


Expand All @@ -59,9 +61,24 @@ namespace aspect
const Point<dim> &position,
const unsigned int compositional_field) const
{
// In case not all fields are fixed on the boundary,
// figure out the right index of the given field.
unsigned int field_id = compositional_field;
if (this->get_boundary_composition_manager().boundaries_with_fixed_subset_of_fields_exist())
{
const std::set<unsigned int> fixed_fields = this->get_boundary_composition_manager().get_fixed_compositional_fields_for_plugin("ascii data");
Assert (fixed_fields.find(compositional_field) != fixed_fields.end(),
ExcMessage ("Boundary composition was requested for field " +
Utilities::int_to_string(compositional_field) +
" on boundary " +
Utilities::int_to_string(boundary_indicator) +
" but this field is not prescribed by the `ascii data` plugin. "));
field_id = std::distance(fixed_fields.begin(), fixed_fields.find(compositional_field));
}

return Utilities::AsciiDataBoundary<dim>::get_data_component(boundary_indicator,
position,
compositional_field);
field_id);
}

template <int dim>
Expand Down Expand Up @@ -109,11 +126,12 @@ namespace aspect
"has to be `x', `composition1', `composition2', "
"etc. in a 2d model and "
"`x', `y', `composition1', `composition2', "
"etc., in a 3d model, according "
"to the number of compositional fields, which means that "
"there has to be a single column "
"for every composition in the model. "
"Note that the data in the input "
"etc., in a 3d model, with a column for each of "
"the compositional fields that are "
"prescribed by this plugin (on all boundaries). "
"This means that there has to be a single column "
"for every composition that is prescribed with `ascii data' "
"in the model. Note that the data in the input "
"files need to be sorted in a specific order: "
"the first coordinate needs to ascend first, "
"followed by the second in order to "
Expand Down
78 changes: 54 additions & 24 deletions source/boundary_composition/box.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,23 @@ namespace aspect
const unsigned int compositional_field) const
{
Assert (boundary_indicator<2*dim, ExcMessage ("The given boundary indicator needs to be less than 2*dimension.."));
return composition_values[boundary_indicator][compositional_field];

// In case not all fields are fixed on the boundary,
// figure out the right index of the given field.
unsigned int field_id = compositional_field;
if (this->get_boundary_composition_manager().boundaries_with_fixed_subset_of_fields_exist())
{
const std::set<unsigned int> fixed_fields = this->get_boundary_composition_manager().get_fixed_compositional_fields_for_plugin_on_boundary("box", boundary_indicator);
Assert (fixed_fields.find(compositional_field) != fixed_fields.end(),
ExcMessage ("Boundary composition was requested for field " +
Utilities::int_to_string(compositional_field) +
" on boundary " +
Utilities::int_to_string(boundary_indicator) +
" but this field is not prescribed by the `box` plugin. "));
field_id = std::distance(fixed_fields.begin(), fixed_fields.find(compositional_field));
}

return composition_values[boundary_indicator][field_id];
}

template <int dim>
Expand All @@ -55,36 +71,42 @@ namespace aspect
Patterns::List(Patterns::Double ()),
"A comma separated list of composition boundary values "
"at the left boundary (at minimal $x$-value). This list must have as many "
"entries as there are compositional fields. Units: none.");
"entries as there are compositional fields prescribed by the plugin on the left boundary. "
"Units: none.");
prm.declare_entry ("Right composition", "",
Patterns::List(Patterns::Double ()),
"A comma separated list of composition boundary values "
"at the right boundary (at maximal $x$-value). This list must have as many "
"entries as there are compositional fields. Units: none.");
"entries as there are compositional fields prescribed by the plugin on the right boundary. "
"Units: none.");
prm.declare_entry ("Bottom composition", "",
Patterns::List(Patterns::Double ()),
"A comma separated list of composition boundary values "
"at the bottom boundary (at minimal $y$-value in 2d, or minimal "
"$z$-value in 3d). This list must have as many "
"entries as there are compositional fields. Units: none.");
"entries as there are compositional fields prescribed by the plugin on the bottom boundary. "
"Units: none.");
prm.declare_entry ("Top composition", "",
Patterns::List(Patterns::Double ()),
"A comma separated list of composition boundary values "
"at the top boundary (at maximal $y$-value in 2d, or maximal "
"$z$-value in 3d). This list must have as many "
"entries as there are compositional fields. Units: none.");
"entries as there are compositional fields prescribed by the plugin on the top boundary. "
"Units: none.");
if (dim==3)
{
prm.declare_entry ("Front composition", "",
Patterns::List(Patterns::Double ()),
"A comma separated list of composition boundary values "
"at the front boundary (at minimum $y$-value). This list must have as many "
"entries as there are compositional fields. Units: none.");
"entries as there are compositional fields prescribed by the plugin on the front boundary. "
"Units: none.");
prm.declare_entry ("Back composition", "",
Patterns::List(Patterns::Double ()),
"A comma separated list of composition boundary values "
"at the back boundary (at maximum $y$-value). This list must have as many "
"entries as there are compositional fields. Units: none.");
"entries as there are compositional fields prescribed by the plugin on the back boundary. "
"Units: none.");
}
}
prm.leave_subsection ();
Expand Down Expand Up @@ -143,24 +165,32 @@ namespace aspect
// Verify that each of the lists for boundary values
// has the requisite number of elements if it is in the set
// of prescribed boundary indicators.
// Not all fields need to be fixed on a given boundary.
for (unsigned int f=0; f<2*dim; ++f)
if (this->get_boundary_composition_manager().get_fixed_composition_boundary_indicators().count(f) != 0)
AssertThrow (composition_values[f].size() == this->n_compositional_fields(),
ExcMessage (std::string("The specification of boundary composition values for the `box' model "
"requires as many values on each face of the box as there are compositional "
"fields. However, for face ")
+
Utilities::int_to_string(f)
+
", the input file specifies "
+
Utilities::int_to_string(composition_values[f].size())
+
" values even though there are "
+
Utilities::int_to_string(this->n_compositional_fields())
+
" compositional fields."));
{
const std::set<types::boundary_id> fixed_boundary_indicators = this->get_boundary_composition_manager().get_fixed_compositional_fields_for_plugin_on_boundary("box",f);
if (fixed_boundary_indicators.count(f) != 0)
AssertThrow (composition_values[f].size() == fixed_boundary_indicators.size(),
ExcMessage (std::string("The specification of boundary composition values for the `box' model "
"requires as many values on each face of the box as there are "
"compositional fields prescribed by the plugin on each face. However, for face ")
+
Utilities::int_to_string(f)
+
", the input file specifies "
+
Utilities::int_to_string(composition_values[f].size())
+
" values even though there are "
+
Utilities::int_to_string(this->n_compositional_fields())
+
" compositional field(s) and "
+
Utilities::int_to_string(fixed_boundary_indicators.size())
+
" compositional field(s) prescribed by the plugin on this face."));
}
}

}
Expand Down
Loading
Loading