├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── banner.png
├── build
└── Readme.md
├── docs
├── engines.drawio
├── engines.png
├── mesh.drawio
└── mesh.png
├── examples
└── 1dHeatRod
│ └── 1dHeatRod.cpp
└── src
├── Engine.cpp
├── Engine.hpp
├── Engine1D.cpp
├── Engine1D.hpp
├── Engine2D.cpp
├── Engine2D.hpp
├── FDMEngine.hpp
├── Mesh.hpp
├── Mesh1D.hpp
└── Mesh2D.hpp
/.gitignore:
--------------------------------------------------------------------------------
1 | .vs/*
2 | *.pch
3 | *.log
4 | *.tlog
5 | *.obj
6 | *.idb
7 | *.pdb
8 | *.ipch
9 | *.db
10 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.10)
2 | project(QODES)
3 | set(CMAKE_CXX_STANDARD 20)
4 | include_directories(src/)
5 | set(SOURCES examples/1dHeatRod/1dHeatRod.cpp src/Engine1D.cpp src/Engine.cpp)
6 | add_executable(FDM ${SOURCES})
7 |
8 | if(MSVC)
9 | add_compile_options(/W4 /WX)
10 | else()
11 | add_compile_options(-Wall -Wextra -pedantic -Werror)
12 | endif()
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Thomas Thelen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | [](https://www.repostatus.org/#active) []()
4 | [](https://www.codefactor.io/repository/github/thomasthelen/finite-difference-method)
5 |
6 |
7 | # FDM
8 |
9 | FDM is a C++ source library that exposes an engine for running the method of Finite Elements across one dimension. This is mostly a personal exploration of The Finite Difference Method, CUDA, and Python Bindings.
10 |
11 | ## Using
12 |
13 | To use the engine, git clone the repository and include the required headers in your source file. Examples are given in the [examples](examples/) directory.
14 |
15 | ## Building
16 |
17 | To build, run `cmake ..` and `cmake --build .` from the `build/` directory.
18 |
19 | ## Source
20 | The project has a few directories to separate various parts of the project, detailed below
21 |
22 | - `build/`: Contains the build output
23 | - `examples`: Examples of how the library can be used
24 | - `src`: The source code for the engine
25 |
26 | ### Overview
27 |
28 | The `Mesh` struct manages information about the object being simulated over. There's an associated _Mesh_ class for each dimension. For example, one dimensional simulations should use `1DMesh`.
29 |
30 | 
31 |
32 | The `Engine` class parses information from associated mesh and is responsible for encapsulating the routines for the Finite Difference Method.
33 |
34 | 
35 |
36 | ## Creating Simulations
37 |
38 |
39 | A successful simulation will have both a Mesh and an Engine class instantiated.
40 |
41 | The mesh must have the following defined,
42 | ```
43 | mesh.spatial_length = 10;
44 | mesh.spatial_step_size = 1;
45 | mesh.thermal_conductivity = 0.01;
46 | mesh.DirchletBoundaryEquation = BC;
47 | mesh.InitialDistribution = InitialRodDistribution;
48 | ```
49 |
50 | The boundary condition must be a function with the signature
51 |
52 | `double BoundaryCondition(double x, int time)`
53 |
54 | For example,
55 | ```
56 | double BoundaryCondition(double x, int time)
57 | {
58 | return 15*x+t/2;
59 | }
60 | ```
61 |
62 | The initial distribution method provides an interface to defining the temperature along the object and must have a signature of
63 |
64 | `double TempDistribution(double position)`
65 |
66 | For example, a function that defines the temperature as a constant `50` between the boundary points...
67 |
68 | ```
69 | double TempDistribution(double position) {
70 | return 10;
71 | }
72 | ```
73 |
74 | To run, call `StartSimulation` on the engine object and pass it the mesh object.
75 | ```
76 | Engine engine;
77 | engine.StartSimulation(int time_length, int time_step, Mesh1D& mesh);
78 | ```
--------------------------------------------------------------------------------
/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThomasThelen/Finite-Difference-Method/35c377038d0bc7cc311f31213bb0841681d9c411/banner.png
--------------------------------------------------------------------------------
/build/Readme.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThomasThelen/Finite-Difference-Method/35c377038d0bc7cc311f31213bb0841681d9c411/build/Readme.md
--------------------------------------------------------------------------------
/docs/engines.drawio:
--------------------------------------------------------------------------------
1 | 7VbBbptAEP0ajqmAtZF7re2kqlrlYLV1jxsYw7YLQ5bBgL++iz0YkIWVSFGiSDmZefOGnXlvNdgRy7S+MzJPfmAE2vHdqHbEyvF9z10E9qdFmhOycBmIjYqY1AMbdYCuktFSRVCMiISoSeVjMMQsg5BGmDQGqzFth3p8ai5juAA2odSX6G8VUcJTzN0e/woqTrqTPZczqezIDBSJjLAaQGLtiKVBpNNTWi9Bt+J1upzqbiey58YMZPSUgttt5X17kI936a9DVfzcFof7m5s590ZNNzBEdn4O0VCCMWZSr3v0i8Eyi6B9q2ujnvMdMbegZ8G/QNSwmbIktFBCqeYs1Iq2bfmnOUd/BplVzW8+Bg0Hpz7b5ibHZ6jA0oRwZWafr5E0MdAVnjibZG83YApkGltnQEtS+3Efkq9ZfOb1TtgHNuMZxgQfxkzyZm9pDDe5l7rkk9ZZrDK48Kt3oxWwShTBJpdHASq7K8fK75TWS9RojrUikrDYhRYvyOA/GGSCcAEPu7PuezAE9XXlL5XiAvGZVxPvZi/guOo3ndetr2Sw5Trei4srJsT1Vu9RXn8sr/32vbG8swl5/fco7yx4PXlt2H+oj7nB3x2x/g8=
--------------------------------------------------------------------------------
/docs/engines.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThomasThelen/Finite-Difference-Method/35c377038d0bc7cc311f31213bb0841681d9c411/docs/engines.png
--------------------------------------------------------------------------------
/docs/mesh.drawio:
--------------------------------------------------------------------------------
1 | 7VZRb5swEP41PG4CHFD6WpJ2D+1eMmnboxdfwYvhmDkC7NfPJEcApYk6aWpVaU/4vruz777POuOJJG/vrSyzR1RgvNBXrSdWXhgG/jJ2nx7pjsjSZyC1WnHQCGz0bxgyGa21gmoWSIiGdDkHt1gUsKUZJq3FZh72hGZ+ailTOAM2W2nO0a9aUcZdRP6IfwKdZsPJgc+eXA7BDFSZVNhMILH2RGIR6bjK2wRMT97AyzHv7oL3VJiFgl6S0NDnjbhN6wS/PNyL3S9R3uw+8C4VdUPDoFz/bKKlDFMspFmP6K3FulDQ7+o7a4x5QCwdGDjwJxB1LKasCR2UUW7YC62mb336x4it7xPPquWdD0bHxrHOvriL7Q+9YG23cKVnwddI2hToStziJJK73YA5kO1cngUjSe/ndUi+ZukpblTCLViMvxAm/C/MxbjoLYXhIvfS1HzSI1TZmVqjFj19TaYJNqU8tN+4STnn/Ukbk6BBe8gVKoKlWji8Ios7mHiW4Q8RxyfW92AJ2uu8n/PECeKGBxNP5iBmuxnnXDAMr2wy44a4f07t4llqg9V7JDeck+vevTcmN3qW3PA9kruIX49cZ45P9ME3+dER6z8=
--------------------------------------------------------------------------------
/docs/mesh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ThomasThelen/Finite-Difference-Method/35c377038d0bc7cc311f31213bb0841681d9c411/docs/mesh.png
--------------------------------------------------------------------------------
/examples/1dHeatRod/1dHeatRod.cpp:
--------------------------------------------------------------------------------
1 | // 1dHeatRod.cpp : Simulation of heat flowing in a one dimensional rod with a time & position dependant boundary condition.
2 |
3 | #include "../../src/Engine1D.hpp"
4 | #include "../../src/Mesh1D.hpp"
5 |
6 | // A boundary condition that varies in space and time
7 | double BC(double x, int time)
8 | {
9 | return .2+x * (time +.1);
10 | }
11 |
12 | // A function that defines the initial temperature at some x position. Used to
13 | // populate the initial conditions on the rod (everything inbetween the boundaries)
14 | double TempDistribution(double position) {
15 | return position + 1;
16 | }
17 |
18 | int main()
19 | {
20 | // Create a 1 dimensional mesh with
21 | // Length: 10 meters
22 | // Step size: 1 meter
23 | // Thermal Conductivity: 0.01
24 | Mesh1D mesh;
25 | mesh.x_length = 10;
26 | mesh.spatial_step_size = 1;
27 | mesh.thermal_conductivity = 0.01;
28 | mesh.DirchletBoundaryEquation = BC;
29 | mesh.InitialDistribution = TempDistribution;
30 | // Create the engine
31 | Engine1D engine;
32 |
33 | // Start the simulation using the mesh above
34 | engine.StartSimulation(10, 1, mesh);
35 | return 0;
36 | }
--------------------------------------------------------------------------------
/src/Engine.cpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Engine.hpp"
3 |
4 | void Engine::CreateTime()
5 | {
6 | cout << "Creating time domain..." << endl;
7 | times.push_back(0);
8 | while (times.back() < time_length)
9 | {
10 | times.push_back(times.back() + time_step);
11 | }
12 | cout << "Time Created" << endl;
13 | }
14 |
15 | tuple Engine::GetRecordb(int state_position, int record_position) const
16 | {
17 | vector> state;
18 | tuple record;
19 | state = results.at(state_position);
20 | record = state.at(record_position);
21 | return record;
22 | }
--------------------------------------------------------------------------------
/src/Engine.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Mesh.hpp"
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | using std::vector;
10 | using std::tuple;
11 | using std::cout;
12 | using std::endl;
13 | using std::get;
14 |
15 | /*! \class Engine
16 | * \A base class for solution engines
17 | * Contains basic information that's used across n-dimensional solvers.
18 | */
19 |
20 | class Engine
21 | {
22 | public:
23 | size_t number_of_states;
24 |
25 | double time_length;
26 |
27 | double time_step;
28 |
29 | double initial_temperature = 0;
30 |
31 | double last_temperature = 0;
32 |
33 | // CHANGE NAME
34 | vector times;
35 |
36 | //Contains the position and Temperature data at a specific time.
37 | vector> current_configuration;
38 |
39 | // Contains all of the configurations over time.
40 | vector< vector>> results;
41 |
42 | // !Initiates the simulation
43 |
44 | // !Fills the first element of results with the initial state.
45 | void CreateInitialState(Mesh&);
46 | // !Create a csv file with the simulation results.
47 | // !This is the FTCS numerical approximation.
48 | // !Retrieve a temperature at a given state and node from the results vector.
49 | //virtual void CreateMesh(Mesh&);
50 | // !Retrieves a record from the results vector
51 | tuple GetRecordb(int, int) const;
52 | // !Retrieves a temperature in the forward or backward position.
53 | void CreateTime();
54 | };
--------------------------------------------------------------------------------
/src/Engine1D.cpp:
--------------------------------------------------------------------------------
1 | #include "Engine1D.hpp"
2 |
3 | double Engine1D::GetPreviousTemperature(int current_state, int node_location, char direction)
4 | {
5 | // Check if we're checking the value at the next node location
6 | if (direction == 'f')
7 | {
8 | return RetrieveTemperature(current_state - 1, node_location + 1);
9 | }
10 | // Check if we're going back one node length
11 | if (direction == 'b')
12 | {
13 | return RetrieveTemperature(current_state - 1, node_location - 1);
14 | }
15 | // Check if we're at the current node
16 | if (direction == 'n')
17 | {
18 | return RetrieveTemperature(current_state - 1, node_location);
19 | }
20 | else
21 | {
22 | cout << "Error Obtaining Temperature" << endl;
23 | return 0;
24 | }
25 | }
26 |
27 | void Engine1D::StartSimulation(int time_length, int time_step, Mesh1D& mesh)
28 | {
29 | this->time_length = time_length;
30 | this->time_step = time_step;
31 | number_of_states = static_cast(time_length / time_step);
32 | CreateMesh(mesh);
33 | CreateTime();
34 | CreateInitialState(mesh);
35 | Solve(mesh);
36 | }
37 |
38 | void Engine1D::CreateInitialState(Mesh1D& mesh)
39 | {
40 | // !Place first initial condition
41 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.front(), mesh.DirchletBoundaryEquation(0, 1)));
42 | // !Iterate over the nodes which are not boundary conditions. (starts at node 1 and stops at # of nodes-1
43 | for (auto j = 1; j <= mesh.number_of_nodes - 1; ++j)
44 | {
45 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.at(j), mesh.InitialDistribution(0)));
46 | }
47 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.back(), mesh.DirchletBoundaryEquation(0, 2))); // Once filled, set the last B.C.
48 | results.push_back(current_configuration); // Add to the vector of states
49 | current_configuration.clear(); // Clear the current state
50 | }
51 | void Engine1D::CreateMesh(Mesh1D& mesh)
52 | {
53 | mesh.number_of_nodes = static_cast((mesh.x_length / mesh.spatial_step_size));
54 | cout << "Computing the localtions for all of the nodes (points where calculations are made)" << endl;
55 | mesh.all_node_locations.push_back(0);
56 |
57 | //Store the location of each node
58 | for (int i = 0; i < mesh.number_of_nodes; i++)
59 | {
60 | mesh.all_node_locations.push_back(mesh.all_node_locations.back() + mesh.spatial_step_size);
61 | }
62 | cout << "Mesh Created" << endl;
63 | }
64 | void Engine1D::Solve(Mesh1D& mesh)
65 | {
66 | if ((mesh.thermal_conductivity * time_step) / (mesh.spatial_step_size * mesh.spatial_step_size) > 0.5)
67 | {
68 | cout << endl << endl;
69 | cout << "Under the current configuration, unstale results may occur." << endl;
70 | cout << "To Ensure convergence, please satisfy the following equation." << endl;
71 | cout << "0.5<(thermal_conductivity*time_step)/(spatial_step_size^2)" << endl;
72 | cout << endl;
73 | cout << "This can be achieved by modifying any of the following:" << endl;
74 | cout << " -thermal_conductivity" << endl;
75 | cout << " -time_step" << endl;
76 | cout << " -spatial_step_size" << endl;
77 | cout << endl;
78 | cout << " It is currently at " << (mesh.thermal_conductivity * time_step) / (mesh.spatial_step_size * mesh.spatial_step_size) << endl;
79 | }
80 |
81 | vector temperature;
82 | temperature.reserve(number_of_states);
83 | double constants = (mesh.thermal_conductivity * time_step) / (mesh.spatial_step_size * mesh.spatial_step_size);
84 | int current_node = 1; // Always start at 1; 0 is set by the boundary condition
85 |
86 | int state_location = 1; // Always start at state 1; 0 is set by the intitial condition
87 |
88 | for (double i = 0; i <= number_of_states; i++) // Iterate over time. Start at 0 because the time step may be < or > 1
89 | {
90 | cout << i << endl;
91 | temperature.push_back(mesh.DirchletBoundaryEquation(i, 1)); //Set the boundary condition
92 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.at(0), temperature.front())); // Set the boundary condition
93 | for (int j = 1; j < mesh.number_of_nodes; ++j) // Start at the 2nd node (first is set above by the bountary condition)
94 | {
95 | cout << GetPreviousTemperature(state_location, current_node, 'f') << " + " << (1 - 2 * constants) * GetPreviousTemperature(state_location, current_node, 'n') << " +" << GetPreviousTemperature(state_location, current_node, 'b') * constants << endl;
96 | double new_temp = constants * GetPreviousTemperature(state_location, current_node, 'f') + (1 - 2 * constants) * GetPreviousTemperature(state_location, current_node, 'n') + GetPreviousTemperature(state_location, current_node, 'b') * constants; // Get the temperature at the current node #; passes the current state.
97 | temperature.push_back(new_temp);
98 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.at(current_node), temperature.at(current_node))); // Use current_node to access the approriate physical node location.
99 | ++current_node;
100 | }
101 | ++state_location;
102 | temperature.push_back(mesh.DirchletBoundaryEquation(i, 2));
103 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.at(current_node), 0));
104 | cout << endl << endl << endl << endl << endl;
105 | current_node = 1;
106 | results.push_back(current_configuration); // Push the current state configuration vector into the results vector.
107 | current_configuration.clear(); // Prepare for the next configuration by clearing the current one
108 | temperature.clear(); // Clear the temperature vector
109 | }
110 | CreateCSV(mesh);
111 | }
112 | void Engine1D::CreateCSV(Mesh1D mesh)
113 | {
114 | std::ofstream dataFile;
115 | dataFile.open("Results.csv");
116 | tuple record;
117 | //Iterate records with GetRecord
118 |
119 | for (int i = 0; i < number_of_states; i++)
120 | {
121 | for (int j = 0; j < mesh.all_node_locations.size(); j++)
122 | {
123 | record = GetRecordb(i, j);
124 | dataFile << get<0>(record) << "," << get<1>(record) << endl;
125 | }
126 | }
127 | dataFile.close();
128 | }
129 | double Engine1D::RetrieveTemperature(int state_position, int record_position)
130 | {
131 | vector> state;
132 | tuple record;
133 | state = results.at(state_position);
134 | record = state.at(record_position);
135 | return get<1>(record);
136 | }
--------------------------------------------------------------------------------
/src/Engine1D.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Engine.hpp"
3 | #include "Mesh1D.hpp"
4 |
5 | class Engine1D : public Engine
6 | {
7 | public:
8 | /*! Starts the simulation.
9 | @arg Mesh1D The one-dimensional mesh that will be used during the simulation
10 | */
11 | void StartSimulation(int time_length, int time_step, Mesh1D& mesh);
12 |
13 |
14 | /*! Fills in important properties for the mesh.
15 | @arg Mesh1D An empty mesh object whose are going to be set by CreateMesh
16 |
17 | */
18 | void CreateMesh(Mesh1D&);
19 |
20 |
21 | /*! Creates the initial state of the experiment
22 | @arg Mesh1D
23 |
24 | */
25 | void CreateInitialState(Mesh1D&);
26 |
27 | void CreateCSV(Mesh1D);
28 |
29 | void Solve(Mesh1D&);
30 |
31 | double RetrieveTemperature(int, int);
32 |
33 | double GetPreviousTemperature(int, int, char);
34 | };
35 |
--------------------------------------------------------------------------------
/src/Engine2D.cpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Engine2D.hpp"
3 |
4 | void Engine2D::CreateInitialState(Mesh2D &mesh)
5 | {
6 | vector>> instance_container;
7 | for (int i = 0; i < (mesh.c_length / mesh.spatial_step_size); i++)
8 | {
9 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.front(), mesh.left_side_boundary_conditions.at(0))); //Put the first I.C in.
10 | for (float j = 1; j <= mesh.number_of_nodes - 1; ++j) // Iterate over the nodes which are not boundary conditions. (starts at node 1 and stops at # of nodes-1
11 | {
12 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.at(j), mesh.InitialDistribution(0)));
13 | }
14 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.back(), mesh.right_side_boundary_conditions.at(0))); // Once filled, set the last B.C.
15 | Instance.push_back(current_configuration);
16 | current_configuration.clear(); // Clear the current state
17 | }
18 |
19 | Results.push_back(Instance); // Add to the vector of states
20 | Instance.clear();
21 | }
22 | void Engine2D::CreateMesh(Mesh2D& mesh)
23 | {
24 | // Fill side1 length BC -> Left side
25 | // Fill side2 length BC -> Right side
26 | // Fill width1 BC ->Top
27 | // Fill width2 BC ->bottom
28 | mesh.number_of_nodes = (mesh.c_length / mesh.spatial_step_size);
29 | mesh.all_node_locations.push_back(0);
30 | for (int i = 0; i < mesh.number_of_nodes; i++)
31 | {
32 | mesh.all_node_locations.push_back(mesh.all_node_locations.back() + mesh.spatial_step_size);
33 | }
34 | // !Create a boundary condition for each state
35 | for (int state = 0; state <= number_of_states; state++)
36 | {
37 | mesh.left_side_boundary_conditions.push_back(mesh.SideBoundary());
38 | mesh.right_side_boundary_conditions.push_back(mesh.SideBoundary());
39 | // !First and last states
40 | if (state== 0 || state==number_of_states)
41 | {
42 | mesh.top_width_boundary_conditions.push_back(mesh.WidthBoundary());
43 | mesh.bottom_width_boundary_conditions.push_back(mesh.WidthBoundary());
44 | }
45 | }
46 | }
47 | bool Engine2D::CheckStability(Mesh2D mesh)
48 | {
49 | double check = 2 * (mesh.thermal_conductivity*time_step) / (mesh.spatial_step_size*mesh.spatial_step_size);
50 | if (check <= 0.5)
51 | {
52 | cout << endl << endl;
53 | cout << "Under the current configuration, unstale results may occur." << endl;
54 | cout << "To Ensure convergence, please satisfy the following equation." << endl;
55 | cout << "2*(mesh.thermal_conductivity*time_step)/(mesh.spatial_step_size*mesh.spatial_step_size) <=0.5" << endl;
56 | cout << endl;
57 | cout << "This can be achieved by modifying any of the following:" << endl;
58 | cout << " -thermal_conductivity" << endl;
59 | cout << " -time_step" << endl;
60 | cout << " -spatial_step_size" << endl;
61 | cout << endl;
62 | cout << " It is currently at " << (mesh.thermal_conductivity*time_step) / (mesh.spatial_step_size*mesh.spatial_step_size) << endl;
63 | return false;
64 | }
65 | return true;
66 | }
67 | void Engine2D::Solve(Mesh2D &mesh)
68 | {
69 | CheckStability(mesh);
70 |
71 | double alpha = (mesh.thermal_conductivity*time_step) / (mesh.spatial_step_size);
72 | double beta=alpha;
73 | vector Temperature;
74 | // !Iterate over the states
75 | for (int i = 1; i <= number_of_states; i++)
76 | {
77 | // !Iterate through each row on the panel
78 | for (int j = 1; j < (mesh.x_length / mesh.spatial_step_size); j++)
79 | {
80 | // SET THE FIRST NODE FROM BC
81 | Temperature.push_back(5);
82 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.at(0), Temperature.at(0)));
83 | // !Iterate over the node
84 | for (int k = 1; k < mesh.number_of_nodes; k++)
85 | {
86 | Temperature.push_back(alpha*(GetPreviousTemperature(i, j, k, 'f') + GetPreviousTemperature(i, j, k, 'b')) +(beta*(GetPreviousTemperature(i, j,k, 'f') + GetPreviousTemperature(i, j, k, 'b'))) + ((1 - 2 * alpha - 2 * beta)*GetPreviousTemperature(i, j, k, 'n')));
87 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.at(k), Temperature.at(k)));
88 | }
89 | Temperature.push_back(5);
90 | current_configuration.push_back(std::make_tuple(mesh.all_node_locations.at(mesh.all_node_locations.size()-1), Temperature.at(mesh.number_of_nodes)));
91 | Instance.push_back(current_configuration);
92 | current_configuration.clear();
93 | }
94 | Results.push_back(Instance);
95 | Instance.clear();
96 | }
97 | CreateCSV(mesh);
98 | }
99 |
100 | double Engine2D::RetrieveTemperature(int current_state, int y_position, int node_position)
101 | {
102 | vector>> instance_container;
103 | vector> temperature_dist;
104 | tuple record;
105 | instance_container = Results.at(current_state);
106 | temperature_dist =instance_container.at(y_position);
107 | record = temperature_dist.at(node_position);
108 | return get<1>(record);
109 | }
110 |
111 | double Engine2D::GetPreviousTemperature(int current_state, int y_position, double node_location, char direction)
112 | {
113 | if (direction == 'f')
114 | {
115 | return RetrieveTemperature(current_state-1, y_position - 1, node_location + 1);
116 | }
117 | if (direction == 'b')
118 | {
119 | return RetrieveTemperature(current_state-1, y_position - 1, node_location - 1);
120 | }
121 | if (direction == 'n')
122 | {
123 | return RetrieveTemperature(current_state-1, y_position - 1, node_location);
124 | }
125 | else
126 | {
127 | cout << "Error Obtaining Temperature" << endl;
128 | return 0;
129 | }
130 | }
131 |
132 | void Engine2D::CreateCSV(Mesh2D mesh)
133 | {
134 | std::ofstream dataFile;
135 | dataFile.open("Results.csv");
136 | tuple record;
137 | //Iterate records with GetRecord
138 |
139 | for (int i = 0; i < number_of_states; i++)
140 | {
141 | for (int j = 0; j < mesh.all_node_locations.size(); j++)
142 | {
143 | record = GetRecordb(i, j);
144 | dataFile << get<0>(record) << "," << get<1>(record) << endl; // CORRECT THIS
145 | }
146 | }
147 | dataFile.close();
148 | }
149 |
--------------------------------------------------------------------------------
/src/Engine2D.hpp:
--------------------------------------------------------------------------------
1 | #include "Engine.hpp"
2 |
3 | class Engine2D : public Engine
4 | {
5 | public:
6 | vector>> Instance;
7 |
8 | // !This is ugly
9 | vector>>> Results;
10 |
11 | void CreateMesh(Mesh2D&);
12 |
13 | void CreateInitialState(Mesh2D&);
14 |
15 | void CreateCSV(Mesh2D);
16 |
17 | void Solve(Mesh2D&);
18 |
19 | bool CheckStability(Mesh2D);
20 |
21 | double RetrieveTemperature(int, int, int);
22 |
23 | double GetPreviousTemperature(int, int, double, char);
24 | };
--------------------------------------------------------------------------------
/src/FDMEngine.hpp:
--------------------------------------------------------------------------------
1 | /*! \file FDMEngine.hpp
2 | * \brief Contains the methods for the simulation.
3 | *
4 | * The two classes are Mesh and Engine
5 | */
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/Mesh.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | struct Mesh
5 | {
6 | //! Length of the object.
7 | double x_length;
8 |
9 | //! The step size between nodes.
10 | double spatial_step_size;
11 |
12 | //! The thermal conductivity of the mesh.
13 | double thermal_conductivity;
14 |
15 | //! Number of nodes on the mesh -> POSSIBLY DELETE.
16 | int number_of_nodes;
17 |
18 | //! A pointer to the user defined boundary condition function.
19 | std::function DirchletBoundaryEquation;
20 | std::function InitialDistribution;
21 | };
--------------------------------------------------------------------------------
/src/Mesh1D.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "Mesh.hpp"
3 | #include
4 | struct Mesh1D : public Mesh
5 | {
6 | public:
7 | double spatial_width;
8 | std::vector all_node_locations;
9 | };
10 |
--------------------------------------------------------------------------------
/src/Mesh2D.hpp:
--------------------------------------------------------------------------------
1 | #include "Mesh.hpp"
2 |
3 | struct Mesh2D : public Mesh
4 | {
5 | double spacial_width;
6 |
7 | vector left_side_boundary_conditions;
8 |
9 | vector right_side_boundary_conditions;
10 |
11 | vector top_width_boundary_conditions;
12 |
13 | vector bottom_width_boundary_conditions;
14 |
15 | vector all_node_locations;
16 |
17 | std::function SideBoundary;
18 |
19 | std::function WidthBoundary;
20 | };
--------------------------------------------------------------------------------