module; #include #include #include #include #include #include #include #include #include #include #include #include export module mean_field:solver.stellar_structure; export import :operators.stellar_equilibrium_problem; export import :solver.stellar_equilibrium_types; export namespace mean_field::solver { template class StellarEquilibriumEvaluationReport; } namespace mean_field::solver::detail { enum class StellarViewCertification : std::uint8_t { unavailable, checkpoint, structure }; template struct StellarStructureStorage final { using ProblemType = std::remove_cvref_t; StellarStructureStorage( std::unique_ptr ownedProblem, std::unique_ptr acceptedPhysicalState, std::unique_ptr prescribedRotation ) : problem(std::move(ownedProblem)), physicalState(std::move(acceptedPhysicalState)), rotation(std::move(prescribedRotation)) { } std::unique_ptr problem; std::unique_ptr physicalState; std::unique_ptr rotation; std::uint64_t viewGeneration{0}; StellarViewCertification certification{StellarViewCertification::unavailable}; }; template [[nodiscard]] bool IsCurrentView( const std::weak_ptr> &candidate, const std::uint64_t generation, const bool requireConverged ) noexcept { const auto storage = candidate.lock(); if (storage == nullptr || storage->problem == nullptr || storage->physicalState == nullptr || storage->viewGeneration != generation) { return false; } if (requireConverged) { return storage->certification == StellarViewCertification::structure; } return storage->certification == StellarViewCertification::checkpoint || storage->certification == StellarViewCertification::structure; } template [[nodiscard]] std::shared_ptr> RequireCurrentView( const std::weak_ptr> &candidate, const std::uint64_t generation, const bool requireConverged ) { auto storage = candidate.lock(); if (storage == nullptr || storage->problem == nullptr || storage->physicalState == nullptr || storage->viewGeneration != generation || (requireConverged && storage->certification != StellarViewCertification::structure) || (!requireConverged && storage->certification != StellarViewCertification::checkpoint && storage->certification != StellarViewCertification::structure)) { throw std::logic_error("The stellar structure view is stale or is not certified for this result."); } return storage; } template [[nodiscard]] std::span ReadOnlySpan(const Vector &values) noexcept { return {values.GetData(), static_cast(values.Size())}; } template struct StellarEvaluationReportAccess; } // namespace mean_field::solver::detail export namespace mean_field::equilibrium { /* * These are the future owning, self-contained values. There is no public * construction path until deep capture and its MPI-independent storage * schema are implemented. */ template class StellarStructure final { public: using ProblemType = std::remove_cvref_t; StellarStructure(const StellarStructure &) = delete; StellarStructure &operator=(const StellarStructure &) = delete; StellarStructure(StellarStructure &&) noexcept = default; StellarStructure &operator=(StellarStructure &&) = delete; ~StellarStructure() = default; private: StellarStructure() = default; }; template class StellarCheckpoint final { public: using ProblemType = std::remove_cvref_t; StellarCheckpoint(const StellarCheckpoint &) = delete; StellarCheckpoint &operator=(const StellarCheckpoint &) = delete; StellarCheckpoint(StellarCheckpoint &&) noexcept = default; StellarCheckpoint &operator=(StellarCheckpoint &&) = delete; ~StellarCheckpoint() = default; private: StellarCheckpoint() = default; }; /* * Result views weakly observe context-owned storage. valid() remains safe * after that context is destroyed. References and spans extracted from a * valid view remain borrowed: the context must outlive their use, and the * next evaluate() call invalidates them along with their originating view. */ template class StellarStructureView final { public: using ProblemType = std::remove_cvref_t; using ModelType = typename ProblemType::ModelType; [[nodiscard]] bool valid() const noexcept { return solver::detail::IsCurrentView(m_storage, m_generation, true); } [[nodiscard]] const ModelType &model() const & { const auto storage = RequireStorage(); return storage->problem->GetStellarModel(); } [[nodiscard]] const ModelType &model() const && = delete; [[nodiscard]] MPI_Comm communicator() const & { const auto storage = RequireStorage(); return storage->problem->GetCommunicator(); } [[nodiscard]] MPI_Comm communicator() const && = delete; [[nodiscard]] std::span state() const & { const auto storage = RequireStorage(); return solver::detail::ReadOnlySpan(*storage->physicalState); } [[nodiscard]] std::span state() const && = delete; [[nodiscard]] std::span stateDescriptors() const & { const auto storage = RequireStorage(); return storage->problem->GetManifest().valueBlocks(); } [[nodiscard]] std::span stateDescriptors() const && = delete; template requires requires( const typename ProblemType::ManifestType &manifest, const mfem::Vector &physicalState, const Term &term ) { manifest.stateView(physicalState).block(term); } [[nodiscard]] std::span stateBlock(const Term &term) const & { const auto storage = RequireStorage(); const auto block = storage->problem->GetManifest().stateView(*storage->physicalState).block(term); return solver::detail::ReadOnlySpan(block); } template [[nodiscard]] std::span stateBlock(const Term &) const && = delete; [[nodiscard]] std::optional prescribedRotation() const & { const auto storage = RequireStorage(); if (storage->rotation == nullptr) { return std::nullopt; } return *storage->rotation; } [[nodiscard]] std::optional prescribedRotation() const && = delete; [[nodiscard]] physics::RigidRotation rotation() const & { const auto storage = RequireStorage(); return storage->problem->GetPreparedOperator().GetRotation(); } [[nodiscard]] physics::RigidRotation rotation() const && = delete; [[nodiscard]] StellarStructure capture() const { (void)RequireStorage(); throw std::logic_error("Capturing a self-contained StellarStructure is not implemented."); } private: template friend class solver::StellarEquilibriumEvaluationReport; using Storage = solver::detail::StellarStructureStorage; StellarStructureView( std::weak_ptr storage, const std::uint64_t generation ) noexcept : m_storage(std::move(storage)), m_generation(generation) { } [[nodiscard]] std::shared_ptr RequireStorage() const { return solver::detail::RequireCurrentView(m_storage, m_generation, true); } std::weak_ptr m_storage; std::uint64_t m_generation; }; template class StellarCheckpointView final { public: using ProblemType = std::remove_cvref_t; using ModelType = typename ProblemType::ModelType; [[nodiscard]] bool valid() const noexcept { return solver::detail::IsCurrentView(m_storage, m_generation, false); } [[nodiscard]] const ModelType &model() const & { const auto storage = RequireStorage(); return storage->problem->GetStellarModel(); } [[nodiscard]] const ModelType &model() const && = delete; [[nodiscard]] MPI_Comm communicator() const & { const auto storage = RequireStorage(); return storage->problem->GetCommunicator(); } [[nodiscard]] MPI_Comm communicator() const && = delete; [[nodiscard]] std::span state() const & { const auto storage = RequireStorage(); return solver::detail::ReadOnlySpan(*storage->physicalState); } [[nodiscard]] std::span state() const && = delete; [[nodiscard]] std::span stateDescriptors() const & { const auto storage = RequireStorage(); return storage->problem->GetManifest().valueBlocks(); } [[nodiscard]] std::span stateDescriptors() const && = delete; template requires requires( const typename ProblemType::ManifestType &manifest, const mfem::Vector &physicalState, const Term &term ) { manifest.stateView(physicalState).block(term); } [[nodiscard]] std::span stateBlock(const Term &term) const & { const auto storage = RequireStorage(); const auto block = storage->problem->GetManifest().stateView(*storage->physicalState).block(term); return solver::detail::ReadOnlySpan(block); } template [[nodiscard]] std::span stateBlock(const Term &) const && = delete; [[nodiscard]] std::optional prescribedRotation() const & { const auto storage = RequireStorage(); if (storage->rotation == nullptr) { return std::nullopt; } return *storage->rotation; } [[nodiscard]] std::optional prescribedRotation() const && = delete; [[nodiscard]] physics::RigidRotation rotation() const & { const auto storage = RequireStorage(); return storage->problem->GetPreparedOperator().GetRotation(); } [[nodiscard]] physics::RigidRotation rotation() const && = delete; [[nodiscard]] StellarCheckpoint capture() const { (void)RequireStorage(); throw std::logic_error("Capturing a self-contained StellarCheckpoint is not implemented."); } private: template friend class solver::StellarEquilibriumEvaluationReport; using Storage = solver::detail::StellarStructureStorage; StellarCheckpointView( std::weak_ptr storage, const std::uint64_t generation ) noexcept : m_storage(std::move(storage)), m_generation(generation) { } [[nodiscard]] std::shared_ptr RequireStorage() const { return solver::detail::RequireCurrentView(m_storage, m_generation, false); } std::weak_ptr m_storage; std::uint64_t m_generation; }; template [[noreturn]] void serialize( const StellarStructure &, const std::filesystem::path & ) { throw std::logic_error("Serializing a StellarStructure is not implemented."); } template [[noreturn]] void serialize( const StellarStructureView &view, const std::filesystem::path & ) { (void)view.state(); throw std::logic_error("Serializing a StellarStructureView is not implemented."); } template [[noreturn]] void serialize( const StellarCheckpoint &, const std::filesystem::path & ) { throw std::logic_error("Serializing a StellarCheckpoint is not implemented."); } template [[noreturn]] void serialize( const StellarCheckpointView &view, const std::filesystem::path & ) { (void)view.state(); throw std::logic_error("Serializing a StellarCheckpointView is not implemented."); } } // namespace mean_field::equilibrium export namespace mean_field::solver { template class StellarEquilibriumEvaluationReport final { public: using ProblemType = std::remove_cvref_t; using StructureView = equilibrium::StellarStructureView; using CheckpointView = equilibrium::StellarCheckpointView; StellarEquilibriumEvaluationReport(const StellarEquilibriumEvaluationReport &) = default; StellarEquilibriumEvaluationReport &operator=(const StellarEquilibriumEvaluationReport &) = default; StellarEquilibriumEvaluationReport(StellarEquilibriumEvaluationReport &&) noexcept = default; StellarEquilibriumEvaluationReport &operator=(StellarEquilibriumEvaluationReport &&) noexcept = default; ~StellarEquilibriumEvaluationReport() = default; [[nodiscard]] bool converged() const noexcept { return m_converged; } [[nodiscard]] const StellarEquilibriumEvaluationDiagnostics &diagnostics() const & noexcept { return m_diagnostics; } [[nodiscard]] const StellarEquilibriumEvaluationDiagnostics &diagnostics() const && = delete; [[nodiscard]] int completedNonlinearIterations() const noexcept { return m_diagnostics.acceptedNonlinearIterations; } [[nodiscard]] double initialResidualNorm() const noexcept { return m_diagnostics.initialResidualNorm; } [[nodiscard]] double finalResidualNorm() const noexcept { return m_diagnostics.finalResidualNorm; } [[nodiscard]] const StellarEquilibriumFailureReport &failure() const & { if (!m_failure.has_value()) { throw std::logic_error("A converged stellar-equilibrium report has no failure record."); } return *m_failure; } [[nodiscard]] const StellarEquilibriumFailureReport &failure() const && = delete; [[nodiscard]] StructureView structureView() const { if (!m_converged) { throw std::logic_error("A failed stellar-equilibrium report cannot certify a structure view."); } StructureView view{m_storage, m_generation}; if (!view.valid()) { throw std::logic_error("The stellar-equilibrium structure view has been invalidated."); } return view; } [[nodiscard]] CheckpointView checkpointView() const { CheckpointView view{m_storage, m_generation}; if (!view.valid()) { throw std::logic_error("The stellar-equilibrium checkpoint view has been invalidated."); } return view; } [[nodiscard]] CheckpointView lastAcceptedCheckpointView() const { return checkpointView(); } private: friend struct detail::StellarEvaluationReportAccess; using Storage = detail::StellarStructureStorage; StellarEquilibriumEvaluationReport( const bool converged, StellarEquilibriumEvaluationDiagnostics diagnostics, std::optional failure, std::weak_ptr storage, const std::uint64_t generation ) : m_converged(converged), m_diagnostics(std::move(diagnostics)), m_failure(std::move(failure)), m_storage(std::move(storage)), m_generation(generation) { } bool m_converged; StellarEquilibriumEvaluationDiagnostics m_diagnostics; std::optional m_failure; std::weak_ptr m_storage; std::uint64_t m_generation; }; } // namespace mean_field::solver namespace mean_field::solver::detail { template struct StellarEvaluationReportAccess final { using ProblemType = std::remove_cvref_t; using Report = StellarEquilibriumEvaluationReport; using Storage = StellarStructureStorage; [[nodiscard]] static Report Success( const std::shared_ptr &storage, StellarEquilibriumEvaluationDiagnostics diagnostics ) { if (storage == nullptr) { throw std::invalid_argument("A stellar-equilibrium report requires owned result storage."); } storage->certification = StellarViewCertification::structure; return Report{true, std::move(diagnostics), std::nullopt, storage, storage->viewGeneration}; } [[nodiscard]] static Report Failure( const std::shared_ptr &storage, StellarEquilibriumEvaluationDiagnostics diagnostics, const StellarEquilibriumFailureReason reason, std::string message ) { if (storage == nullptr) { throw std::invalid_argument("A stellar-equilibrium report requires owned result storage."); } storage->certification = StellarViewCertification::checkpoint; StellarEquilibriumFailureReport failure{ .reason = reason, .message = std::move(message), .completedNonlinearIterations = diagnostics.acceptedNonlinearIterations, .initialResidualNorm = diagnostics.initialResidualNorm, .finalResidualNorm = diagnostics.finalResidualNorm }; return Report{ false, std::move(diagnostics), std::optional{std::move(failure)}, storage, storage->viewGeneration }; } }; } // namespace mean_field::solver::detail