PLaSK library

Loading...
Searching...
No Matches
solver.hpp
Go to the documentation of this file.
1/*
2 * This file is part of PLaSK (https://plask.app) by Photonics Group at TUL
3 * Copyright (c) 2022 Lodz University of Technology
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program 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
12 * GNU General Public License for more details.
13 */
14#ifndef PLASK__SOLVER_H
15#define PLASK__SOLVER_H
16
507#include <string>
508
509#include "log/log.hpp"
510#include "log/data.hpp"
511#include "mesh/mesh.hpp"
512#include "geometry/space.hpp"
513#include "geometry/reader.hpp"
514#include "manager.hpp"
515
516 namespace plask {
517
518 struct Manager;
519
525 class PLASK_API Solver {
526
528 std::string solver_name;
529
530 protected:
531
533 bool initialized;
534
540 virtual void onInitialize() {}
541
548 virtual void onInvalidate() {}
549
550 public:
551
557 bool initCalculation();
558
563 Solver(const std::string& name=""): solver_name(name), initialized(false) {}
564
566 virtual ~Solver() {}
567
577 virtual void loadConfiguration(XMLReader& source, Manager& manager);
578
589 void parseStandardConfiguration(XMLReader& source, Manager& manager, const std::string& expected_msg="solver configuration element");
590
595 bool isInitialized() { return initialized; }
596
603 void invalidate() {
604 if (initialized) {
605 initialized = false;
606 writelog(LOG_INFO, "Invalidating solver");
607 onInvalidate();
608 }
609 }
610
615 virtual std::string getClassName() const = 0;
616
621 inline std::string getId() const {
622 std::string name = "";
623 if (solver_name != "") {
624 name += solver_name; name += ":";
625 }
626 return name + getClassName();
627 }
628
630 inline std::string getName() const { return solver_name; }
631
636 virtual std::string getClassDescription() const { return ""; }
637
638 template<typename ArgT = double, typename ValT = double>
639 DataLog<ArgT, ValT> dataLog(const std::string& chart_name, const std::string& axis_arg_name, const std::string& axis_val_name) {
640 return DataLog<ArgT, ValT>(getId(), chart_name, axis_arg_name, axis_val_name);
641 }
642
643
644 template<typename ArgT = double, typename ValT = double>
645 DataLog<ArgT, ValT> dataLog(const std::string& axis_arg_name, const std::string& axis_val_name) {
646 return DataLog<ArgT, ValT>(getId(), axis_arg_name, axis_val_name);
647 }
648
655 template<typename ...Args>
656 void writelog(LogLevel level, std::string msg, Args&&... params) const { plask::writelog(level, getId() + ": " + msg, std::forward<Args>(params)...); }
657
658 //virtual shared_ptr<const Geometry> getUsedGeometry() const; //return empty by default
659 //virtual shared_ptr<const Mesh> getUsedMesh() const;
660
661};
662
663/*
664 * Function constructing solver on library loadConfiguration
665 */
666#define SOLVER_CONSTRUCT_FUNCTION_SUFFIX "_solver_factory"
667 extern "C" typedef Solver* solver_construct_f(const std::string& name);
668
669
670 template <typename, typename> struct SolverWithMesh;
671
675 template <typename SpaceT>
676 class SolverOver: public Solver {
677
678 void diconnectGeometry() {
679 if (this->geometry)
680 this->geometry->changedDisconnectMethod(this, &SolverOver<SpaceT>::onGeometryChange);
681 }
682
683 protected:
684
686 shared_ptr<SpaceT> geometry;
687
694 template <typename Boundary, typename ConditionT>
695 void readBoundaryConditions(Manager& manager, XMLReader& reader, BoundaryConditions<Boundary, ConditionT>& dest) {
696 manager.readBoundaryConditions<Boundary, ConditionT>(reader, dest);
697 }
698
699 public:
700
702 typedef SpaceT SpaceType;
703
704 SolverOver(const std::string& name="") : Solver(name) {}
705
706 ~SolverOver() {
707 diconnectGeometry();
708 }
709
710 void loadConfiguration(XMLReader& source, Manager& manager) override;
711
712 void parseStandardConfiguration(XMLReader& source, Manager& manager, const std::string& expected_msg="solver configuration element");
713
719 virtual void onGeometryChange(const Geometry::Event&) {
720 this->invalidate();
721 }
722
727 inline shared_ptr<SpaceT> getGeometry() const { return geometry; }
728
733 void setGeometry(const shared_ptr<SpaceT>& geometry) {
734 if (geometry == this->geometry) return;
735 writelog(LOG_INFO, "Attaching geometry to solver");
736 diconnectGeometry();
737 this->geometry = geometry;
738 if (this->geometry)
739 this->geometry->changedConnectMethod(this, &SolverOver<SpaceT>::onGeometryChange);
740 onGeometryChange(Geometry::Event(geometry.get(), 0));
741 }
742};
743
747 template <typename SpaceT, typename MeshT>
748 struct SolverWithMesh: public SolverOver<SpaceT> {
749
751 typedef MeshT MeshType;
752
753 private:
754
755 shared_ptr<MeshGeneratorD<MeshT::DIM>> mesh_generator;
756
757 void disconnectMesh() {
758 /*if (this->mesh)
759 this->mesh->changedDisconnectMethod(this, &SolverWithMesh<SpaceT, MeshT>::onMeshChange);*/
760 mesh_signal_connection.disconnect();
761 }
762
763 void clearGenerator() {
764 if (this->mesh_generator)
765 this->mesh_generator->changedDisconnectMethod(this, &SolverWithMesh<SpaceT, MeshT>::onGeneratorChange);
766 mesh_generator.reset();
767 }
768
769 void regenerateMesh() {
770 if (this->mesh_generator && this->geometry) {
771 auto mesh = mesh_generator->template get<MeshType>(this->geometry->getChild());
772 if (mesh == this->mesh) return;
773 disconnectMesh();
774 this->mesh = mesh;
775 if (this->mesh)
776 mesh_signal_connection = this->mesh->changedConnectMethod(this, &SolverWithMesh<SpaceT, MeshT>::onMeshChange);
777 onMeshChange(typename MeshT::Event(mesh.get(), 0));
778 }
779 }
780
785 void onGeneratorChange(const typename MeshGenerator::Event&) {
786 regenerateMesh();
787 }
788
789 protected:
790
792 shared_ptr<MeshT> mesh;
793
795 boost::signals2::connection mesh_signal_connection;
796
797 public:
798
799 SolverWithMesh(const std::string& name="") : SolverOver<SpaceT>(name) {}
800
801 ~SolverWithMesh() {
802 disconnectMesh();
803 clearGenerator();
804 }
805
806 void loadConfiguration(XMLReader& source, Manager& manager) override;
807
808 void parseStandardConfiguration(XMLReader& source, Manager& manager, const std::string& expected_msg="solver configuration element");
809
815 virtual void onMeshChange(const typename MeshT::Event& PLASK_UNUSED(evt)) {
816 this->invalidate();
817 }
818
826 void onGeometryChange(const Geometry::Event& PLASK_UNUSED(evt)) override {
827 this->invalidate();
828 this->regenerateMesh();
829 }
830
837 inline MeshT& meshRef() const { return *mesh; }
838
843 inline shared_ptr<MeshT> getMesh() const { return mesh; }
844
849 void setMesh(const shared_ptr<MeshT>& mesh) {
850 clearGenerator();
851 if (mesh == this->mesh) return;
852 this->writelog(LOG_INFO, "Attaching mesh to solver");
853 disconnectMesh();
854 this->mesh = mesh;
855 if (this->mesh)
856 mesh_signal_connection = this->mesh->changedConnectMethod(this, &SolverWithMesh<SpaceT, MeshT>::onMeshChange);
857 onMeshChange(typename MeshT::Event(mesh.get(), 0));
858 }
859
864 void setMesh(shared_ptr<MeshGeneratorD<MeshT::DIM>> generator) {
865 clearGenerator();
866 this->writelog(LOG_INFO, "Attaching mesh generator to solver");
867 mesh_generator = generator;
868 if (mesh_generator)
869 mesh_generator->changedConnectMethod(this, &SolverWithMesh<SpaceT, MeshT>::onGeneratorChange);
870 regenerateMesh();
871 }
872};
873
874} //namespace plask
875
876#include "manager.hpp" // Just in case module author includes only "solver.hpp"
877
878 namespace plask {
879
880 template <typename SpaceT>
881 void SolverOver<SpaceT>::loadConfiguration(XMLReader& reader, Manager& manager) {
882 while (reader.requireTagOrEnd()) parseStandardConfiguration(reader, manager, "<geometry>");
883}
884
885 template <typename SpaceT, typename MeshT>
886 void SolverWithMesh<SpaceT, MeshT>::loadConfiguration(XMLReader& reader, Manager& manager) {
887 while (reader.requireTagOrEnd()) parseStandardConfiguration(reader, manager, "<geometry> or <mesh>");
888}
889
890
891 template <typename SpaceT>
892 void SolverOver<SpaceT>::parseStandardConfiguration(XMLReader& reader, Manager& manager, const std::string& expected_msg) {
893 if (reader.getNodeName() == "geometry") {
894 auto name = reader.getAttribute("ref");
895 if (!name) name.reset(reader.requireTextInCurrentTag());
896 else reader.requireTagEnd();
897 auto found = manager.geometrics.find(*name);
898 if (found == manager.geometrics.end())
899 throw BadInput(this->getId(), "geometry '{0}' not found", *name);
900 else {
901 auto geometry = dynamic_pointer_cast<SpaceT>(found->second);
902 if (!geometry) throw BadInput(this->getId(), "geometry '{0}' of wrong type", *name);
903 this->setGeometry(geometry);
904 }
905 } else {
906 Solver::parseStandardConfiguration(reader, manager, expected_msg);
907 }
908}
909
910 template <typename SpaceT, typename MeshT>
911 void SolverWithMesh<SpaceT, MeshT>::parseStandardConfiguration(XMLReader& reader, Manager& manager, const std::string& expected_msg) {
912 if (reader.getNodeName() == "mesh") {
913 auto name = reader.getAttribute("ref");
914 if (!name) name.reset(reader.requireTextInCurrentTag());
915 else reader.requireTagEnd();
916 auto found = manager.meshes.find(*name);
917 if (found != manager.meshes.end()) {
918 if (shared_ptr<MeshT> mesh = dynamic_pointer_cast<MeshT>(found->second)) {
919 this->setMesh(mesh);
920 } else {
921 auto generator = dynamic_pointer_cast<MeshGeneratorD<MeshT::DIM>>(found->second);
922 if (!generator) throw BadInput(this->getId(), "mesh or generator '{0}' of wrong type", *name);
923 this->setMesh(generator);
924 }
925 }
926 } else {
927 SolverOver<SpaceT>::parseStandardConfiguration(reader, manager, expected_msg);
928 }
929}
930
931} // namespace plask
932
933#endif // PLASK__SOLVER_H