libMesh
Loading...
Searching...
No Matches
file_solution_history.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18// libMesh includes
19#include "libmesh/file_solution_history.h"
20#include "libmesh/file_history_data.h"
21#include "libmesh/diff_system.h"
22#include "libmesh/numeric_vector.h"
23
24// C++ includes
25#include <iostream>
26#include <cmath>
27#include <iterator>
28
29namespace libMesh
30{
31
37 : SolutionHistory(), _system(system)
38{
41
42 libmesh_experimental();
43}
44
45
47
48std::unique_ptr<SolutionHistory>
50{
51 return std::make_unique<FileSolutionHistory>(_system);
52}
53
54// This functions writes the solution at the current system time to disk
55void FileSolutionHistory::store(bool is_adjoint_solve, Real time)
56{
57 // This will map the stored_datum iterator to the current time
58 this->find_stored_entry(time, true);
59
60 // In an empty history we create the first entry
61 if (stored_data.begin() == stored_data.end())
62 {
63 stored_data[time] = std::make_unique<FileHistoryData>(_system);
64 stored_datum = stored_data.begin();
65 }
66
67 // If we're past the end we can create a new entry
68 if (time - stored_datum->first > TOLERANCE )
69 {
70#ifndef NDEBUG
73#endif
74 stored_data[time] = std::make_unique<FileHistoryData>(_system);
77 }
78
79 // If we're before the beginning we can create a new entry
80 else if (stored_datum->first - time > TOLERANCE)
81 {
83 stored_data[time] = std::make_unique<FileHistoryData>(_system);
84 stored_datum = stored_data.begin();
85 }
86
87 // We don't support inserting entries elsewhere
88 libmesh_assert(std::abs(stored_datum->first - time) < TOLERANCE);
89
90 // If we are in the primal loop, either reuse an existing timestamp if a write has been done for
91 // this time earlier. Else, we are at a new time and need to make a new entry in the timeTotimestamp map.
92 if(!is_adjoint_solve)
93 {
94 // First we handle the case of the initial data, this is the only case in which
95 // stored_data will have size one
96 if(stored_data.size() == 1)
97 {
98 (stored_datum->second)->store_initial_solution();
99 }
100 else if((stored_datum->second)->get_previously_stored() == false) // If we are not at the initial time, we are either creating a new entry or overwriting an existing one
101 {
102 (stored_datum->second)->store_primal_solution(stored_datum);
103 }
104 else
105 {
106 (stored_datum->second)->rewrite_stored_solution();
107 }
108 }
109 else // We are in the adjoint time stepping loop
110 {
111 (stored_datum->second)->store_adjoint_solution();
112 }
113
114}
115
116void FileSolutionHistory::retrieve(bool is_adjoint_solve, Real time)
117{
118 this->find_stored_entry(time, false);
119
120 // If we are solving the adjoint, the timestep we need to move to the past step
121 // is the one taken at that step to get to the current time.
122 // At the initial time, be ready for the primal time march again.
123 if(is_adjoint_solve)
124 {
125 if( stored_datum != stored_data.begin() )
126 {
127 stored_data_iterator stored_datum_past = stored_datum;
128 stored_datum_past--;
129
130 _system.deltat = (stored_datum_past->second)->get_deltat_at();
131 }
132 else
133 {
134 _system.deltat = (stored_datum->second)->get_deltat_at();
135 }
136 }
137 else
138 {
139 if( stored_datum != std::prev(stored_data.end()) )
140 _system.deltat = (stored_datum->second)->get_deltat_at();
141 else
142 {
143 stored_data_iterator stored_datum_past = stored_datum;
144 stored_datum_past--;
145
146 _system.deltat = (stored_datum_past->second)->get_deltat_at();
147 }
148
149 }
150
151 // Get the time at which we are recovering the solution vectors
152 Real recovery_time = stored_datum->first;
153
154 // Do we not have a solution for this time? Then
155 // there's nothing to do.
156 if (stored_datum == stored_data.end() ||
157 std::abs(recovery_time - time) > TOLERANCE)
158 {
159 //libMesh::out << "No more solutions to recover ! We are at time t = " <<
160 // _system.time << std::endl;
161 return;
162 }
163
164
165 // If we are doing an adjoint solve, we read in the primal solution,
166 // but this overwrites the adjoint solution with zero, so we swap
167 // the last adjoint solution out to prevent this zeroing
168 if(is_adjoint_solve)
169 {
170 // Reading in the primal xdas overwrites the adjoint solution with zero
171 // So swap to retain the adjoint and old adjoint vectors
172 for (auto j : make_range(_system.n_qois()))
173 {
175
176 std::string old_adjoint_solution_name = "_old_adjoint_solution";
177 old_adjoint_solution_name+= std::to_string(j);
178 old_dual_solution_copies[j] = _system.get_vector(old_adjoint_solution_name).clone();
179 }
180
181 // Read in the primal solution stored at the current recovery time from the disk
182 (stored_datum->second)->retrieve_primal_solution();
183
184 // Swap back the copy of adjoint and old adjoint vectors back in place
185 for (auto j : make_range(_system.n_qois()))
186 {
188
189 std::string old_adjoint_solution_name = "_old_adjoint_solution";
190 old_adjoint_solution_name+= std::to_string(j);
191 (_system.get_vector(old_adjoint_solution_name)).swap(*old_dual_solution_copies[j]);
192 }
193 }
194 else
195 {
196 // // If we are not in the adjoint loop, we could be in the primal loop again having solved
197 // // only the primal problem, or in a primal postprocessing stage to evaluate a QoI for example.
198 // // If we can find an adjoint solution file, read that in, else read in the primal file
199 if(dynamic_cast<FileHistoryData &>(*(stored_datum->second)).get_adjoint_filename().empty())
200 (stored_datum->second)->retrieve_primal_solution();
201 else
202 (stored_datum->second)->retrieve_adjoint_solution();
203 }
204
205 // We need to call update to put system in a consistent state
206 // with the solution that was read in
207 _system.update();
208
209}
210
211}
212// End namespace libMesh
This class provides a specific system class.
Definition diff_system.h:57
Real deltat
For time-dependent problems, this is the amount delta t to advance the solution in time.
HistoryData subclass that provides a struct to store history data such as timestamps,...
std::string & get_adjoint_filename()
virtual void retrieve(bool is_adjoint_solve, Real time) override
Virtual function retrieve which we will be overriding to retrieve timesteps.
virtual void store(bool is_adjoint_solve, Real time) override
Virtual function store which we will be overriding to store timesteps.
virtual std::unique_ptr< SolutionHistory > clone() const override
Definition of the clone function needed for the setter function.
std::vector< std::unique_ptr< NumericVector< Number > > > dual_solution_copies
A vector of pointers to adjoint and old adjoint solutions at the last time step.
std::vector< std::unique_ptr< NumericVector< Number > > > old_dual_solution_copies
FileSolutionHistory(DifferentiableSystem &system)
Constructor, reference to system to be passed by user, set the stored_sols iterator to some initial v...
~FileSolutionHistory()
Destructor, defaulted out-of-line.
virtual std::unique_ptr< NumericVector< T > > clone() const =0
A SolutionHistory class that enables the storage and retrieval of timesteps and (in the future) adapt...
void find_stored_entry(Real time, bool storing=false)
map_type::iterator stored_data_iterator
stored_data_iterator stored_datum
unsigned int n_qois() const
Number of currently active quantities of interest.
Definition system.h:2562
virtual void update()
Update the local values to reflect the solution on neighboring processors.
Definition system.C:498
NumericVector< Number > & get_adjoint_solution(unsigned int i=0)
Definition system.C:1232
const NumericVector< Number > & get_vector(std::string_view vec_name) const
Definition system.C:931
The libMesh namespace provides an interface to certain functionality in the library.
libmesh_assert(ctx)
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition int_range.h:176