├── gui
├── __init__.py
├── worker.py
├── plot_window.py
└── main_window.py
├── version.py
├── translation
├── __init__.py
├── main.py
├── messages.pot
├── messages-en.po
└── messages-ro.po
├── requirements.txt
├── docs
├── app-diagram.png
└── app-diagram.drawio
├── resources
├── app-icon-16.ico
├── app-icon-16.png
├── app-icon-32.ico
├── app-icon-32.png
├── app-icon-60.ico
├── app-icon-60.png
├── app-icon-70.png
├── app-icon-72.ico
├── app-icon-72.png
├── app-icon-76.png
├── app-icon-96.ico
└── app-icon-96.png
├── .gitignore
├── main.py
├── compile-messages.sh
├── LICENSE
├── sample
├── tut-export-limited.txt
└── tut-export.txt
├── README.md
└── osa
├── test_simulator.py
├── simulator.py
└── old_simulator.py
/gui/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/version.py:
--------------------------------------------------------------------------------
1 | VERSION = "2.0"
2 |
--------------------------------------------------------------------------------
/translation/__init__.py:
--------------------------------------------------------------------------------
1 | from .main import install
2 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pyside6
2 | pytest
3 | fbs
4 | numpy
5 | matplotlib
--------------------------------------------------------------------------------
/docs/app-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/docs/app-diagram.png
--------------------------------------------------------------------------------
/resources/app-icon-16.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-16.ico
--------------------------------------------------------------------------------
/resources/app-icon-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-16.png
--------------------------------------------------------------------------------
/resources/app-icon-32.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-32.ico
--------------------------------------------------------------------------------
/resources/app-icon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-32.png
--------------------------------------------------------------------------------
/resources/app-icon-60.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-60.ico
--------------------------------------------------------------------------------
/resources/app-icon-60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-60.png
--------------------------------------------------------------------------------
/resources/app-icon-70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-70.png
--------------------------------------------------------------------------------
/resources/app-icon-72.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-72.ico
--------------------------------------------------------------------------------
/resources/app-icon-72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-72.png
--------------------------------------------------------------------------------
/resources/app-icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-76.png
--------------------------------------------------------------------------------
/resources/app-icon-96.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-96.ico
--------------------------------------------------------------------------------
/resources/app-icon-96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kopsha/fbg-simulation-pyqt/HEAD/resources/app-icon-96.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .nvimlog
3 | .venv/
4 | *~
5 | translation/**/
6 | sample/*.png
7 |
8 | # Python precompiled
9 | __pycache__/
10 | *.py[cod]
11 | *$py.class
12 |
13 |
14 | # Unit test / coverage reports
15 | htmlcov/
16 | .tox/
17 | .coverage
18 | .coverage.*
19 | .cache
20 | nosetests.xml
21 | coverage.xml
22 | *.cover
23 | *.py,cover
24 | .hypothesis/
25 | .pytest_cache/
26 |
--------------------------------------------------------------------------------
/translation/main.py:
--------------------------------------------------------------------------------
1 | import gettext
2 |
3 |
4 | _translators = dict()
5 |
6 |
7 | def install(lang: str):
8 | gettext.bindtextdomain("fbg-simulation-pyqt", "./translation")
9 | gettext.textdomain("fbg-simulation-pyqt")
10 |
11 | global _translators
12 | _translators = dict(
13 | ro=gettext.translation("fbg-simulation-pyqt", "./translation", languages=["ro"]),
14 | en=gettext.translation("fbg-simulation-pyqt", "./translation", languages=["en"]),
15 | )
16 | _translators.get(lang).install()
17 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | import sys
3 | from PySide6.QtWidgets import QApplication
4 | from PySide6.QtGui import QIcon
5 |
6 | from locale import setlocale, LC_ALL
7 | import translation
8 | from gui.main_window import MainWindow
9 | from version import VERSION
10 |
11 |
12 | def main(argv):
13 | app = QApplication(argv)
14 | translation.install("ro")
15 | setlocale(LC_ALL, "")
16 |
17 | window = MainWindow()
18 | window.setWindowTitle(f"Simulator FBG v{VERSION} (2023)")
19 | window.setWindowIcon(QIcon("resources/app-icon-96.ico"))
20 | window.resize(1440, 720)
21 | window.show()
22 |
23 | # maybe call some post init stuff
24 | ret_code = app.exec()
25 | # maybe call some closing handlers
26 |
27 | return ret_code
28 |
29 |
30 | if __name__ == "__main__":
31 | main(sys.argv)
32 |
--------------------------------------------------------------------------------
/compile-messages.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euo pipefail
3 |
4 | AUTHOR="Codruta Toadere"
5 | EMAIL="codrutatoadere@gmail.com"
6 |
7 | init()
8 | {
9 | use_locale=$1
10 | echo "..: Creating ${use_locale} translation."
11 |
12 | lang=${use_locale:0:2}
13 | msginit --locale=${use_locale} --input=messages.pot --output=messages-${lang}.po
14 | }
15 |
16 | compile()
17 | {
18 | use_locale=$1
19 | echo "..: Building ${use_locale} translation binaries"
20 |
21 | lang=${use_locale:0:2}
22 | if [ ! -f "messages-${lang}.po" ]; then
23 | init $use_locale
24 | fi
25 |
26 | msgmerge "messages-${lang}.po" messages.pot \
27 | --lang=${use_locale} \
28 | --sort-output \
29 | --no-wrap \
30 | --verbose \
31 | --update
32 |
33 | mkdir -p "./${lang}/LC_MESSAGES"
34 | msgfmt "messages-${lang}.po" \
35 | --verbose \
36 | --output="./${lang}/LC_MESSAGES/fbg-simulation-pyqt.mo"
37 | }
38 |
39 | # collect all translatable strings
40 | xgettext gui/*.py \
41 | --sort-output \
42 | --foreign-user \
43 | --copyright-holder="${AUTHOR}" \
44 | --package-name="fbg-simulation-pyqt" \
45 | --package-version="v2.0" \
46 | --msgid-bugs-address="${EMAIL}" \
47 | --language=Python \
48 | --verbose \
49 | --output="./translation/messages.pot"
50 |
51 | cd ./translation
52 | for language in ro_RO en_US; do
53 | compile $language
54 | done
55 | cd ..
56 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2023, Florin Ciurcanu
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | 3. Neither the name of the copyright holder nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/gui/worker.py:
--------------------------------------------------------------------------------
1 | from PySide6.QtCore import QThread, Signal
2 | from osa.simulator import OsaSimulator
3 |
4 |
5 | class WorkerThread(QThread):
6 | progress = Signal(int)
7 |
8 | def __init__(self, params: dict) -> None:
9 | super().__init__()
10 |
11 | self.units = params.pop("units")
12 | self.include_undeformed_signal = params.pop("has_reflected_signal")
13 | self.strain_type = params.pop("strain_type")
14 | self.stress_type = params.pop("stress_type")
15 | self.datafile = params.pop("filepath")
16 | self.params = params
17 | self.error_message = ""
18 | self.data = None
19 |
20 | def run(self):
21 | self.progress.emit(13)
22 |
23 | undeformed_data = None
24 | deformed_data = None
25 | summary_data = None
26 |
27 | try:
28 | simu = OsaSimulator(**self.params)
29 | simu.from_file(filepath=self.datafile, units=self.units)
30 | self.progress.emit(21)
31 |
32 | if self.include_undeformed_signal:
33 | undeformed_data = simu.undeformed_fbg()
34 | self.progress.emit(34)
35 |
36 | self.progress.emit(55)
37 | deformed_data = simu.deformed_fbg(
38 | strain_type=self.strain_type,
39 | stress_type=self.stress_type,
40 | )
41 | self.progress.emit(89)
42 |
43 | summary_data = simu.compute_fbg_shifts_and_widths(
44 | strain_type=self.strain_type,
45 | stress_type=self.stress_type,
46 | )
47 | self.progress.emit(100)
48 |
49 | except Exception as err:
50 | self.error_message = str(err)
51 |
52 | self.data = dict(
53 | undeformed=undeformed_data,
54 | deformed=deformed_data,
55 | summary=summary_data,
56 | )
57 |
--------------------------------------------------------------------------------
/docs/app-diagram.drawio:
--------------------------------------------------------------------------------
1 | 7Zvdb+I4EMD/GqS7h63I54bHhX7cQ3uHDt129wkZ4iTeOnHkOAvsX39j4hCCNwVUSFopUoXwZJw4Mz/PjI07sCbx+oGjNHpiPqYDc+ivB9btwDRHtgefUrApBPbILgQhJ34hMirBjPzCSjhU0pz4OKspCsaoIGlduGRJgpeiJkOcs1VdLWC0/tQUhVgTzJaI6tJn4ouokHrOsJL/hUkYlU82hupKjEplJcgi5LPVnsi6G1gTzpgovsXrCabSdqVdin73DVd3A+M4Ead0ePAWP14evk6nc/fvEN3/5316DD+pu/xENFcvPCNxTpFgHMT34wf4BMmU5plUM2/KlxGb0kLZisQUJdAaryIi8CxFS3lpBTyALBIxhZYBX9WzMBd43fgSxs40gBRmMRZ8Ayqqg62ev6k3V5VrXE/Joj23WKUTkMIh3N25shh8UUY7w4CmoxkE+0CQajIuIhayBNG7SjrmLE98LG87hFal88hYqmz1AwuxUdMB5YLVLYnXRHyT3W8c1fq+d+V2re68bWxUoxinHFyj7V9DJGM5X+LXLKFmJ+Ihfu1+1u8dzDFQR37WB3d5d2m8x4gkN+lG82LlI+M42QGhdMIoTBrZ1wqQ/xktQZ4Jzl7w3pWF7TpD+9S50OyPN0wQw/7NBLGvNT8szeBPYPBnkshY+EooCVgiykkk6V1GhPqPaMNyOeJMoOVL2RpHjJNfoI9Kd8BlLtTkMV3dP76DPd+u9ZzJO6pncZxB32npCONA9ITWNcVHlIlylIxSlGZksR237BjDdCDJmAnBYqV0hCWNGc9cWK7bHjOGeSI0xtC+EjW2Rs3AHEtWsMjTeU7++FNjB2wiNOslrIBpz/1KhCgJE2hSHMhu0qgEsv4XJRYyEI8zcBJJwsetzq1dSf5VRpAiBn0Dus3sEfF9nGwDvEACLXb0powkYmskZwx/YMuJDN0ODHwCbaNqw59U52LCEngXmCvyORgQW2GJ2UVy7DlxWUEB0+gkJkq9iyPhNCDB82SeFTULYUkPRttgOGbHYLhNsSJiq3lKmeiZaJuJz17HTHgaE7MUVoc8j78S3Ncd76TuML2DwmN0IjfXKzxGfeHReizx3nfhUe5E6ZUHDmAiRn2O6YSLzusOQ987U7EC/cTzgIQ5xz0WbWPReelh6FtMs93y5JnxF8y7qz8Q9oLlR6k/3KWHF0GL9Yd74r5Hydjl2dF3y3aL3D6UXD6UFHP1HZceTZseAUlIFmG/h6J1KLqvO/Q1yj8Z2vvZrk8u7yG5OMODxa196uLWutpvlU0rGcqQDxUr7evVa8ST0ftOMmbTOkb+/hkwHmNgYxH2aLSORuepxtTXMgUah2C4VNppAcnHDcXOJD0qraHS+bLXbFq6LFmc5gLPs4gEIuujSOto7DbLu2PD1Zze4hmp8rs8IVWdl+rmjJRazx09I2W89ZDUtusXztFmT0HBXN15KgV7+yHmQcnqOfu+P6o/Gh2gUgygAmf3Jm9gyfsoLAExfPNtv1H0MkynFFQdt61azynmBIyFeUtouiei2bD92tLxvdFH8f613VVuFR4PJQ3ZoR2HlWvZjo7HnuEwH8kNtVoyvqL3nEvEdy0gG9oP6qP6LQpaVK/KtWcnCu3E4JFEcajfRqawjI+C3i5TGPVMcSxPtIqseXLAuQjb5yJpH6Bvuq8jeah/gPC5SEKz+k+OQr36dxjr7n8=
--------------------------------------------------------------------------------
/sample/tut-export-limited.txt:
--------------------------------------------------------------------------------
1 | % Model:
2 | % Version: COMSOL 5.4.0.388
3 | % Date: Jan 12 2021, 23:17
4 | % Dimension: 1
5 | % Nodes: 20
6 | % Expressions: 7
7 | % Description: Logarithmic strain tensor, xx component, Logarithmic strain tensor, yy component, Logarithmic strain tensor, zz component, Stress tensor, x component, Stress tensor, y component, Stress tensor, z component, Temperature
8 | % cln1x solid.elogxx (1) solid.elogyy (1) solid.elogzz (1) solid.sx (N/m^2) solid.sy (N/m^2) solid.sz (N/m^2) T (K)
9 | 0.022000 0.0019151 -3.2940E-4 -3.7446E-4 4.6799E7 -277.81 3.5968E-6 293.15
10 | 0.023000 0.0018947 -3.2100E-4 -3.6965E-4 4.6199E7 -277.79 -1.1126E-5 293.15
11 | 0.024000 0.0018745 -3.1251E-4 -3.6488E-4 4.5601E7 277.77 -5.6252E-6 293.15
12 | 0.025000 0.0018542 -3.0393E-4 -3.6005E-4 4.4999E7 -277.78 -1.4998E-5 293.15
13 | 0.026000 0.0018341 -2.9527E-4 -3.5525E-4 4.4399E7 -277.78 -2.9696E-5 293.15
14 | 0.027000 0.0018142 -2.8654E-4 -3.5047E-4 4.3801E7 277.78 -5.2527E-6 293.15
15 | 0.028000 0.0017942 -2.7775E-4 -3.4567E-4 4.3201E7 277.78 1.6950E-5 293.15
16 | 0.029000 0.0017742 -2.6889E-4 -3.4084E-4 4.2599E7 -277.78 -3.4092E-5 293.15
17 | 0.030000 0.0017544 -2.5997E-4 -3.3607E-4 4.2001E7 277.78 -1.8673E-5 293.15
18 | 0.031000 0.0017346 -2.5100E-4 -3.3127E-4 4.1401E7 277.78 -2.8200E-5 293.15
19 | 0.032000 0.0017147 -2.4197E-4 -3.2644E-4 4.0799E7 -277.78 -1.0144E-5 293.15
20 | 0.033000 0.0016951 -2.3291E-4 -3.2167E-4 4.0201E7 277.78 -3.6996E-5 293.15
21 | 0.034000 0.0016755 -2.2380E-4 -3.1686E-4 3.9601E7 277.78 1.3024E-5 293.15
22 | 0.035000 0.0016557 -2.1466E-4 -3.1204E-4 3.8999E7 -277.78 2.9437E-5 293.15
23 | 0.036000 0.0016362 -2.0549E-4 -3.0726E-4 3.8401E7 277.78 -1.7652E-4 293.15
24 | 0.037000 0.0016167 -1.9630E-4 -3.0246E-4 3.7801E7 277.78 2.6179E-5 293.15
25 | 0.038000 0.0015970 -1.8708E-4 -2.9763E-4 3.7199E7 -277.78 4.3446E-5 293.15
26 | 0.039000 0.0015775 -1.7785E-4 -2.9283E-4 3.6599E7 -277.78 -9.6249E-5 293.15
27 | 0.040000 0.0015580 -1.6860E-4 -2.8805E-4 3.6001E7 277.78 -1.1721E-5 293.15
28 | 0.041000 0.0015384 -1.5934E-4 -2.8323E-4 3.5399E7 -277.78 -7.3165E-6 293.15
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FBG-Simulation-PyQt
2 |
3 | FBG Simulation PyQt is an open-source project that builds upon the previous work
4 | of [Gilmar Pereira](https://github.com/GilmarPereira)'s
5 | project [FBG_SiMul](https://github.com/GilmarPereira/FBG_SiMul) and
6 | [Benjamin Frey](https://github.com/benfrey)'s project
7 | [FBG-SimPlus](https://github.com/benfrey/FBG-SimPlus).
8 |
9 | Our goal is to provide a clean sample implementation of a Qt application that
10 | can be used in any simulations projects. It proves how to effectively decouple
11 | simulation code from GUI which is really tough to manage without years of
12 | experience in developing Qt or GUI.
13 |
14 | And hopefully allows scientist and researchers to write richer simulation
15 | without the hassle of writing a stable and clean GUI application.
16 |
17 | This project is released under [BSD 3](./LICENSE), and we adhere to the
18 | licensing and attribution requirements of the original projects that we have
19 | adapted.
20 |
21 | ## Features
22 |
23 | - Easy-to-use interface for managing simulations
24 | - Decoupled implementation of FBG simulation (fully tested with pytest)
25 | - [WIP, will add more]
26 |
27 |
28 | ## Getting Started
29 |
30 | ### Prerequisites
31 |
32 | The python application is built with [PySide6](https://pypi.org/project/PySide6/)
33 | and uses [pytest](https://docs.pytest.org/) for all its unit tests.
34 |
35 |
36 | ### Installation
37 |
38 | Considering that you have Python already installed, you can install all required
39 | packages with just one command:
40 |
41 | ```bash
42 | pip install -r requirements.txt
43 | ```
44 |
45 | Then, you need to compile the translated messages by running the shell script
46 | ```bash
47 | ./compile-messages.sh
48 | ```
49 |
50 | And you're good to go.
51 |
52 | ### Usage
53 |
54 | To start the application simply run the [main.py](./main.py) and load the
55 | provided [sample.txt](./sample/tut-export.txt) datafile.
56 |
57 |
58 | ## Application design diagram
59 |
60 | The implementation of this application has completely decoupled GUI classes from
61 | the simulator. The simulation code is pure python code and can be further
62 | integrated in any kind of other applications (be it GUI or computing centric)
63 |
64 | 
65 |
66 |
67 | ## Acknowledgments and Licensing
68 |
69 | This project is built upon, and adapted from, the following open source projects:
70 |
71 | - [FBG_SiMul](https://github.com/GilmarPereira/FBG_SiMul), licensed under
72 | [GPL-3](https://github.com/GilmarPereira/FBG_SiMul/blob/master/LICENSE)
73 | - [FBG-SimPlus](https://github.com/benfrey/FBG-SimPlus), licensed under
74 | [GPL-3](https://github.com/benfrey/FBG-SimPlus/blob/master/LICENSE)
75 |
76 | Please make sure to review the licenses of these projects to understand their terms and conditions. Our project adheres to these licenses and provides proper attribution to the original authors.
77 |
78 | **Citation**: If you choose to use elements of this application in your own
79 | work, please cite the following paper:
80 |
81 | > Frey, B., Snyder, P., Ziock, K., & Passian, A. (2021).
82 | > _"Semicomputational calculation of Bragg shift in stratified materials"_.
83 | > Physical Review E, 104(5), 055307.
84 |
85 |
86 | ## License
87 |
88 | This project is licensed under the BSD-3 license. Please read the
89 | [LICENSE](./LICENSE) file for full details.
90 |
--------------------------------------------------------------------------------
/translation/messages.pot:
--------------------------------------------------------------------------------
1 | # SOME DESCRIPTIVE TITLE.
2 | # Copyright (C) YEAR Codruta Toadere
3 | # This file is distributed under the same license as the fbg-simulation-pyqt package.
4 | # FIRST AUTHOR , YEAR.
5 | #
6 | #, fuzzy
7 | msgid ""
8 | msgstr ""
9 | "Project-Id-Version: fbg-simulation-pyqt v2.0\n"
10 | "Report-Msgid-Bugs-To: codrutatoadere@gmail.com\n"
11 | "POT-Creation-Date: 2023-08-24 07:25+0300\n"
12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13 | "Last-Translator: FULL NAME \n"
14 | "Language-Team: LANGUAGE \n"
15 | "Language: \n"
16 | "MIME-Version: 1.0\n"
17 | "Content-Type: text/plain; charset=CHARSET\n"
18 | "Content-Transfer-Encoding: 8bit\n"
19 |
20 | #: gui/main_window.py:514
21 | msgid "A simulator session is already running."
22 | msgstr ""
23 |
24 | #: gui/main_window.py:326
25 | msgid "Add"
26 | msgstr ""
27 |
28 | #: gui/main_window.py:207
29 | msgid "Ambient temperature"
30 | msgstr ""
31 |
32 | #: gui/main_window.py:104
33 | msgid "Apply conversion from m to mm"
34 | msgstr ""
35 |
36 | #: gui/main_window.py:499
37 | msgid "At least one wavelength is above the maximum bandwidth setting."
38 | msgstr ""
39 |
40 | #: gui/main_window.py:497
41 | msgid "At least one wavelength is below the minimum bandwidth setting."
42 | msgstr ""
43 |
44 | #: gui/main_window.py:336
45 | msgid "Auto"
46 | msgstr ""
47 |
48 | #: gui/main_window.py:218
49 | msgid "Average variation in refractive index"
50 | msgstr ""
51 |
52 | #: gui/plot_window.py:105
53 | msgid "Axis control"
54 | msgstr ""
55 |
56 | #: gui/main_window.py:127
57 | msgid "Choose a simulation type"
58 | msgstr ""
59 |
60 | #: gui/main_window.py:93
61 | msgid "Choose file"
62 | msgstr ""
63 |
64 | #: gui/main_window.py:406
65 | msgid "Clear log"
66 | msgstr ""
67 |
68 | #: gui/plot_window.py:266
69 | msgid "Deformed FBG Spectrum"
70 | msgstr ""
71 |
72 | #: gui/main_window.py:432
73 | msgid "ERROR"
74 | msgstr ""
75 |
76 | #: gui/main_window.py:164
77 | msgid "Emulate model temperature"
78 | msgstr ""
79 |
80 | #: gui/main_window.py:161
81 | msgid "Emulation options"
82 | msgstr ""
83 |
84 | #: gui/plot_window.py:155
85 | msgid "Enable panning"
86 | msgstr ""
87 |
88 | #: gui/main_window.py:211
89 | msgid "Fiber attributes (advanced mode)"
90 | msgstr ""
91 |
92 | #: gui/main_window.py:236
93 | msgid "Fiber thermal expansion coefficient"
94 | msgstr ""
95 |
96 | #: gui/main_window.py:221
97 | msgid "Fringe visibility"
98 | msgstr ""
99 |
100 | #: gui/plot_window.py:90
101 | msgid "Grid"
102 | msgstr ""
103 |
104 | #: gui/main_window.py:172
105 | msgid "Host thermal expansion coefficient"
106 | msgstr ""
107 |
108 | #: gui/main_window.py:103
109 | msgid "If distances are not expressed in millimeters [mm]"
110 | msgstr ""
111 |
112 | #: gui/plot_window.py:303
113 | msgid "Images"
114 | msgstr ""
115 |
116 | #: gui/main_window.py:147
117 | msgid "Include stress"
118 | msgstr ""
119 |
120 | #: gui/main_window.py:381
121 | msgid "Include the undeformed FBG reflected signal"
122 | msgstr ""
123 |
124 | #: gui/main_window.py:215
125 | msgid "Initial refractive index"
126 | msgstr ""
127 |
128 | #: gui/plot_window.py:89
129 | msgid "Legend"
130 | msgstr ""
131 |
132 | #: gui/plot_window.py:177
133 | msgid "Line properties"
134 | msgstr ""
135 |
136 | #: gui/main_window.py:427
137 | msgid "Load data from"
138 | msgstr ""
139 |
140 | #: gui/main_window.py:89
141 | msgid "Load strain / stress data from file"
142 | msgstr ""
143 |
144 | #: gui/main_window.py:130
145 | msgid "Longitudinal strain"
146 | msgstr ""
147 |
148 | #: gui/main_window.py:204
149 | msgid "Maximum bandwidth"
150 | msgstr ""
151 |
152 | #: gui/main_window.py:399
153 | msgid "Message log"
154 | msgstr ""
155 |
156 | #: gui/main_window.py:201
157 | msgid "Minimum bandwidth"
158 | msgstr ""
159 |
160 | #: gui/main_window.py:136
161 | msgid "Non-uniform"
162 | msgstr ""
163 |
164 | #: gui/main_window.py:133 gui/main_window.py:150
165 | msgid "None"
166 | msgstr ""
167 |
168 | #: gui/main_window.py:299
169 | msgid "Number of FBG sensors"
170 | msgstr ""
171 |
172 | #: gui/main_window.py:385
173 | msgid "Open simulation results"
174 | msgstr ""
175 |
176 | #: gui/main_window.py:307
177 | msgid "Original wavelengths"
178 | msgstr ""
179 |
180 | #: gui/main_window.py:356
181 | msgid "Please enter a value for FBG"
182 | msgstr ""
183 |
184 | #: gui/plot_window.py:36
185 | msgid "Plot FBG Spectrum"
186 | msgstr ""
187 |
188 | #: gui/plot_window.py:86
189 | msgid "Plot options"
190 | msgstr ""
191 |
192 | #: gui/main_window.py:224 gui/main_window.py:227
193 | msgid "Pockel's elasto-optic coefficients"
194 | msgstr ""
195 |
196 | #: gui/main_window.py:233
197 | msgid "Poisson's coefficient"
198 | msgstr ""
199 |
200 | #: gui/main_window.py:304
201 | msgid "Positions of FBG sensors (distance from the start)"
202 | msgstr ""
203 |
204 | #: gui/plot_window.py:130 gui/plot_window.py:286
205 | msgid "Reflectivity"
206 | msgstr ""
207 |
208 | #: gui/main_window.py:328
209 | msgid "Remove"
210 | msgstr ""
211 |
212 | #: gui/plot_window.py:301
213 | msgid "Save FBG Spectrum Plot"
214 | msgstr ""
215 |
216 | #: gui/plot_window.py:72
217 | msgid "Save picture"
218 | msgstr ""
219 |
220 | #: gui/main_window.py:300
221 | msgid "Sensor length"
222 | msgstr ""
223 |
224 | #: gui/main_window.py:502
225 | msgid "Sensors count ({}) and original wavelengths count ({}) must be equal."
226 | msgstr ""
227 |
228 | #: gui/plot_window.py:223
229 | msgid "Shift"
230 | msgstr ""
231 |
232 | #: gui/plot_window.py:195
233 | msgid "Simulated color"
234 | msgstr ""
235 |
236 | #: gui/main_window.py:539
237 | msgid "Simulation completed successfully."
238 | msgstr ""
239 |
240 | #: gui/main_window.py:534
241 | msgid "Simulation has failed, reason: {}"
242 | msgstr ""
243 |
244 | #: gui/plot_window.py:215
245 | msgid "Simulation output"
246 | msgstr ""
247 |
248 | #: gui/main_window.py:195
249 | msgid "Simulation parameters"
250 | msgstr ""
251 |
252 | #: gui/main_window.py:199
253 | msgid "Simulation resolution"
254 | msgstr ""
255 |
256 | #: gui/main_window.py:376
257 | msgid "Spectrum simulation"
258 | msgstr ""
259 |
260 | #: gui/plot_window.py:91
261 | msgid "Split waveform (Birefringence)"
262 | msgstr ""
263 |
264 | #: gui/main_window.py:382
265 | msgid "Start simulation"
266 | msgstr ""
267 |
268 | #: gui/main_window.py:544
269 | msgid "There is no data to show, please run the simulation first."
270 | msgstr ""
271 |
272 | #: gui/main_window.py:239
273 | msgid "Thermo-optic coefficient"
274 | msgstr ""
275 |
276 | #: gui/main_window.py:301
277 | msgid "Tolerance"
278 | msgstr ""
279 |
280 | #: gui/main_window.py:152
281 | msgid "Transverse stress"
282 | msgstr ""
283 |
284 | #: gui/main_window.py:487
285 | msgid "Two consecutive FBG positions cannot be shorter than FBG length."
286 | msgstr ""
287 |
288 | #: gui/plot_window.py:258
289 | msgid "Undeformed FBG Spectrum"
290 | msgstr ""
291 |
292 | #: gui/plot_window.py:190
293 | msgid "Undeformed color"
294 | msgstr ""
295 |
296 | #: gui/main_window.py:135
297 | msgid "Uniform"
298 | msgstr ""
299 |
300 | #: gui/main_window.py:295
301 | msgid "Virtual Fiber Bragg Grating array configuration"
302 | msgstr ""
303 |
304 | #: gui/plot_window.py:109 gui/plot_window.py:223 gui/plot_window.py:285
305 | msgid "Wavelength"
306 | msgstr ""
307 |
308 | #: gui/plot_window.py:180
309 | msgid "Width"
310 | msgstr ""
311 |
312 | #: gui/plot_window.py:223
313 | msgid "Width Variation"
314 | msgstr ""
315 |
316 | #: gui/plot_window.py:275
317 | msgid "Y-Wave Contribution"
318 | msgstr ""
319 |
320 | #: gui/main_window.py:230
321 | msgid "Young's module"
322 | msgstr ""
323 |
324 | #: gui/plot_window.py:282
325 | msgid "Z-Wave Contribution"
326 | msgstr ""
327 |
328 | #: gui/main_window.py:472
329 | msgid "is not a valid data file."
330 | msgstr ""
331 |
332 | #: gui/main_window.py:304
333 | msgid "position"
334 | msgstr ""
335 |
336 | #: gui/main_window.py:307
337 | msgid "wavelength"
338 | msgstr ""
339 |
--------------------------------------------------------------------------------
/osa/test_simulator.py:
--------------------------------------------------------------------------------
1 | """
2 | Testing the every function of the new simulator against the old one
3 | The new implmentation is just a refactoring to a more pythonic state of the
4 | old code, the computations should stay exactly the same.
5 | """
6 | import pytest
7 | import numpy as np
8 |
9 | from old_simulator import OSASimulation
10 | from simulator import OsaSimulator, SiUnits, StrainTypes, StressTypes
11 |
12 |
13 | @pytest.fixture
14 | def init_params():
15 | params = dict(
16 | fbg_count=5,
17 | fbg_length=9,
18 | tolerance=0.01,
19 | fbg_positions=list(),
20 | initial_refractive_index=1.46,
21 | directional_refractive_p11=0,
22 | directional_refractive_p12=0,
23 | poissons_coefficient=0,
24 | resolution=0.05,
25 | min_bandwidth=1500.0,
26 | max_bandwidth=1600.0,
27 | mean_change_refractive_index=4.5e-4,
28 | fringe_visibility=np.float64(1),
29 | emulate_temperature=293.15, # 373.15,
30 | original_wavelengths=[1500.0, 1525.0, 1550.0, 1575.0, 1600.0],
31 | ambient_temperature=293.15,
32 | thermo_optic=8.3e-6,
33 | fiber_expansion_coefficient=10e-6, # Internet says 0.5E-6 to 1E-6
34 | host_expansion_coefficient=10e-6,
35 | youngs_mod=75e9,
36 | )
37 | return params
38 |
39 |
40 | def assert_fbg_equals(left: dict, right: dict):
41 | assert left.keys() == right.keys()
42 | for fb_left, fb_right in zip(left.values(), right.values()):
43 | assert isinstance(fb_left, dict)
44 | assert isinstance(fb_right, dict)
45 |
46 | assert fb_left.keys() == fb_right.keys()
47 | for values_left, values_right in zip(fb_left.values(), fb_right.values()):
48 | assert (values_left == values_right).all()
49 |
50 |
51 | def test_valid_data_from_file(init_params):
52 | """Compare FBG data with old simulator"""
53 | units = SiUnits.MILLIMETERS
54 | ref_sim = OSASimulation(
55 | filename="sample/tut-export-limited.txt",
56 | NumberFBG=init_params["fbg_count"],
57 | FBGLength=init_params["fbg_length"],
58 | Tolerance=init_params["tolerance"],
59 | SkipRow=8,
60 | FBGPosition=init_params["fbg_positions"],
61 | InputUnits=units,
62 | )
63 | ref_data = ref_sim.FBGArray
64 |
65 | simu = OsaSimulator(**init_params)
66 | data = simu.from_file("sample/tut-export-limited.txt", units=units)
67 | assert_fbg_equals(ref_data, data)
68 |
69 |
70 | def test_undeformed_fbg(init_params):
71 | units = SiUnits.MILLIMETERS
72 | ## Prepare reference simulation
73 | ref_sim = OSASimulation(
74 | filename="sample/tut-export-limited.txt",
75 | NumberFBG=init_params["fbg_count"],
76 | FBGLength=init_params["fbg_length"],
77 | Tolerance=init_params["tolerance"],
78 | SkipRow=8,
79 | FBGPosition=init_params["fbg_positions"],
80 | InputUnits=units, # 0 -> meters, 1 -> mm
81 | )
82 | ref_sim.UndeformedFBG(
83 | SimulationResolution=init_params["resolution"],
84 | MinBandWidth=init_params["min_bandwidth"],
85 | MaxBandWidth=init_params["max_bandwidth"],
86 | InitialRefractiveIndex=init_params["initial_refractive_index"],
87 | MeanChangeRefractiveIndex=init_params["mean_change_refractive_index"],
88 | FringeVisibility=init_params["fringe_visibility"],
89 | DirectionalRefractiveP11=init_params["directional_refractive_p11"],
90 | DirectionalRefractiveP12=init_params["directional_refractive_p12"],
91 | PoissonsCoefficient=init_params["poissons_coefficient"],
92 | FBGOriginalWavel=init_params["original_wavelengths"],
93 | )
94 | ref_data = ref_sim.OReflect
95 |
96 | ## Prepare simulation to be tested
97 | simu = OsaSimulator(**init_params)
98 | simu.from_file("sample/tut-export-limited.txt", units=units)
99 | data = simu.undeformed_fbg()
100 |
101 | ## Compare results
102 | assert data["wavelength"] == ref_data["wavelength"]
103 | assert data["reflec"] == ref_data["reflec"]
104 |
105 |
106 | def test_deformed_fbg(init_params):
107 | # initial params
108 | units = SiUnits.MILLIMETERS
109 |
110 | ## Prepare reference simulation
111 | ref_sim = OSASimulation(
112 | filename="sample/tut-export-limited.txt",
113 | NumberFBG=init_params["fbg_count"],
114 | FBGLength=init_params["fbg_length"],
115 | Tolerance=init_params["tolerance"],
116 | SkipRow=8,
117 | FBGPosition=init_params["fbg_positions"],
118 | InputUnits=units, # 0 -> meters, 1 -> mm
119 | )
120 | ref_sim.DeformedFBG(
121 | SimulationResolution=init_params["resolution"],
122 | MinBandWidth=init_params["min_bandwidth"],
123 | MaxBandWidth=init_params["max_bandwidth"],
124 | AmbientTemperature=init_params["ambient_temperature"],
125 | InitialRefractiveIndex=init_params["initial_refractive_index"],
126 | MeanChangeRefractiveIndex=init_params["mean_change_refractive_index"],
127 | FringeVisibility=init_params["fringe_visibility"],
128 | DirectionalRefractiveP11=init_params["directional_refractive_p11"],
129 | DirectionalRefractiveP12=init_params["directional_refractive_p12"],
130 | YoungsModule=init_params["youngs_mod"],
131 | PoissonsCoefficient=init_params["poissons_coefficient"],
132 | ThermoOptic=init_params["thermo_optic"],
133 | EmulateTemperature=init_params["emulate_temperature"],
134 | FiberThermalExpansionCoefficient=init_params["fiber_expansion_coefficient"],
135 | HostThermalExpansionCoefficient=init_params["host_expansion_coefficient"],
136 | FBGOriginalWavel=init_params["original_wavelengths"],
137 | StrainType=StrainTypes.NON_UNIFORM,
138 | StressType=StressTypes.INCLUDED,
139 | )
140 | ref_data = ref_sim.DReflect
141 | ref_Y_data = ref_sim.YReflect
142 | ref_Z_data = ref_sim.ZReflect
143 |
144 | ## Prepare simulation to be tested
145 | simu = OsaSimulator(**init_params)
146 | simu.from_file("sample/tut-export-limited.txt", units=units)
147 | data = simu.deformed_fbg(
148 | strain_type=StrainTypes.NON_UNIFORM,
149 | stress_type=StressTypes.INCLUDED,
150 | )
151 |
152 | assert data["wavelength"] == ref_data["wavelength"]
153 | assert np.array_equal(data["reflec"], ref_data["reflec"])
154 |
155 | assert np.array_equal(data["Y_split"], ref_Y_data["reflec"])
156 | assert np.array_equal(data["Z_split"], ref_Z_data["reflec"])
157 |
158 |
159 | def test_output_sum(init_params):
160 | # initial params
161 | units = SiUnits.MILLIMETERS
162 |
163 | ## Prepare reference simulation
164 | ref_sim = OSASimulation(
165 | filename="sample/tut-export-limited.txt",
166 | NumberFBG=init_params["fbg_count"],
167 | FBGLength=init_params["fbg_length"],
168 | Tolerance=init_params["tolerance"],
169 | SkipRow=8,
170 | FBGPosition=init_params["fbg_positions"],
171 | InputUnits=units, # 0 -> meters, 1 -> mm
172 | )
173 | ref_sim.FBGOutputSum(
174 | AmbientTemperature=init_params["ambient_temperature"],
175 | InitialRefractiveIndex=init_params["initial_refractive_index"],
176 | FringeVisibility=init_params["fringe_visibility"],
177 | DirectionalRefractiveP11=init_params["directional_refractive_p11"],
178 | DirectionalRefractiveP12=init_params["directional_refractive_p12"],
179 | YoungsModule=init_params["youngs_mod"],
180 | PoissonsCoefficient=init_params["poissons_coefficient"],
181 | ThermoOptic=init_params["thermo_optic"],
182 | StrainType=StrainTypes.NON_UNIFORM,
183 | StressType=StressTypes.INCLUDED,
184 | EmulateTemperature=init_params["emulate_temperature"],
185 | FiberThermalExpansionCoefficient=init_params["fiber_expansion_coefficient"],
186 | HostThermalExpansionCoefficient=init_params["host_expansion_coefficient"],
187 | FBGOriginalWavel=init_params["original_wavelengths"],
188 | )
189 | ref_data = ref_sim.FBGOutSum
190 | ref_fbg_stats = ref_sim._FBGmaxmin
191 |
192 | ## Prepare simulation to be tested
193 | simu = OsaSimulator(**init_params)
194 | simu.from_file("sample/tut-export-limited.txt", units=units)
195 | data = simu.compute_fbg_shifts_and_widths(
196 | strain_type=StrainTypes.NON_UNIFORM,
197 | stress_type=StressTypes.INCLUDED,
198 | )
199 | fbg_stats = simu._fbg_stats
200 |
201 | ## Assert starting stats are equal too
202 | for fkey in fbg_stats.keys():
203 | stats = fbg_stats[fkey]
204 | ref_stats = ref_fbg_stats[fkey]
205 | for measure in stats.keys():
206 | assert np.isclose(stats[measure], ref_stats[measure])
207 |
208 | assert data.keys() == ref_data.keys()
209 | for fkey in data.keys():
210 | wave_shift = data[fkey]["wave_shift"]
211 | assert len(ref_data[fkey]["WaveShift"]) == 1
212 | ref_wave_shift = ref_data[fkey]["WaveShift"][0]
213 | assert np.isclose(wave_shift, ref_wave_shift)
214 |
215 | wave_shift = data[fkey]["wave_width"]
216 | assert len(ref_data[fkey]["WaveWidth"]) == 1
217 | ref_wave_shift = ref_data[fkey]["WaveWidth"][0]
218 | assert np.isclose(wave_shift, ref_wave_shift)
219 |
--------------------------------------------------------------------------------
/translation/messages-en.po:
--------------------------------------------------------------------------------
1 | # English translations for fbg-simulation-pyqt package.
2 | # Copyright (C) 2023 Codruta Toadere
3 | # This file is distributed under the same license as the fbg-simulation-pyqt package.
4 | # Codruta Toadere , 2023.
5 | #
6 | msgid ""
7 | msgstr ""
8 | "Project-Id-Version: fbg-simulation-pyqt v2.0\n"
9 | "Report-Msgid-Bugs-To: codrutatoadere@gmail.com\n"
10 | "POT-Creation-Date: 2023-08-24 07:25+0300\n"
11 | "PO-Revision-Date: 2023-08-20 18:28+0300\n"
12 | "Last-Translator: Codruta Toadere \n"
13 | "Language-Team: English\n"
14 | "Language: en_US\n"
15 | "MIME-Version: 1.0\n"
16 | "Content-Type: text/plain; charset=ASCII\n"
17 | "Content-Transfer-Encoding: 8bit\n"
18 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19 |
20 | #: gui/main_window.py:514
21 | msgid "A simulator session is already running."
22 | msgstr "A simulator session is already running."
23 |
24 | #: gui/main_window.py:326
25 | msgid "Add"
26 | msgstr "Add"
27 |
28 | #: gui/main_window.py:207
29 | msgid "Ambient temperature"
30 | msgstr "Ambient temperature"
31 |
32 | #: gui/main_window.py:104
33 | msgid "Apply conversion from m to mm"
34 | msgstr "Apply conversion from m to mm"
35 |
36 | #: gui/main_window.py:499
37 | msgid "At least one wavelength is above the maximum bandwidth setting."
38 | msgstr "At least one wavelength is above the maximum bandwidth setting."
39 |
40 | #: gui/main_window.py:497
41 | msgid "At least one wavelength is below the minimum bandwidth setting."
42 | msgstr "At least one wavelength is below the minimum bandwidth setting."
43 |
44 | #: gui/main_window.py:336
45 | msgid "Auto"
46 | msgstr "Auto"
47 |
48 | #: gui/main_window.py:218
49 | msgid "Average variation in refractive index"
50 | msgstr "Average variation in refractive index"
51 |
52 | #: gui/plot_window.py:105
53 | msgid "Axis control"
54 | msgstr "Axis control"
55 |
56 | #: gui/main_window.py:127
57 | msgid "Choose a simulation type"
58 | msgstr "Choose a simulation type"
59 |
60 | #: gui/main_window.py:93
61 | msgid "Choose file"
62 | msgstr "Choose file"
63 |
64 | #: gui/main_window.py:406
65 | msgid "Clear log"
66 | msgstr "Clear log"
67 |
68 | #: gui/plot_window.py:266
69 | msgid "Deformed FBG Spectrum"
70 | msgstr "Deformed FBG Spectrum"
71 |
72 | #: gui/main_window.py:432
73 | msgid "ERROR"
74 | msgstr "ERROR"
75 |
76 | #: gui/main_window.py:164
77 | msgid "Emulate model temperature"
78 | msgstr "Emulate model temperature"
79 |
80 | #: gui/main_window.py:161
81 | msgid "Emulation options"
82 | msgstr "Emulation options"
83 |
84 | #: gui/plot_window.py:155
85 | msgid "Enable panning"
86 | msgstr "Enable panning"
87 |
88 | #: gui/main_window.py:211
89 | msgid "Fiber attributes (advanced mode)"
90 | msgstr "Fiber attributes (advanced mode)"
91 |
92 | #: gui/main_window.py:236
93 | msgid "Fiber thermal expansion coefficient"
94 | msgstr "Fiber thermal expansion coefficient"
95 |
96 | #: gui/main_window.py:221
97 | msgid "Fringe visibility"
98 | msgstr "Fringe visibility"
99 |
100 | #: gui/plot_window.py:90
101 | msgid "Grid"
102 | msgstr "Grid"
103 |
104 | #: gui/main_window.py:172
105 | msgid "Host thermal expansion coefficient"
106 | msgstr "Host thermal expansion coefficient"
107 |
108 | #: gui/main_window.py:103
109 | msgid "If distances are not expressed in millimeters [mm]"
110 | msgstr "If distances are not expressed in millimeters [mm]"
111 |
112 | #: gui/plot_window.py:303
113 | msgid "Images"
114 | msgstr "Images"
115 |
116 | #: gui/main_window.py:147
117 | msgid "Include stress"
118 | msgstr "Include stress"
119 |
120 | #: gui/main_window.py:381
121 | msgid "Include the undeformed FBG reflected signal"
122 | msgstr "Include the undeformed FBG reflected signal"
123 |
124 | #: gui/main_window.py:215
125 | msgid "Initial refractive index"
126 | msgstr "Initial refractive index"
127 |
128 | #: gui/plot_window.py:89
129 | msgid "Legend"
130 | msgstr "Legend"
131 |
132 | #: gui/plot_window.py:177
133 | msgid "Line properties"
134 | msgstr "Line properties"
135 |
136 | #: gui/main_window.py:427
137 | msgid "Load data from"
138 | msgstr "Load data from"
139 |
140 | #: gui/main_window.py:89
141 | msgid "Load strain / stress data from file"
142 | msgstr "Load strain / stress data from file"
143 |
144 | #: gui/main_window.py:130
145 | msgid "Longitudinal strain"
146 | msgstr "Longitudinal strain"
147 |
148 | #: gui/main_window.py:204
149 | msgid "Maximum bandwidth"
150 | msgstr "Maximum bandwidth"
151 |
152 | #: gui/main_window.py:399
153 | msgid "Message log"
154 | msgstr "Message log"
155 |
156 | #: gui/main_window.py:201
157 | msgid "Minimum bandwidth"
158 | msgstr "Minimum bandwidth"
159 |
160 | #: gui/main_window.py:136
161 | msgid "Non-uniform"
162 | msgstr "Non-uniform"
163 |
164 | #: gui/main_window.py:133 gui/main_window.py:150
165 | msgid "None"
166 | msgstr "None"
167 |
168 | #: gui/main_window.py:299
169 | msgid "Number of FBG sensors"
170 | msgstr "Number of FBG sensors"
171 |
172 | #: gui/main_window.py:385
173 | msgid "Open simulation results"
174 | msgstr "Open simulation results"
175 |
176 | #: gui/main_window.py:307
177 | msgid "Original wavelengths"
178 | msgstr "Original wavelengths"
179 |
180 | #: gui/main_window.py:356
181 | msgid "Please enter a value for FBG"
182 | msgstr "Please enter a value for FBG"
183 |
184 | #: gui/plot_window.py:36
185 | msgid "Plot FBG Spectrum"
186 | msgstr "Plot FBG Spectrum"
187 |
188 | #: gui/plot_window.py:86
189 | msgid "Plot options"
190 | msgstr "Plot options"
191 |
192 | #: gui/main_window.py:224 gui/main_window.py:227
193 | msgid "Pockel's elasto-optic coefficients"
194 | msgstr "Pockel's elasto-optic coefficients"
195 |
196 | #: gui/main_window.py:233
197 | msgid "Poisson's coefficient"
198 | msgstr "Poisson's coefficient"
199 |
200 | #: gui/main_window.py:304
201 | msgid "Positions of FBG sensors (distance from the start)"
202 | msgstr "Positions of FBG sensors (distance from the start)"
203 |
204 | #: gui/plot_window.py:130 gui/plot_window.py:286
205 | msgid "Reflectivity"
206 | msgstr "Reflectivity"
207 |
208 | #: gui/main_window.py:328
209 | msgid "Remove"
210 | msgstr "Remove"
211 |
212 | #: gui/plot_window.py:301
213 | msgid "Save FBG Spectrum Plot"
214 | msgstr "Save FBG Spectrum Plot"
215 |
216 | #: gui/plot_window.py:72
217 | msgid "Save picture"
218 | msgstr "Save picture"
219 |
220 | #: gui/main_window.py:300
221 | msgid "Sensor length"
222 | msgstr "Sensor length"
223 |
224 | #: gui/main_window.py:502
225 | msgid "Sensors count ({}) and original wavelengths count ({}) must be equal."
226 | msgstr "Sensors count ({}) and original wavelengths count ({}) must be equal."
227 |
228 | #: gui/plot_window.py:223
229 | msgid "Shift"
230 | msgstr "Shift"
231 |
232 | #: gui/plot_window.py:195
233 | msgid "Simulated color"
234 | msgstr "Simulated color"
235 |
236 | #: gui/main_window.py:539
237 | msgid "Simulation completed successfully."
238 | msgstr "Simulation completed successfully."
239 |
240 | #: gui/main_window.py:534
241 | msgid "Simulation has failed, reason: {}"
242 | msgstr "Simulation has failed, reason: {}"
243 |
244 | #: gui/plot_window.py:215
245 | msgid "Simulation output"
246 | msgstr "Simulation output"
247 |
248 | #: gui/main_window.py:195
249 | msgid "Simulation parameters"
250 | msgstr "Simulation parameters"
251 |
252 | #: gui/main_window.py:199
253 | msgid "Simulation resolution"
254 | msgstr "Simulation resolution"
255 |
256 | #: gui/main_window.py:376
257 | msgid "Spectrum simulation"
258 | msgstr "Spectrum simulation"
259 |
260 | #: gui/plot_window.py:91
261 | msgid "Split waveform (Birefringence)"
262 | msgstr "Split waveform (Birefringence)"
263 |
264 | #: gui/main_window.py:382
265 | msgid "Start simulation"
266 | msgstr "Start simulation"
267 |
268 | #: gui/main_window.py:544
269 | msgid "There is no data to show, please run the simulation first."
270 | msgstr "There is no data to show, please run the simulation first."
271 |
272 | #: gui/main_window.py:239
273 | msgid "Thermo-optic coefficient"
274 | msgstr "Thermo-optic coefficient"
275 |
276 | #: gui/main_window.py:301
277 | msgid "Tolerance"
278 | msgstr "Tolerance"
279 |
280 | #: gui/main_window.py:152
281 | msgid "Transverse stress"
282 | msgstr "Transverse stress"
283 |
284 | #: gui/main_window.py:487
285 | msgid "Two consecutive FBG positions cannot be shorter than FBG length."
286 | msgstr "Two consecutive FBG positions cannot be shorter than FBG length."
287 |
288 | #: gui/plot_window.py:258
289 | msgid "Undeformed FBG Spectrum"
290 | msgstr "Undeformed FBG Spectrum"
291 |
292 | #: gui/plot_window.py:190
293 | msgid "Undeformed color"
294 | msgstr "Undeformed color"
295 |
296 | #: gui/main_window.py:135
297 | msgid "Uniform"
298 | msgstr "Uniform"
299 |
300 | #: gui/main_window.py:295
301 | msgid "Virtual Fiber Bragg Grating array configuration"
302 | msgstr "Virtual Fiber Bragg Grating array configuration"
303 |
304 | #: gui/plot_window.py:109 gui/plot_window.py:223 gui/plot_window.py:285
305 | msgid "Wavelength"
306 | msgstr "Wavelength"
307 |
308 | #: gui/plot_window.py:180
309 | msgid "Width"
310 | msgstr "Width"
311 |
312 | #: gui/plot_window.py:223
313 | msgid "Width Variation"
314 | msgstr "Width Variation"
315 |
316 | #: gui/plot_window.py:275
317 | msgid "Y-Wave Contribution"
318 | msgstr "Y-Wave Contribution"
319 |
320 | #: gui/main_window.py:230
321 | msgid "Young's module"
322 | msgstr "Young's module"
323 |
324 | #: gui/plot_window.py:282
325 | msgid "Z-Wave Contribution"
326 | msgstr "Z-Wave Contribution"
327 |
328 | #: gui/main_window.py:472
329 | msgid "is not a valid data file."
330 | msgstr "is not a valid data file."
331 |
332 | #: gui/main_window.py:304
333 | msgid "position"
334 | msgstr "position"
335 |
336 | #: gui/main_window.py:307
337 | msgid "wavelength"
338 | msgstr "wavelength"
339 |
--------------------------------------------------------------------------------
/translation/messages-ro.po:
--------------------------------------------------------------------------------
1 | # Romanian translations for fbg-simulation-pyqt package.
2 | # Copyright (C) 2023 Codruta Toadere
3 | # This file is distributed under the same license as the fbg-simulation-pyqt package.
4 | # Codruta Toadere , 2023.
5 | #
6 | msgid ""
7 | msgstr ""
8 | "Project-Id-Version: fbg-simulation-pyqt v2.0\n"
9 | "Report-Msgid-Bugs-To: codrutatoadere@gmail.com\n"
10 | "POT-Creation-Date: 2023-08-24 07:25+0300\n"
11 | "PO-Revision-Date: 2023-08-20 18:28+0300\n"
12 | "Last-Translator: Codruta Toadere \n"
13 | "Language-Team: Romanian \n"
14 | "Language: ro_RO\n"
15 | "MIME-Version: 1.0\n"
16 | "Content-Type: text/plain; charset=UTF-8\n"
17 | "Content-Transfer-Encoding: 8bit\n"
18 | "Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;\n"
19 |
20 | #: gui/main_window.py:514
21 | msgid "A simulator session is already running."
22 | msgstr "O sesiune de simulare este deja în desfășurare."
23 |
24 | #: gui/main_window.py:326
25 | msgid "Add"
26 | msgstr "Adaugă"
27 |
28 | #: gui/main_window.py:207
29 | msgid "Ambient temperature"
30 | msgstr "Temperatură ambientală"
31 |
32 | #: gui/main_window.py:104
33 | msgid "Apply conversion from m to mm"
34 | msgstr "Aplică conversia din m în mm"
35 |
36 | #: gui/main_window.py:499
37 | msgid "At least one wavelength is above the maximum bandwidth setting."
38 | msgstr "Cel puțin o lungime de undă este peste limita de lățime de bandă maximă."
39 |
40 | #: gui/main_window.py:497
41 | msgid "At least one wavelength is below the minimum bandwidth setting."
42 | msgstr "Cel puțin o lungime de undă este sub limita de lățime de bandă minimă."
43 |
44 | #: gui/main_window.py:336
45 | msgid "Auto"
46 | msgstr "Auto"
47 |
48 | #: gui/main_window.py:218
49 | msgid "Average variation in refractive index"
50 | msgstr "Variația medie a indicelui de refracție"
51 |
52 | #: gui/plot_window.py:105
53 | msgid "Axis control"
54 | msgstr "Controlul axelor"
55 |
56 | #: gui/main_window.py:127
57 | msgid "Choose a simulation type"
58 | msgstr "Alegeți un tip de simulare"
59 |
60 | #: gui/main_window.py:93
61 | msgid "Choose file"
62 | msgstr "Alegeți fișierul"
63 |
64 | #: gui/main_window.py:406
65 | msgid "Clear log"
66 | msgstr "Șterge jurnalul"
67 |
68 | #: gui/plot_window.py:266
69 | msgid "Deformed FBG Spectrum"
70 | msgstr "Spectrul FBG deformat"
71 |
72 | #: gui/main_window.py:432
73 | msgid "ERROR"
74 | msgstr "EROARE"
75 |
76 | #: gui/main_window.py:164
77 | msgid "Emulate model temperature"
78 | msgstr "Emulează temperatura modelului"
79 |
80 | #: gui/main_window.py:161
81 | msgid "Emulation options"
82 | msgstr "Opțiuni de emulare"
83 |
84 | #: gui/plot_window.py:155
85 | msgid "Enable panning"
86 | msgstr "Activeaza panoramare"
87 |
88 | #: gui/main_window.py:211
89 | msgid "Fiber attributes (advanced mode)"
90 | msgstr "Atributele fibrei (mod avansat)"
91 |
92 | #: gui/main_window.py:236
93 | msgid "Fiber thermal expansion coefficient"
94 | msgstr "Coeficientul de dilatare termică a fibrei"
95 |
96 | #: gui/main_window.py:221
97 | msgid "Fringe visibility"
98 | msgstr "Vizibilitatea franjelor"
99 |
100 | #: gui/plot_window.py:90
101 | msgid "Grid"
102 | msgstr "Grilă"
103 |
104 | #: gui/main_window.py:172
105 | msgid "Host thermal expansion coefficient"
106 | msgstr "Coeficientul de dilatare termică a gazdei"
107 |
108 | #: gui/main_window.py:103
109 | msgid "If distances are not expressed in millimeters [mm]"
110 | msgstr "Dacă distanțele nu sunt exprimate în milimetri [mm]"
111 |
112 | #: gui/plot_window.py:303
113 | msgid "Images"
114 | msgstr "Imagini"
115 |
116 | #: gui/main_window.py:147
117 | msgid "Include stress"
118 | msgstr "Tensiune"
119 |
120 | #: gui/main_window.py:381
121 | msgid "Include the undeformed FBG reflected signal"
122 | msgstr "Include semnalul FBG reflectat nedeformat"
123 |
124 | #: gui/main_window.py:215
125 | msgid "Initial refractive index"
126 | msgstr "Indice de refracție inițial"
127 |
128 | #: gui/plot_window.py:89
129 | msgid "Legend"
130 | msgstr "Legendă"
131 |
132 | #: gui/plot_window.py:177
133 | msgid "Line properties"
134 | msgstr "Proprietăți linie"
135 |
136 | #: gui/main_window.py:427
137 | msgid "Load data from"
138 | msgstr "Încarcă datele din"
139 |
140 | #: gui/main_window.py:89
141 | msgid "Load strain / stress data from file"
142 | msgstr "Încarcă datele de deformare / tensiune din fișier"
143 |
144 | #: gui/main_window.py:130
145 | msgid "Longitudinal strain"
146 | msgstr "Deformare longitudinală"
147 |
148 | #: gui/main_window.py:204
149 | msgid "Maximum bandwidth"
150 | msgstr "Lățime de bandă maximă"
151 |
152 | #: gui/main_window.py:399
153 | msgid "Message log"
154 | msgstr "Jurnal de mesaje"
155 |
156 | #: gui/main_window.py:201
157 | msgid "Minimum bandwidth"
158 | msgstr "Lățime de bandă minimă"
159 |
160 | #: gui/main_window.py:136
161 | msgid "Non-uniform"
162 | msgstr "Neuniform"
163 |
164 | #: gui/main_window.py:133 gui/main_window.py:150
165 | msgid "None"
166 | msgstr "Niciuna"
167 |
168 | #: gui/main_window.py:299
169 | msgid "Number of FBG sensors"
170 | msgstr "Numărul de senzori FBG"
171 |
172 | #: gui/main_window.py:385
173 | msgid "Open simulation results"
174 | msgstr "Deschideți rezultatele simulării"
175 |
176 | #: gui/main_window.py:307
177 | msgid "Original wavelengths"
178 | msgstr "Lungimi de undă originale"
179 |
180 | #: gui/main_window.py:356
181 | msgid "Please enter a value for FBG"
182 | msgstr "Introduceți o valoare pentru FBG"
183 |
184 | #: gui/plot_window.py:36
185 | msgid "Plot FBG Spectrum"
186 | msgstr "Trasează spectrul FBG"
187 |
188 | #: gui/plot_window.py:86
189 | msgid "Plot options"
190 | msgstr "Opțiuni de trasare"
191 |
192 | #: gui/main_window.py:224 gui/main_window.py:227
193 | msgid "Pockel's elasto-optic coefficients"
194 | msgstr "Coeficienții elasto-optici Pockel"
195 |
196 | #: gui/main_window.py:233
197 | msgid "Poisson's coefficient"
198 | msgstr "Coeficientul lui Poisson"
199 |
200 | #: gui/main_window.py:304
201 | msgid "Positions of FBG sensors (distance from the start)"
202 | msgstr "Pozițiile senzorilor FBG (distanța de la început)"
203 |
204 | #: gui/plot_window.py:130 gui/plot_window.py:286
205 | msgid "Reflectivity"
206 | msgstr "Reflectivitate"
207 |
208 | #: gui/main_window.py:328
209 | msgid "Remove"
210 | msgstr "Elimină"
211 |
212 | #: gui/plot_window.py:301
213 | msgid "Save FBG Spectrum Plot"
214 | msgstr "Salvează graficul spectrului FBG"
215 |
216 | #: gui/plot_window.py:72
217 | msgid "Save picture"
218 | msgstr "Salvează imaginea"
219 |
220 | #: gui/main_window.py:300
221 | msgid "Sensor length"
222 | msgstr "Lungimea senzorului"
223 |
224 | #: gui/main_window.py:502
225 | msgid "Sensors count ({}) and original wavelengths count ({}) must be equal."
226 | msgstr "Numărul de senzori ({}) și numărul de lungimi de undă originale ({}) trebuie să fie egale."
227 |
228 | #: gui/plot_window.py:223
229 | msgid "Shift"
230 | msgstr "Deplasare"
231 |
232 | #: gui/plot_window.py:195
233 | msgid "Simulated color"
234 | msgstr "Culoare spectru simulat"
235 |
236 | #: gui/main_window.py:539
237 | msgid "Simulation completed successfully."
238 | msgstr "Simularea s-a încheiat cu succes."
239 |
240 | #: gui/main_window.py:534
241 | msgid "Simulation has failed, reason: {}"
242 | msgstr "Simularea a eșuat, motiv: {}"
243 |
244 | #: gui/plot_window.py:215
245 | msgid "Simulation output"
246 | msgstr "Rezultat simulare"
247 |
248 | #: gui/main_window.py:195
249 | msgid "Simulation parameters"
250 | msgstr "Parametrii simulării"
251 |
252 | #: gui/main_window.py:199
253 | msgid "Simulation resolution"
254 | msgstr "Rezoluție simulare"
255 |
256 | #: gui/main_window.py:376
257 | msgid "Spectrum simulation"
258 | msgstr "Simulare spectru"
259 |
260 | #: gui/plot_window.py:91
261 | msgid "Split waveform (Birefringence)"
262 | msgstr "Separă forma de undă (Birefringență)"
263 |
264 | #: gui/main_window.py:382
265 | msgid "Start simulation"
266 | msgstr "Pornește simularea"
267 |
268 | #: gui/main_window.py:544
269 | msgid "There is no data to show, please run the simulation first."
270 | msgstr "Nu există date de afișat, vă rugăm să rulați simularea mai întâi."
271 |
272 | #: gui/main_window.py:239
273 | msgid "Thermo-optic coefficient"
274 | msgstr "Coeficient termo-optic"
275 |
276 | #: gui/main_window.py:301
277 | msgid "Tolerance"
278 | msgstr "Toleranță"
279 |
280 | #: gui/main_window.py:152
281 | msgid "Transverse stress"
282 | msgstr "Tensiune transversală"
283 |
284 | #: gui/main_window.py:487
285 | msgid "Two consecutive FBG positions cannot be shorter than FBG length."
286 | msgstr "Două poziții consecutive FBG nu pot fi mai scurte decât lungimea FBG."
287 |
288 | #: gui/plot_window.py:258
289 | msgid "Undeformed FBG Spectrum"
290 | msgstr "Spectru FBG nedeformat"
291 |
292 | #: gui/plot_window.py:190
293 | msgid "Undeformed color"
294 | msgstr "Culoare spectru nedeformat"
295 |
296 | #: gui/main_window.py:135
297 | msgid "Uniform"
298 | msgstr "Uniform"
299 |
300 | #: gui/main_window.py:295
301 | msgid "Virtual Fiber Bragg Grating array configuration"
302 | msgstr "Configurație virtuală a rețelei Fiber Bragg Grating"
303 |
304 | #: gui/plot_window.py:109 gui/plot_window.py:223 gui/plot_window.py:285
305 | msgid "Wavelength"
306 | msgstr "Lungime de undă"
307 |
308 | #: gui/plot_window.py:180
309 | msgid "Width"
310 | msgstr "Grosime"
311 |
312 | #: gui/plot_window.py:223
313 | msgid "Width Variation"
314 | msgstr "Variație de lățime"
315 |
316 | #: gui/plot_window.py:275
317 | msgid "Y-Wave Contribution"
318 | msgstr "Contribuție Y-Wave"
319 |
320 | #: gui/main_window.py:230
321 | msgid "Young's module"
322 | msgstr "Modul lui Young"
323 |
324 | #: gui/plot_window.py:282
325 | msgid "Z-Wave Contribution"
326 | msgstr "Contribuție Z-Wave"
327 |
328 | #: gui/main_window.py:472
329 | msgid "is not a valid data file."
330 | msgstr "nu este un fișier de date valid."
331 |
332 | #: gui/main_window.py:304
333 | msgid "position"
334 | msgstr "poziție"
335 |
336 | #: gui/main_window.py:307
337 | msgid "wavelength"
338 | msgstr "lungime de undă"
339 |
--------------------------------------------------------------------------------
/gui/plot_window.py:
--------------------------------------------------------------------------------
1 | import locale
2 |
3 | from PySide6.QtCore import Qt
4 | from PySide6.QtWidgets import (
5 | QDialog,
6 | QWidget,
7 | QHBoxLayout,
8 | QLabel,
9 | QVBoxLayout,
10 | QGroupBox,
11 | QCheckBox,
12 | QGridLayout,
13 | QSpinBox,
14 | QDoubleSpinBox,
15 | QComboBox,
16 | QPushButton,
17 | QTableView,
18 | QHeaderView,
19 | QFileDialog,
20 | )
21 | from PySide6.QtGui import QStandardItem, QStandardItemModel
22 | import matplotlib
23 |
24 | matplotlib.use("QtAgg")
25 | import matplotlib.pyplot as plt
26 | from matplotlib.backends.backend_qtagg import (
27 | FigureCanvasQTAgg as FigureCanvas,
28 | NavigationToolbar2QT as NavigationToolbar,
29 | )
30 |
31 |
32 | class SpectrumView(QDialog):
33 | USE_COLORS = "orange,red,blue,green,purple,black".split(",")
34 |
35 | def __init__(self, parent: QWidget, data: dict):
36 | super().__init__(parent)
37 | self.setWindowTitle(_("Plot FBG Spectrum"))
38 | self.setGeometry(512, 256, 1280, 768)
39 |
40 | self.data = data
41 |
42 | self.setup_ui()
43 |
44 | def setup_ui(self):
45 | layout = QHBoxLayout(self)
46 |
47 | plot_layout = self.make_plot_layout()
48 | side_layout = self.make_side_layout()
49 |
50 | layout.addLayout(plot_layout, 68)
51 | layout.addLayout(side_layout, 32)
52 |
53 | self.refresh_plot()
54 |
55 | def make_plot_layout(self):
56 | layout = QVBoxLayout()
57 |
58 | self.fig, self.ax = plt.subplots()
59 | self.canvas = FigureCanvas(self.fig)
60 | self.toolbar = NavigationToolbar(self.canvas, self)
61 | self.toolbar.hide()
62 |
63 | layout.addWidget(self.canvas)
64 | return layout
65 |
66 | def make_side_layout(self):
67 | options_group = self.make_options_group()
68 | axis_group = self.make_axis_group()
69 | line_group = self.make_line_group()
70 |
71 | summary_group = self.make_summary_group()
72 |
73 | save_button = QPushButton(_("Save picture"))
74 | save_button.clicked.connect(self.savePlotFigure)
75 |
76 | layout = QVBoxLayout()
77 | layout.addWidget(options_group)
78 | layout.addWidget(axis_group)
79 | layout.addWidget(line_group)
80 | layout.addWidget(summary_group)
81 | layout.addStretch()
82 | layout.addWidget(save_button)
83 |
84 | return layout
85 |
86 | def make_options_group(self):
87 | options_group = QGroupBox(_("Plot options"))
88 | options_group_layout = QVBoxLayout()
89 |
90 | self.legend = QCheckBox(_("Legend"), options_group, checked=True)
91 | self.grid = QCheckBox(_("Grid"), options_group, checked=False)
92 | self.split = QCheckBox(_("Split waveform (Birefringence)"), options_group, checked=False)
93 |
94 | self.legend.clicked.connect(self.refresh_plot)
95 | self.grid.clicked.connect(self.refresh_plot)
96 | self.split.clicked.connect(self.refresh_plot)
97 |
98 | options_group_layout.addWidget(self.legend)
99 | options_group_layout.addWidget(self.grid)
100 | options_group_layout.addWidget(self.split)
101 | options_group.setLayout(options_group_layout)
102 |
103 | return options_group
104 |
105 | def make_axis_group(self):
106 | axis_group = QGroupBox(_("Axis control"))
107 | axis_group_layout = QGridLayout()
108 |
109 | x_between = QLabel("↔", axis_group)
110 | x_label = QLabel(_("Wavelength"), axis_group)
111 | self.xmin = QSpinBox(
112 | axis_group,
113 | minimum=1000,
114 | maximum=2000,
115 | singleStep=10,
116 | value=1500,
117 | suffix=" nm",
118 | alignment=Qt.AlignmentFlag.AlignRight,
119 | )
120 | self.xmax = QSpinBox(
121 | axis_group,
122 | minimum=1000,
123 | maximum=2000,
124 | singleStep=10,
125 | value=1600,
126 | suffix=" nm",
127 | alignment=Qt.AlignmentFlag.AlignRight,
128 | )
129 |
130 | y_between = QLabel("↔", axis_group)
131 | y_label = QLabel(_("Reflectivity"), axis_group)
132 | self.ymin = QDoubleSpinBox(
133 | axis_group,
134 | minimum=-0.5,
135 | maximum=2.0,
136 | singleStep=0.1,
137 | value=-0.1,
138 | suffix=" R",
139 | alignment=Qt.AlignmentFlag.AlignRight,
140 | )
141 | self.ymax = QDoubleSpinBox(
142 | axis_group,
143 | minimum=-0.5,
144 | maximum=2.0,
145 | singleStep=0.1,
146 | value=1.2,
147 | suffix=" R",
148 | alignment=Qt.AlignmentFlag.AlignRight,
149 | )
150 |
151 | self.xmin.valueChanged.connect(self.refresh_plot)
152 | self.xmax.valueChanged.connect(self.refresh_plot)
153 | self.ymin.valueChanged.connect(self.refresh_plot)
154 | self.ymax.valueChanged.connect(self.refresh_plot)
155 |
156 | enable_panning = QCheckBox(_("Enable panning"), axis_group, checked=False)
157 | enable_panning.clicked.connect(self.toolbar.pan)
158 |
159 | axis_group_layout.addWidget(x_label, 0, 0)
160 | axis_group_layout.addWidget(self.xmin, 1, 0)
161 | axis_group_layout.addWidget(x_between, 1, 1)
162 | axis_group_layout.addWidget(self.xmax, 1, 2)
163 |
164 | axis_group_layout.addWidget(y_label, 2, 0)
165 | axis_group_layout.addWidget(self.ymin, 3, 0)
166 | axis_group_layout.addWidget(y_between, 3, 1)
167 | axis_group_layout.addWidget(self.ymax, 3, 2)
168 |
169 | axis_group_layout.addWidget(enable_panning, 4, 0, 1, 3)
170 |
171 | axis_group_layout.setColumnStretch(0, 3)
172 | axis_group_layout.setColumnStretch(2, 3)
173 | axis_group.setLayout(axis_group_layout)
174 |
175 | return axis_group
176 |
177 | def make_line_group(self):
178 | line_group = QGroupBox(_("Line properties"))
179 | line_group_layout = QGridLayout()
180 |
181 | line_width_label = QLabel(_("Width"), line_group)
182 | self.line_width = QDoubleSpinBox(
183 | line_group,
184 | minimum=0.1,
185 | maximum=5.0,
186 | singleStep=0.1,
187 | value=0.5,
188 | suffix=" pt",
189 | alignment=Qt.AlignmentFlag.AlignRight,
190 | )
191 | undeformed_color_label = QLabel(_("Undeformed color"), line_group)
192 | self.undeformed_color = QComboBox(line_group)
193 | self.undeformed_color.addItems(self.USE_COLORS)
194 | self.undeformed_color.setCurrentText("blue")
195 |
196 | simulated_color_label = QLabel(_("Simulated color"), line_group)
197 | self.simulated_color = QComboBox(line_group)
198 | self.simulated_color.addItems(self.USE_COLORS)
199 | self.simulated_color.setCurrentText("orange")
200 |
201 | self.line_width.valueChanged.connect(self.refresh_plot)
202 | self.undeformed_color.currentTextChanged.connect(self.refresh_plot)
203 | self.simulated_color.currentTextChanged.connect(self.refresh_plot)
204 |
205 | line_group_layout.addWidget(line_width_label, 0, 0)
206 | line_group_layout.addWidget(self.line_width, 0, 1)
207 | line_group_layout.addWidget(undeformed_color_label, 1, 0)
208 | line_group_layout.addWidget(self.undeformed_color, 1, 1)
209 | line_group_layout.addWidget(simulated_color_label, 2, 0)
210 | line_group_layout.addWidget(self.simulated_color, 2, 1)
211 | line_group.setLayout(line_group_layout)
212 |
213 | return line_group
214 |
215 | def make_summary_group(self):
216 | summary_group = QGroupBox(_("Simulation output"))
217 | summary_group_layout = QVBoxLayout()
218 |
219 | summary_table = QTableView()
220 |
221 | model = QStandardItemModel()
222 | summary_table.setModel(model)
223 |
224 | columns = [_("Wavelength"), _("Shift"), _("Width Variation")]
225 | model.setHorizontalHeaderLabels(columns)
226 | horizontal_header = summary_table.horizontalHeader()
227 | horizontal_header.setSectionResizeMode(QHeaderView.ResizeToContents)
228 |
229 | self.read_data_rows(model)
230 |
231 | summary_group_layout.addWidget(summary_table)
232 | summary_group.setLayout(summary_group_layout)
233 |
234 | return summary_group
235 |
236 | def read_data_rows(self, model):
237 | for i in range(self.data["params"]["fbg_count"]):
238 | key = f"FBG{i+1}"
239 | wave_length = locale.format_string(
240 | "%.0f nm", self.data["params"]["original_wavelengths"][i]
241 | )
242 | wave_shift = locale.format_string("%.15f nm", self.data["summary"][key]["wave_shift"])
243 | wave_width = locale.format_string("%.15f nm", self.data["summary"][key]["wave_width"])
244 | self.add_summary_row(model, [wave_length, wave_shift, wave_width])
245 |
246 | def add_summary_row(self, model, data):
247 | items = [QStandardItem(str(datum)) for datum in data]
248 | for item in items:
249 | item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
250 | model.appendRow(items)
251 |
252 | def refresh_plot(self):
253 | self.ax.clear()
254 |
255 | if self.data["undeformed"]:
256 | self.ax.plot(
257 | self.data["undeformed"]["wavelength"],
258 | self.data["undeformed"]["reflec"],
259 | color=self.undeformed_color.currentText(),
260 | linewidth=self.line_width.value(),
261 | label=_("Undeformed FBG Spectrum"),
262 | )
263 |
264 | self.ax.plot(
265 | self.data["deformed"]["wavelength"],
266 | self.data["deformed"]["reflec"],
267 | color=self.simulated_color.currentText(),
268 | linewidth=self.line_width.value(),
269 | label=_("Deformed FBG Spectrum"),
270 | )
271 |
272 | if self.split.isChecked():
273 | self.ax.plot(
274 | self.data["deformed"]["wavelength"],
275 | self.data["deformed"]["Y_split"],
276 | color="red",
277 | linewidth=self.line_width.value(),
278 | label=_("Y-Wave Contribution"),
279 | )
280 | self.ax.plot(
281 | self.data["deformed"]["wavelength"],
282 | self.data["deformed"]["Z_split"],
283 | color="green",
284 | linewidth=self.line_width.value(),
285 | label=_("Z-Wave Contribution"),
286 | )
287 |
288 | self.ax.set_xlabel("{} [nm]".format(_("Wavelength")))
289 | self.ax.set_ylabel("{} [R]".format(_("Reflectivity")))
290 | self.ax.set_xlim(xmin=self.xmin.value(), xmax=self.xmax.value())
291 | self.ax.set_ylim(ymin=self.ymin.value(), ymax=self.ymax.value())
292 |
293 | if self.legend.isChecked():
294 | self.ax.legend()
295 |
296 | if self.grid.isChecked():
297 | self.ax.grid()
298 |
299 | self.canvas.draw()
300 |
301 | def savePlotFigure(self):
302 | to_file, filter = QFileDialog.getSaveFileName(
303 | self,
304 | caption=_("Save FBG Spectrum Plot"),
305 | dir="./sample",
306 | filter="{} (*.png)".format(_("Images")),
307 | )
308 | if to_file:
309 | self.fig.savefig(to_file)
310 |
--------------------------------------------------------------------------------
/sample/tut-export.txt:
--------------------------------------------------------------------------------
1 | % Model:
2 | % Version: COMSOL 5.4.0.388
3 | % Date: Jan 12 2021, 23:17
4 | % Dimension: 1
5 | % Nodes: 101
6 | % Expressions: 7
7 | % Description: Logarithmic strain tensor, xx component, Logarithmic strain tensor, yy component, Logarithmic strain tensor, zz component, Stress tensor, x component, Stress tensor, y component, Stress tensor, z component, Temperature
8 | % cln1x solid.elogxx (1) solid.elogyy (1) solid.elogzz (1) solid.sx (N/m^2) solid.sy (N/m^2) solid.sz (N/m^2) T (K)
9 | 0.0000 0.0027498 3.0117E-7 -6.8871E-4 7.1716E7 1.4343E7 -1.1176E-8 293.15
10 | 0.0010000 0.0023298 -5.2143E-4 -4.5269E-4 5.8013E7 -1.4392E6 -9.6858E-8 293.15
11 | 0.0020000 0.0022514 -4.4574E-4 -4.5188E-4 5.6357E7 1.1539E5 -2.5891E-7 293.15
12 | 0.0030000 0.0022957 -4.6266E-4 -4.5846E-4 5.7407E7 -1.1237E5 -4.9174E-7 293.15
13 | 0.0040000 0.0022867 -4.5459E-4 -4.5782E-4 5.7188E7 26229 5.2154E-7 293.15
14 | 0.0050000 0.0022722 -4.5147E-4 -4.5448E-4 5.6796E7 866.05 4.8243E-7 293.15
15 | 0.0060000 0.0022539 -4.4617E-4 -4.5062E-4 5.6309E7 5856.7 -8.4378E-7 293.15
16 | 0.0070000 0.0022333 -4.4053E-4 -4.4616E-4 5.5756E7 1529.3 -1.3355E-6 293.15
17 | 0.0080000 0.0022121 -4.3437E-4 -4.4161E-4 5.5187E7 1907.0 -1.0114E-6 293.15
18 | 0.0090000 0.0021903 -4.2793E-4 -4.3688E-4 5.4597E7 1058.9 -2.5332E-7 293.15
19 | 0.010000 0.0021683 -4.2124E-4 -4.3207E-4 5.3997E7 -32.666 -3.3025E-6 293.15
20 | 0.011000 0.0021466 -4.1436E-4 -4.2731E-4 5.3402E7 440.31 -1.5646E-7 293.15
21 | 0.012000 0.0021249 -4.0732E-4 -4.2251E-4 5.2802E7 342.88 -6.4801E-6 293.15
22 | 0.013000 0.0021033 -4.0011E-4 -4.1768E-4 5.2199E7 -266.34 -4.2170E-6 293.15
23 | 0.014000 0.0020818 -3.9276E-4 -4.1287E-4 5.1599E7 -275.64 -2.3749E-6 293.15
24 | 0.015000 0.0020607 -3.8527E-4 -4.0810E-4 5.1001E7 278.21 -8.2031E-6 293.15
25 | 0.016000 0.0020394 -3.7764E-4 -4.0327E-4 5.0399E7 -278.82 -2.0862E-6 293.15
26 | 0.017000 0.0020184 -3.6989E-4 -3.9847E-4 4.9799E7 -278.59 1.5479E-6 293.15
27 | 0.018000 0.0019976 -3.6201E-4 -3.9369E-4 4.9201E7 277.12 -1.1528E-5 293.15
28 | 0.019000 0.0019767 -3.5402E-4 -3.8886E-4 4.8599E7 -278.05 2.5351E-6 293.15
29 | 0.020000 0.0019561 -3.4592E-4 -3.8406E-4 4.7999E7 -277.92 -5.7947E-6 293.15
30 | 0.021000 0.0019356 -3.3771E-4 -3.7929E-4 4.7401E7 277.68 -4.7348E-6 293.15
31 | 0.022000 0.0019151 -3.2940E-4 -3.7446E-4 4.6799E7 -277.81 3.5968E-6 293.15
32 | 0.023000 0.0018947 -3.2100E-4 -3.6965E-4 4.6199E7 -277.79 -1.1126E-5 293.15
33 | 0.024000 0.0018745 -3.1251E-4 -3.6488E-4 4.5601E7 277.77 -5.6252E-6 293.15
34 | 0.025000 0.0018542 -3.0393E-4 -3.6005E-4 4.4999E7 -277.78 -1.4998E-5 293.15
35 | 0.026000 0.0018341 -2.9527E-4 -3.5525E-4 4.4399E7 -277.78 -2.9696E-5 293.15
36 | 0.027000 0.0018142 -2.8654E-4 -3.5047E-4 4.3801E7 277.78 -5.2527E-6 293.15
37 | 0.028000 0.0017942 -2.7775E-4 -3.4567E-4 4.3201E7 277.78 1.6950E-5 293.15
38 | 0.029000 0.0017742 -2.6889E-4 -3.4084E-4 4.2599E7 -277.78 -3.4092E-5 293.15
39 | 0.030000 0.0017544 -2.5997E-4 -3.3607E-4 4.2001E7 277.78 -1.8673E-5 293.15
40 | 0.031000 0.0017346 -2.5100E-4 -3.3127E-4 4.1401E7 277.78 -2.8200E-5 293.15
41 | 0.032000 0.0017147 -2.4197E-4 -3.2644E-4 4.0799E7 -277.78 -1.0144E-5 293.15
42 | 0.033000 0.0016951 -2.3291E-4 -3.2167E-4 4.0201E7 277.78 -3.6996E-5 293.15
43 | 0.034000 0.0016755 -2.2380E-4 -3.1686E-4 3.9601E7 277.78 1.3024E-5 293.15
44 | 0.035000 0.0016557 -2.1466E-4 -3.1204E-4 3.8999E7 -277.78 2.9437E-5 293.15
45 | 0.036000 0.0016362 -2.0549E-4 -3.0726E-4 3.8401E7 277.78 -1.7652E-4 293.15
46 | 0.037000 0.0016167 -1.9630E-4 -3.0246E-4 3.7801E7 277.78 2.6179E-5 293.15
47 | 0.038000 0.0015970 -1.8708E-4 -2.9763E-4 3.7199E7 -277.78 4.3446E-5 293.15
48 | 0.039000 0.0015775 -1.7785E-4 -2.9283E-4 3.6599E7 -277.78 -9.6249E-5 293.15
49 | 0.040000 0.0015580 -1.6860E-4 -2.8805E-4 3.6001E7 277.78 -1.1721E-5 293.15
50 | 0.041000 0.0015384 -1.5934E-4 -2.8323E-4 3.5399E7 -277.78 -7.3165E-6 293.15
51 | 0.042000 0.0015189 -1.5008E-4 -2.7843E-4 3.4799E7 -277.78 2.0547E-5 293.15
52 | 0.043000 0.0014995 -1.4082E-4 -2.7365E-4 3.4201E7 277.78 -1.5945E-4 293.15
53 | 0.044000 0.0014799 -1.3157E-4 -2.6882E-4 3.3599E7 -277.78 -3.7741E-5 293.15
54 | 0.045000 0.0014603 -1.2232E-4 -2.6402E-4 3.2999E7 -277.78 4.5728E-6 293.15
55 | 0.046000 0.0014409 -1.1308E-4 -2.5925E-4 3.2401E7 277.78 -9.8095E-5 293.15
56 | 0.047000 0.0014212 -1.0385E-4 -2.5442E-4 3.1799E7 -277.78 1.0308E-4 293.15
57 | 0.048000 0.0014017 -9.4650E-5 -2.4962E-4 3.1199E7 -277.78 5.9400E-5 293.15
58 | 0.049000 0.0013822 -8.5467E-5 -2.4484E-4 3.0601E7 277.78 6.9027E-5 293.15
59 | 0.050000 0.0013625 -7.6311E-5 -2.4002E-4 2.9999E7 -277.78 -9.7646E-5 293.15
60 | 0.051000 0.0013428 -6.7183E-5 -2.3521E-4 2.9399E7 -277.78 3.3246E-4 293.15
61 | 0.052000 0.0013232 -5.8089E-5 -2.3044E-4 2.8801E7 277.78 7.4034E-5 293.15
62 | 0.053000 0.0013035 -4.9031E-5 -2.2564E-4 2.8201E7 277.78 -8.7398E-5 293.15
63 | 0.054000 0.0012836 -4.0012E-5 -2.2081E-4 2.7599E7 -277.78 2.8680E-4 293.15
64 | 0.055000 0.0012640 -3.1036E-5 -2.1604E-4 2.7001E7 277.78 2.1880E-4 293.15
65 | 0.056000 0.0012441 -2.2106E-5 -2.1124E-4 2.6401E7 277.78 3.0914E-4 293.15
66 | 0.057000 0.0012241 -1.3224E-5 -2.0641E-4 2.5799E7 -277.78 -1.1738E-4 293.15
67 | 0.058000 0.0012043 -4.3949E-6 -2.0163E-4 2.5201E7 277.77 4.5139E-5 293.15
68 | 0.059000 0.0011843 4.3799E-6 -1.9683E-4 2.4601E7 277.77 4.8308E-6 293.15
69 | 0.060000 0.0011641 1.3097E-5 -1.9201E-4 2.3999E7 -277.79 1.2640E-4 293.15
70 | 0.061000 0.0011441 2.1754E-5 -1.8723E-4 2.3401E7 277.77 -5.0980E-4 293.15
71 | 0.062000 0.0011239 3.0347E-5 -1.8243E-4 2.2801E7 277.76 2.8389E-4 293.15
72 | 0.063000 0.0011036 3.8875E-5 -1.7760E-4 2.2199E7 -277.81 1.3909E-4 293.15
73 | 0.064000 0.0010832 4.7334E-5 -1.7280E-4 2.1599E7 -277.82 1.2913E-4 293.15
74 | 0.065000 0.0010630 5.5722E-5 -1.6803E-4 2.1001E7 277.73 -5.5874E-4 293.15
75 | 0.066000 0.0010424 6.4037E-5 -1.6320E-4 2.0399E7 -277.83 -2.4481E-4 293.15
76 | 0.067000 0.0010219 7.2276E-5 -1.5840E-4 1.9799E7 -277.82 -7.9970E-4 293.15
77 | 0.068000 0.0010013 8.0436E-5 -1.5363E-4 1.9201E7 277.74 -3.0373E-4 293.15
78 | 0.069000 9.8055E-4 8.8517E-5 -1.4880E-4 1.8599E7 -277.69 1.6968E-4 293.15
79 | 0.070000 9.5977E-4 9.6515E-5 -1.4400E-4 1.7999E7 -277.51 1.9871E-5 293.15
80 | 0.071000 9.3902E-4 1.0443E-4 -1.3922E-4 1.7401E7 278.18 -1.8318E-4 293.15
81 | 0.072000 9.1796E-4 1.1226E-4 -1.3440E-4 1.6799E7 -276.61 -3.2509E-4 293.15
82 | 0.073000 8.9692E-4 1.1999E-4 -1.2960E-4 1.6199E7 -275.71 -3.2962E-4 293.15
83 | 0.074000 8.7590E-4 1.2764E-4 -1.2482E-4 1.5601E7 280.49 -2.3535E-4 293.15
84 | 0.075000 8.5457E-4 1.3520E-4 -1.1999E-4 1.4999E7 -272.38 -2.0272E-4 293.15
85 | 0.076000 8.3325E-4 1.4266E-4 -1.1519E-4 1.4398E7 -269.72 -6.8704E-6 293.15
86 | 0.077000 8.1194E-4 1.5003E-4 -1.1042E-4 1.3801E7 287.68 8.7055E-4 293.15
87 | 0.078000 7.9043E-4 1.5730E-4 -1.0561E-4 1.3201E7 291.46 2.6021E-4 293.15
88 | 0.079000 7.6870E-4 1.6447E-4 -1.0078E-4 1.2598E7 -259.18 1.2897E-4 293.15
89 | 0.080000 7.4707E-4 1.7154E-4 -9.6006E-5 1.2000E7 298.55 -8.8287E-4 293.15
90 | 0.081000 7.2523E-4 1.7851E-4 -9.1199E-5 1.1399E7 298.45 -7.9919E-4 293.15
91 | 0.082000 7.0316E-4 1.8538E-4 -8.6362E-5 1.0795E7 -275.48 -7.2714E-4 293.15
92 | 0.083000 6.8120E-4 1.9215E-4 -8.1578E-5 1.0197E7 269.10 2.1105E-4 293.15
93 | 0.084000 6.5902E-4 1.9881E-4 -7.6767E-5 9.5953E6 221.28 -1.5525E-4 293.15
94 | 0.085000 6.3662E-4 2.0536E-4 -7.1928E-5 8.9911E6 -498.12 -1.8121E-4 293.15
95 | 0.086000 6.1440E-4 2.1178E-4 -6.7158E-5 8.3945E6 -31.538 -3.4204E-4 293.15
96 | 0.087000 5.9206E-4 2.1806E-4 -6.2378E-5 7.7973E6 -300.28 -9.2855E-4 293.15
97 | 0.088000 5.6966E-4 2.2419E-4 -5.7599E-5 7.2013E6 -1566.1 7.2534E-4 293.15
98 | 0.089000 5.4765E-4 2.3011E-4 -5.2928E-5 6.6182E6 -2355.2 -6.7686E-5 293.15
99 | 0.090000 5.2639E-4 2.3578E-4 -4.8435E-5 6.0567E6 -2377.2 -7.4908E-5 293.15
100 | 0.091000 5.0562E-4 2.4111E-4 -4.4037E-5 5.5097E6 -5172.1 -1.3550E-4 293.15
101 | 0.092000 4.8663E-4 2.4596E-4 -4.0018E-5 5.0099E6 -7750.4 -3.0503E-4 293.15
102 | 0.093000 4.7063E-4 2.5021E-4 -3.6631E-5 4.5870E6 -8133.6 -9.2242E-4 293.15
103 | 0.094000 4.5780E-4 2.5337E-4 -3.3793E-5 4.2428E6 -18656 -4.4418E-4 293.15
104 | 0.095000 4.5194E-4 2.5585E-4 -3.2511E-5 4.0751E6 -11346 1.0426E-4 293.15
105 | 0.096000 4.5945E-4 2.5316E-4 -3.3179E-5 4.2225E6 -75109 3.7906E-4 293.15
106 | 0.097000 4.8372E-4 2.6083E-4 -4.0367E-5 4.8427E6 2.0307E5 -4.9213E-4 293.15
107 | 0.098000 5.9632E-4 2.0320E-4 -5.2740E-5 7.3681E6 -7.7579E5 2.9518E-4 293.15
108 | 0.099000 7.2721E-4 3.5285E-4 -1.1730E-4 1.1191E7 3.4711E6 -0.0018452 293.15
109 | 0.10000 0.0012863 -0.0016728 2.9423E-4 1.2828E7 -4.9612E7 -6.4945E-4 293.15
110 |
--------------------------------------------------------------------------------
/gui/main_window.py:
--------------------------------------------------------------------------------
1 | from pathlib import Path
2 | from functools import partial
3 | from itertools import pairwise
4 | import locale
5 |
6 | from numpy import linspace
7 | from PySide6.QtWidgets import (
8 | QCheckBox,
9 | QFileDialog,
10 | QGridLayout,
11 | QGroupBox,
12 | QHBoxLayout,
13 | QInputDialog,
14 | QLabel,
15 | QLineEdit,
16 | QMainWindow,
17 | QProgressBar,
18 | QPushButton,
19 | QRadioButton,
20 | QSpinBox,
21 | QTextEdit,
22 | QVBoxLayout,
23 | QWidget,
24 | )
25 | from PySide6.QtCore import Qt, Slot, QCoreApplication
26 | from PySide6.QtGui import QTextCursor, QDoubleValidator
27 |
28 | from osa.simulator import StrainTypes, StressTypes, SiUnits
29 | from gui.worker import WorkerThread
30 | from gui.plot_window import SpectrumView
31 |
32 |
33 | class MainWindow(QMainWindow):
34 | def __init__(self):
35 | super().__init__()
36 |
37 | view = ParametersView(self)
38 | self.setCentralWidget(view)
39 |
40 |
41 | class ParametersView(QWidget):
42 | def __init__(self, parent: QWidget):
43 | super().__init__(parent=parent)
44 |
45 | self.worker = None
46 | self.simulation_data = None
47 |
48 | self.float_validator = QDoubleValidator(self)
49 | self.setup_ui()
50 |
51 | def setup_ui(self):
52 | self.layout = QHBoxLayout(self)
53 |
54 | main_layout = self.make_main_layout()
55 | self.layout.addLayout(main_layout, 78)
56 |
57 | side_layout = self.make_side_layout()
58 | self.layout.addLayout(side_layout, 22)
59 |
60 | def make_side_layout(self):
61 | layout = QVBoxLayout()
62 |
63 | section_5 = self.make_spectrum_section(5)
64 | layout.addLayout(section_5)
65 |
66 | section_6 = self.make_journal_section(6)
67 | layout.addLayout(section_6)
68 |
69 | return layout
70 |
71 | def make_main_layout(self):
72 | grid = QGridLayout()
73 |
74 | section_1 = self.make_loader_section(1)
75 | grid.addLayout(section_1, 1, 1)
76 |
77 | section_2 = self.make_deform_types_section(3)
78 | grid.addLayout(section_2, 1, 2)
79 |
80 | section_3 = self.make_parameters_section(2)
81 | grid.addLayout(section_3, 2, 1)
82 |
83 | section_4 = self.make_virtual_configuration_section(4)
84 | grid.addLayout(section_4, 2, 2)
85 |
86 | return grid
87 |
88 | def make_loader_section(self, section_id: int):
89 | title = QLabel(
90 | "({}) {}".format(section_id, _("Load strain / stress data from file"))
91 | )
92 | title.setAlignment(Qt.AlignmentFlag.AlignCenter)
93 |
94 | load_button = QPushButton(_("Choose file"))
95 | load_button.clicked.connect(self.load_file)
96 |
97 | self.filepath = QLineEdit(self)
98 | self.filepath.setReadOnly(True)
99 |
100 | row = QHBoxLayout()
101 | row.addWidget(self.filepath)
102 | row.addWidget(load_button)
103 |
104 | si_units_group = QGroupBox(_("If distances are not expressed in millimeters [mm]"))
105 | self.has_si_units = QCheckBox(_("Apply conversion from m to mm"), si_units_group)
106 | group_layout = QVBoxLayout()
107 | group_layout.addWidget(self.has_si_units)
108 | si_units_group.setLayout(group_layout)
109 |
110 | layout = QVBoxLayout()
111 | layout.addWidget(title)
112 | layout.addLayout(row)
113 | layout.addWidget(si_units_group)
114 | layout.addStretch()
115 |
116 | return layout
117 |
118 | def make_deform_types_section(self, section_id: int):
119 | def set_strain_type(value: StrainTypes):
120 | self.strain_type = value
121 |
122 | def set_stress_type(value: StressTypes):
123 | self.stress_type = value
124 |
125 | self.strain_type = StrainTypes.NONE
126 | self.stress_type = StressTypes.NONE
127 |
128 | title = QLabel("({}) {}".format(section_id, _("Choose a simulation type")))
129 | title.setAlignment(Qt.AlignmentFlag.AlignCenter)
130 |
131 | strain_type_group = QGroupBox(_("Longitudinal strain"))
132 | strain_group_layout = QVBoxLayout()
133 |
134 | no_strain = QRadioButton(_("None"), strain_type_group)
135 | no_strain.setChecked(True)
136 | uniform_strain = QRadioButton(_("Uniform"), strain_type_group)
137 | non_uniform_strain = QRadioButton(_("Non-uniform"), strain_type_group)
138 |
139 | no_strain.clicked.connect(lambda: set_strain_type(StrainTypes.NONE))
140 | uniform_strain.clicked.connect(lambda: set_strain_type(StrainTypes.UNIFORM))
141 | non_uniform_strain.clicked.connect(lambda: set_strain_type(StrainTypes.NON_UNIFORM))
142 |
143 | strain_group_layout.addWidget(no_strain)
144 | strain_group_layout.addWidget(uniform_strain)
145 | strain_group_layout.addWidget(non_uniform_strain)
146 | strain_type_group.setLayout(strain_group_layout)
147 |
148 | stress_type_group = QGroupBox(_("Include stress"))
149 | stress_group_layout = QVBoxLayout()
150 |
151 | no_stress = QRadioButton(_("None"), stress_type_group)
152 | no_stress.setChecked(True)
153 | included_stress = QRadioButton(_("Transverse stress"), stress_type_group)
154 |
155 | no_stress.clicked.connect(lambda: set_stress_type(StressTypes.NONE))
156 | included_stress.clicked.connect(lambda: set_stress_type(StressTypes.INCLUDED))
157 |
158 | stress_group_layout.addWidget(no_stress)
159 | stress_group_layout.addWidget(included_stress)
160 | stress_type_group.setLayout(stress_group_layout)
161 |
162 | emulation_group = QGroupBox(_("Emulation options"))
163 |
164 | row1, self.emulate_temperature = self.make_float_parameter(
165 | _("Emulate model temperature"), "[K]", "293.15"
166 | )
167 | self.has_emulate_temperature = QCheckBox(emulation_group)
168 | self.emulate_temperature.setEnabled(False)
169 | self.has_emulate_temperature.toggled.connect(self.emulate_temperature.setEnabled)
170 | row1.insertWidget(0, self.has_emulate_temperature)
171 |
172 | row2, self.host_expansion_coefficient = self.make_float_parameter(
173 | _("Host thermal expansion coefficient"), "[K-1]", "5e-5"
174 | )
175 | self.has_host_expansion = QCheckBox(emulation_group)
176 | self.host_expansion_coefficient.setEnabled(False)
177 | self.has_host_expansion.toggled.connect(self.host_expansion_coefficient.setEnabled)
178 | row2.insertWidget(0, self.has_host_expansion)
179 |
180 | emulation_group_layout = QVBoxLayout()
181 | emulation_group_layout.addLayout(row1)
182 | emulation_group_layout.addLayout(row2)
183 | emulation_group.setLayout(emulation_group_layout)
184 |
185 | layout = QVBoxLayout()
186 | layout.addWidget(title)
187 | layout.addWidget(strain_type_group)
188 | layout.addWidget(stress_type_group)
189 | layout.addWidget(emulation_group)
190 | layout.addStretch()
191 |
192 | return layout
193 |
194 | def make_parameters_section(self, section_id: int):
195 | title = QLabel(
196 | "({}) {}".format(section_id, _("Simulation parameters")),
197 | alignment=Qt.AlignmentFlag.AlignCenter,
198 | )
199 |
200 | row1, self.resolution = self.make_float_parameter(
201 | _("Simulation resolution"), "[nm]", "0.05"
202 | )
203 | row2, self.min_bandwidth = self.make_float_parameter(
204 | _("Minimum bandwidth"), "[nm]", "1500.00"
205 | )
206 | row3, self.max_bandwidth = self.make_float_parameter(
207 | _("Maximum bandwidth"), "[nm]", "1600.00"
208 | )
209 | row4, self.ambient_temperature = self.make_float_parameter(
210 | _("Ambient temperature"), "[K]", "293.15"
211 | )
212 |
213 | advanded_group = QGroupBox(
214 | _("Fiber attributes (advanced mode)"), checkable=True, checked=False
215 | )
216 |
217 | row5, self.initial_refractive_index = self.make_float_parameter(
218 | _("Initial refractive index"), "[neff]", "1.46"
219 | )
220 | row6, self.mean_change_refractive_index = self.make_float_parameter(
221 | _("Average variation in refractive index"), "[δneff]", "4.5e-4"
222 | )
223 | row7, self.fringe_visibility = self.make_float_parameter(
224 | _("Fringe visibility"), "%", "1.0"
225 | )
226 | row8, self.directional_refractive_p11 = self.make_float_parameter(
227 | _("Pockel's elasto-optic coefficients"), "p11", "0.121"
228 | )
229 | row9, self.directional_refractive_p12 = self.make_float_parameter(
230 | _("Pockel's elasto-optic coefficients"), "p12", "0.270"
231 | )
232 | row10, self.youngs_mod = self.make_float_parameter(_("Young's module"), "[Pa]", "75e9")
233 | row11, self.poissons_coefficient = self.make_float_parameter(
234 | _("Poisson's coefficient"), "", "0.17"
235 | )
236 | row12, self.fiber_expansion_coefficient = self.make_float_parameter(
237 | _("Fiber thermal expansion coefficient"), "[K-1]", "0.55e-6"
238 | )
239 | row13, self.thermo_optic = self.make_float_parameter(
240 | _("Thermo-optic coefficient"), "[K-1]", "8.3e-6"
241 | )
242 |
243 | advanced_group_layout = QVBoxLayout()
244 | advanced_group_layout.addLayout(row5)
245 | advanced_group_layout.addLayout(row6)
246 | advanced_group_layout.addLayout(row7)
247 | advanced_group_layout.addLayout(row8)
248 | advanced_group_layout.addLayout(row9)
249 | advanced_group_layout.addLayout(row10)
250 | advanced_group_layout.addLayout(row11)
251 | advanced_group_layout.addLayout(row12)
252 | advanced_group_layout.addLayout(row13)
253 | advanded_group.setLayout(advanced_group_layout)
254 |
255 | layout = QVBoxLayout()
256 | layout.addWidget(title)
257 | layout.addLayout(row1)
258 | layout.addLayout(row2)
259 | layout.addLayout(row3)
260 | layout.addLayout(row4)
261 | layout.addWidget(advanded_group)
262 | layout.addStretch()
263 |
264 | return layout
265 |
266 | def make_float_parameter(self, display_text: str, unit_text, value_text):
267 | row = QHBoxLayout()
268 | label = QLabel(display_text)
269 | unit_label = QLabel(unit_text)
270 | value = QLineEdit(
271 | locale.str(float(value_text)),
272 | alignment=Qt.AlignmentFlag.AlignRight,
273 | validator=self.float_validator,
274 | )
275 | row.addWidget(label, stretch=3)
276 | row.addWidget(unit_label)
277 | row.addWidget(value)
278 | return row, value
279 |
280 | def make_int_parameter(self, display_text: str, unit_text, value_text):
281 | row = QHBoxLayout()
282 | label = QLabel(display_text)
283 | unit_label = QLabel(unit_text)
284 | value = QSpinBox(
285 | value=int(value_text),
286 | alignment=Qt.AlignmentFlag.AlignRight,
287 | minimum=1,
288 | )
289 | row.addWidget(label, stretch=3)
290 | row.addWidget(unit_label)
291 | row.addWidget(value)
292 | return row, value
293 |
294 | def make_virtual_configuration_section(self, section_id: int):
295 | title = QLabel(
296 | "({}) {}".format(
297 | section_id, _("Virtual Fiber Bragg Grating array configuration")
298 | ),
299 | alignment=Qt.AlignmentFlag.AlignCenter,
300 | )
301 |
302 | row1, self.fbg_count = self.make_int_parameter(_("Number of FBG sensors"), "", "1")
303 | row2, self.fbg_length = self.make_float_parameter(_("Sensor length"), "mm", "10.0")
304 | row3, self.tolerance = self.make_float_parameter(_("Tolerance"), "mm", "0.01")
305 |
306 | positions_group, self.fbg_positions = self.make_float_list_parameter(
307 | _("Positions of FBG sensors (distance from the start)"),
308 | "[mm]",
309 | _("position"),
310 | )
311 | wavelengths_group, self.original_wavelengths = self.make_float_list_parameter(
312 | _("Original wavelengths"), "[nm]", _("wavelength"), with_auto=True
313 | )
314 |
315 | layout = QVBoxLayout()
316 | layout.addWidget(title)
317 | layout.addLayout(row1)
318 | layout.addLayout(row2)
319 | layout.addLayout(row3)
320 | layout.addWidget(positions_group)
321 | layout.addWidget(wavelengths_group)
322 | layout.addStretch()
323 |
324 | return layout
325 |
326 | def make_float_list_parameter(
327 | self, display_text: str, unit_text: str, keyword: str, with_auto: bool = False
328 | ):
329 | group = QGroupBox(f"{display_text} {unit_text}")
330 |
331 | values = QTextEdit(group, readOnly=True)
332 |
333 | add_button = QPushButton(_("Add"), group)
334 | add_button.clicked.connect(partial(self.add_float_list, values, keyword))
335 | clear_button = QPushButton(_("Remove"), group)
336 | clear_button.clicked.connect(values.clear)
337 |
338 | actions_layout = QVBoxLayout()
339 | actions_layout.addWidget(add_button)
340 | actions_layout.addWidget(clear_button)
341 |
342 | if with_auto:
343 | auto_button = QPushButton(_("Auto"), group)
344 | min_bandwidth = (locale.atof(self.min_bandwidth.text()),)
345 | max_bandwidth = (locale.atof(self.max_bandwidth.text()),)
346 | auto_button.clicked.connect(
347 | partial(self.fill_float_list, values, (min_bandwidth, max_bandwidth))
348 | )
349 | actions_layout.insertWidget(0, auto_button)
350 |
351 | layout = QHBoxLayout()
352 | layout.addWidget(values)
353 | layout.addLayout(actions_layout)
354 | group.setLayout(layout)
355 |
356 | return group, values
357 |
358 | def add_float_list(self, target: QTextEdit, keyword: str):
359 | values = list()
360 |
361 | for i in range(self.fbg_count.value()):
362 | value, ok = QInputDialog.getDouble(
363 | self,
364 | "",
365 | "{} #{} {}".format(_("Please enter a value for FBG"), i + 1, keyword),
366 | flags=Qt.WindowType.Popup,
367 | )
368 | if ok:
369 | values.append(value)
370 | else:
371 | return # User has cancelled
372 |
373 | QCoreApplication.processEvents()
374 |
375 | values.sort()
376 | target.setText("\n".join(map(locale.str, values)))
377 |
378 | def fill_float_list(self, target: QTextEdit, range: tuple):
379 | left, right = range
380 | values = linspace(left, right, self.fbg_count.value() + 1, endpoint=False)
381 | target.setText("\n".join(map(locale.str, values[1:])))
382 |
383 | def make_spectrum_section(self, section_id: int):
384 | title = QLabel(
385 | "({}) {}".format(section_id, _("Spectrum simulation")),
386 | alignment=Qt.AlignmentFlag.AlignCenter,
387 | )
388 | title.setAlignment(Qt.AlignmentFlag.AlignCenter)
389 |
390 | self.has_reflected_signal = QCheckBox(
391 | _("Include the undeformed FBG reflected signal"), checked=True
392 | )
393 | simulate_button = QPushButton(_("Start simulation"))
394 | simulate_button.clicked.connect(self.run_simulation)
395 | self.progress = QProgressBar(value=0)
396 | show_plot_button = QPushButton(_("Open simulation results"))
397 | show_plot_button.clicked.connect(self.showPlot)
398 |
399 | layout = QVBoxLayout()
400 | layout.addWidget(title)
401 | layout.addWidget(self.has_reflected_signal)
402 | layout.addWidget(simulate_button)
403 | layout.addWidget(self.progress)
404 | layout.addWidget(show_plot_button)
405 |
406 | return layout
407 |
408 | def make_journal_section(self, section_id: int):
409 | title = QLabel(
410 | "({}) {}".format(section_id, _("Message log")),
411 | alignment=Qt.AlignmentFlag.AlignCenter,
412 | )
413 |
414 | self.console = QTextEdit(self)
415 | self.console.setReadOnly(True)
416 |
417 | clear_button = QPushButton(_("Clear log"), self)
418 | clear_button.clicked.connect(self.console.clear)
419 |
420 | layout = QVBoxLayout()
421 | layout.addWidget(title)
422 | layout.addWidget(self.console)
423 | layout.addWidget(clear_button)
424 |
425 | return layout
426 |
427 | def println(self, text: str):
428 | if isinstance(text, str):
429 | show_text = text
430 | else:
431 | show_text = repr(text)
432 | self.console.append(show_text)
433 | self.console.moveCursor(QTextCursor.MoveOperation.End)
434 | print(show_text)
435 |
436 | def load_file(self):
437 | fullpath, filter = QFileDialog.getOpenFileName(
438 | self, _("Load data from"), "./sample", "text (*.txt)"
439 | )
440 | self.filepath.setText(fullpath)
441 |
442 | def print_error(self, message: str):
443 | self.println("{}: {}".format(_("ERROR"), message))
444 |
445 | def validate_params(self):
446 | """Collect all simulation parameters from self and validate them."""
447 |
448 | params = dict(
449 | units=SiUnits(int(self.has_si_units.isChecked())),
450 | strain_type=self.strain_type,
451 | stress_type=self.stress_type,
452 | emulate_temperature=locale.atof(self.emulate_temperature.text())
453 | if self.has_emulate_temperature.isChecked()
454 | else None,
455 | host_expansion_coefficient=locale.atof(
456 | self.host_expansion_coefficient.text()
457 | if self.has_host_expansion.isChecked()
458 | else self.fiber_expansion_coefficient.text()
459 | ),
460 | resolution=locale.atof(self.resolution.text()),
461 | min_bandwidth=locale.atof(self.min_bandwidth.text()),
462 | max_bandwidth=locale.atof(self.max_bandwidth.text()),
463 | ambient_temperature=locale.atof(self.ambient_temperature.text()),
464 | initial_refractive_index=locale.atof(self.initial_refractive_index.text()),
465 | mean_change_refractive_index=locale.atof(self.mean_change_refractive_index.text()),
466 | fringe_visibility=locale.atof(self.fringe_visibility.text()),
467 | directional_refractive_p11=locale.atof(self.directional_refractive_p11.text()),
468 | directional_refractive_p12=locale.atof(self.directional_refractive_p12.text()),
469 | youngs_mod=locale.atof(self.youngs_mod.text()),
470 | poissons_coefficient=locale.atof(self.poissons_coefficient.text()),
471 | fiber_expansion_coefficient=locale.atof(self.fiber_expansion_coefficient.text()),
472 | thermo_optic=locale.atof(self.thermo_optic.text()),
473 | fbg_count=int(self.fbg_count.text()),
474 | fbg_length=locale.atof(self.fbg_length.text()),
475 | tolerance=locale.atof(self.tolerance.text()),
476 | has_reflected_signal=self.has_reflected_signal.isChecked(),
477 | )
478 |
479 | datafile = self.filepath.text()
480 | if Path(datafile).is_file():
481 | params["filepath"] = datafile
482 | else:
483 | raise ValueError("'{}' {}".format(datafile, _("is not a valid data file.")))
484 |
485 | if positions := self.fbg_positions.toPlainText():
486 | fbg_positions = list(map(float, positions.split("\n")))
487 | else:
488 | fbg_positions = []
489 |
490 | steps = [right - left for left, right in pairwise(fbg_positions)]
491 | if len(fbg_positions) != params["fbg_count"]:
492 | raise ValueError(
493 | "Sensors count ({}) and positions count ({}) should be equal.".format(
494 | params["fbg_count"], len(fbg_positions)
495 | )
496 | )
497 | elif min(steps, default=params["fbg_length"]) < params["fbg_length"]:
498 | raise ValueError(_("Two consecutive FBG positions cannot be shorter than FBG length."))
499 | else:
500 | params["fbg_positions"] = fbg_positions
501 |
502 | if wavelengths := self.original_wavelengths.toPlainText():
503 | original_wavelengths = list(map(float, wavelengths.split("\n")))
504 | else:
505 | original_wavelengths = []
506 |
507 | if min(original_wavelengths, default=params["min_bandwidth"]) < params["min_bandwidth"]:
508 | raise ValueError(_("At least one wavelength is below the minimum bandwidth setting."))
509 | elif max(original_wavelengths, default=params["max_bandwidth"]) > params["max_bandwidth"]:
510 | raise ValueError(_("At least one wavelength is above the maximum bandwidth setting."))
511 | elif len(original_wavelengths) != params["fbg_count"]:
512 | raise ValueError(
513 | _("Sensors count ({}) and original wavelengths count ({}) must be equal.").format(
514 | params["fbg_count"], len(original_wavelengths)
515 | )
516 | )
517 | else:
518 | params["original_wavelengths"] = original_wavelengths
519 |
520 | return params
521 |
522 | @Slot()
523 | def run_simulation(self):
524 | if self.worker is not None:
525 | self.print_error(_("A simulator session is already running."))
526 | return
527 |
528 | self.simulation_data = None
529 | self.progress.setValue(0)
530 | try:
531 | params = self.validate_params()
532 | except ValueError as err:
533 | self.print_error(str(err))
534 | return
535 |
536 | self.progress.setValue(5)
537 | self.worker = WorkerThread(params)
538 | self.worker.progress.connect(self.progress.setValue)
539 | self.worker.finished.connect(self.worker_finished)
540 | self.worker.start()
541 | self.progress.setValue(8)
542 |
543 | def worker_finished(self):
544 | if self.worker.error_message:
545 | message = _("Simulation has failed, reason: {}").format(self.worker.error_message)
546 | self.print_error(message)
547 | else:
548 | self.simulation_data = self.worker.data
549 | self.simulation_data["params"] = self.worker.params
550 | self.println(_("Simulation completed successfully."))
551 | self.worker = None
552 |
553 | def showPlot(self):
554 | if self.simulation_data is None:
555 | self.print_error(_("There is no data to show, please run the simulation first."))
556 | return
557 |
558 | plot = SpectrumView(self, data=self.simulation_data)
559 | plot.exec()
560 |
--------------------------------------------------------------------------------
/osa/simulator.py:
--------------------------------------------------------------------------------
1 | """
2 | Simulation of reflected FBG spectrum using coupled-mode theory.
3 | TODO: review with [Ben Frey](https://github.com/benfrey)
4 | """
5 | import numpy as np
6 | from cmath import pi, sqrt, cosh, sinh
7 | from enum import IntEnum
8 |
9 |
10 | class SiUnits(IntEnum):
11 | METERS = 0
12 | MILLIMETERS = 1
13 |
14 |
15 | class StrainTypes(IntEnum):
16 | NONE = 0
17 | UNIFORM = 1
18 | NON_UNIFORM = 2
19 |
20 |
21 | class StressTypes(IntEnum):
22 | NONE = 0
23 | INCLUDED = 1
24 |
25 |
26 | class OsaSimulator:
27 | def __init__(
28 | self,
29 | fbg_count: int,
30 | fbg_length: float,
31 | tolerance: float,
32 | fbg_positions: list,
33 | original_wavelengths: list,
34 | initial_refractive_index: float,
35 | directional_refractive_p11: float,
36 | directional_refractive_p12: float,
37 | poissons_coefficient: float,
38 | emulate_temperature: float,
39 | resolution: float,
40 | min_bandwidth: float,
41 | max_bandwidth: float,
42 | mean_change_refractive_index: float,
43 | fringe_visibility: float,
44 | ambient_temperature: float,
45 | thermo_optic: float,
46 | fiber_expansion_coefficient: float,
47 | host_expansion_coefficient: float,
48 | youngs_mod: float,
49 | ):
50 | """
51 | Prepares an OSA simulation with the specified parameters.
52 |
53 | Parameters
54 | ----------
55 | fbg_count : int
56 | Number of FBG per optical fibre.
57 | fbg_length : float
58 | Length of the Grating.
59 | tolerance : float
60 | Tolerance in the FBG length.
61 | positions : list
62 | Position of each FBG from the beginning of the Path.
63 | initial_refractive_index : float
64 | Initial effective refractive index (neff).
65 | mean_change_refractive_index : float
66 | Mean induced change in the refractive index (dneff).
67 | directional_refractive_p11 : float
68 | Pockel’s normal photoelastic constant.
69 | directional_refractive_p12 : float
70 | Pockel’s shear photoelastic constant.
71 | poissons_coefficient : float
72 | Poisson's Coefficient of fiber.
73 | emulate_temperature : float
74 | Theoretical emulated temperature of fiber.
75 | resolution : float
76 | Simulation resolution - Wavelength increment.
77 | min_bandwidth : float
78 | Light Minimum Bandwidth.
79 | max_bandwidth : float
80 | Light Maximum Bandwidth.
81 | fringe_visibility : float
82 | Fringe Visibility (FV).
83 | ambient_temperature : float
84 | Base in which our reference temperature is set.
85 | thermo_optic : float
86 | Thermo optic coefficient of fiber.
87 | fiber_expansion_coefficient : float
88 | Thermal expansion coefficient of fiber material.
89 | host_expansion_coefficient : float
90 | Thermal expansion coefficient of host material.
91 | youngs_mod : float
92 | Young's modulus of fiber.
93 |
94 | Note
95 | ----
96 | Everything in this class will be expressed in (mm).
97 | """
98 |
99 | self.fbg_count = int(fbg_count)
100 | self.fbg_length = np.float64(fbg_length)
101 | self.tolerance = np.float64(tolerance)
102 | self.fbg_positions = np.array(fbg_positions, dtype=np.float64)
103 | self.initial_refractive_index = np.float64(initial_refractive_index)
104 | self.mean_change_refractive_index = np.float64(mean_change_refractive_index)
105 | self.directional_refractive_p11 = np.float64(directional_refractive_p11)
106 | self.directional_refractive_p12 = np.float64(directional_refractive_p12)
107 | self.poissons_coefficient = np.float64(poissons_coefficient)
108 | self.emulate_temperature = np.float64(emulate_temperature)
109 | self.resolution = np.float64(resolution)
110 | self.min_bandwidth = np.float64(min_bandwidth)
111 | self.max_bandwidth = np.float64(max_bandwidth)
112 | self.fringe_visibility = np.float64(fringe_visibility)
113 | self.ambient_temperature = np.float64(ambient_temperature)
114 | self.thermo_optic = np.float64(thermo_optic)
115 | self.fiber_expansion_coefficient = np.float64(fiber_expansion_coefficient)
116 | self.host_expansion_coefficient = np.float64(host_expansion_coefficient)
117 | self.youngs_mod = np.float64(youngs_mod)
118 |
119 | assert len(original_wavelengths) == self.fbg_count
120 | self.original_wavelengths = np.array(original_wavelengths, dtype=np.float64)
121 | self.grating_periods = self.original_wavelengths[: self.fbg_count] / (
122 | 2.0 * initial_refractive_index
123 | )
124 | self.original_fbg_periods = [
125 | wavelen / (2.0 * self.initial_refractive_index)
126 | for wavelen in self.original_wavelengths
127 | ]
128 |
129 | self.directional_refractive_p11 = directional_refractive_p11
130 | self.directional_refractive_p12 = directional_refractive_p12
131 | self.poissons_coefficient = poissons_coefficient
132 | self.emulate_temperature = emulate_temperature
133 | self.resolution = resolution
134 | self.min_bandwidth = min_bandwidth
135 | self.max_bandwidth = max_bandwidth
136 | self.fringe_visibility = fringe_visibility
137 |
138 | self.ambient_temperature = ambient_temperature
139 | self.thermo_optic = thermo_optic
140 | self.fiber_expansion_coefficient = fiber_expansion_coefficient
141 | self.host_expansion_coefficient = host_expansion_coefficient
142 | self.youngs_mod = youngs_mod
143 |
144 | self._compute_photo_elastic_coefficient()
145 |
146 | def _compute_photo_elastic_coefficient(self):
147 | """
148 | Calculate photoelastic coefficient from directional coefficients.
149 | """
150 | self.photo_elastic_param = (self.initial_refractive_index**2 / 2) * (
151 | self.directional_refractive_p12
152 | - self.poissons_coefficient
153 | * (self.directional_refractive_p11 + self.directional_refractive_p12)
154 | )
155 |
156 | def from_file(self, filepath: str, units=SiUnits.MILLIMETERS) -> dict:
157 | """
158 | Loads FBG data from a text file.
159 |
160 | The file is expected to have the following fields:
161 | - 'x', 'LE11', 'LE22', 'LE33', 'S11', 'S22', 'S33', 'T'
162 |
163 | Parameters
164 | ----------
165 | filepath : str
166 | Full path to the data file.
167 | units : SiUnits, optional
168 | Units of the data (default is SiUnits.MILLIMETERS).
169 | """
170 | from_meters = units == SiUnits.METERS
171 | fields = dict(
172 | x=dict(format="f8", multiply=1000 if from_meters else 1),
173 | LE11=dict(format="f8"),
174 | LE22=dict(format="f8"),
175 | LE33=dict(format="f8"),
176 | S11=dict(format="f8", divide=(10**6) if from_meters else 1),
177 | S22=dict(format="f8", divide=(10**6) if from_meters else 1),
178 | S33=dict(format="f8", divide=(10**6) if from_meters else 1),
179 | T=dict(format="f8"),
180 | )
181 | dtypes = dict(names=list(fields.keys()), formats=[v["format"] for v in fields.values()])
182 | raw_data = np.genfromtxt(filepath, dtypes, comments="%")
183 |
184 | fbg = dict()
185 | for b in range(self.fbg_count):
186 | b_key = f"FBG{b+1}"
187 | fbg[b_key] = dict()
188 | for key in fields:
189 | if key.startswith("S"):
190 | factor = fields[key]["divide"]
191 | fbg[b_key][key] = raw_data[key] / factor
192 | elif key == "x":
193 | factor = fields[key]["multiply"]
194 | fbg[b_key][key] = raw_data[key] * factor
195 | else:
196 | fbg[b_key][key] = raw_data[key]
197 |
198 | self.fbg = fbg
199 | return fbg
200 |
201 | def sigma(self, period: float, wavelen: float, dneff: float) -> float:
202 | """
203 | Compute the sigma value based on period, wavelength, and change in effective refractive index.
204 |
205 | Parameters
206 | ----------
207 | period : float
208 | FBG grating period.
209 | wavelen : float
210 | Wavelength under consideration.
211 | dneff : float
212 | Change in effective refractive index.
213 |
214 | Returns
215 | -------
216 | float
217 | Computed sigma value.
218 | """
219 | refractive_term = self.initial_refractive_index + dneff
220 | inverse_wavelength_difference = (1.0 / wavelen) - (1.0 / (2.0 * refractive_term * period))
221 | mean_refraction_effect = 2.0 * pi * self.mean_change_refractive_index / wavelen
222 |
223 | return 2.0 * pi * refractive_term * inverse_wavelength_difference + mean_refraction_effect
224 |
225 | def kaa(self, wavelen: float) -> float:
226 | """
227 | Compute the kaa value based on the provided wavelength.
228 |
229 | Parameters
230 | ----------
231 | wavelen : float
232 | Wavelength under consideration.
233 |
234 | Returns
235 | -------
236 | float
237 | Computed kaa value.
238 | """
239 | return pi * self.fringe_visibility * self.mean_change_refractive_index / wavelen
240 |
241 | def transfer_matrix(
242 | self, count: int, wavelen: float, use_period, use_dneff: list = []
243 | ) -> np.ndarray:
244 | """
245 | Calculate the transfer matrix for the FBG based on various parameters.
246 |
247 | Parameters
248 | ----------
249 | count : int
250 | Number of divisions to consider for the FBG length.
251 | wavelen : float
252 | Wavelength under consideration.
253 | use_period : float or list
254 | FBG grating period. Can be a float (for uniform period) or a list (for varying period).
255 | use_dneff : list, optional
256 | List of changes in effective refractive index.
257 |
258 | Returns
259 | -------
260 | np.ndarray
261 | Calculated transfer matrix.
262 | """
263 | trx_mat = np.identity(2)
264 | delta_z = self.fbg_length * (10**6) / count
265 |
266 | for z in range(count):
267 | period = use_period if isinstance(use_period, float) else use_period[z]
268 | dneff = use_dneff[z] if len(use_dneff) else 0.0
269 | sig = self.sigma(period, wavelen=wavelen, dneff=dneff)
270 | kaa_value = self.kaa(wavelen=wavelen)
271 | gamma = sqrt(kaa_value**2 - sig**2)
272 |
273 | f11 = complex(cosh(gamma * delta_z), -(sig / gamma) * sinh(gamma * delta_z))
274 | f22 = complex(cosh(gamma * delta_z), (sig / gamma) * sinh(gamma * delta_z))
275 | f12 = complex(0, -(kaa_value / gamma) * sinh(gamma * delta_z))
276 | f21 = complex(0, +(kaa_value / gamma) * sinh(gamma * delta_z))
277 |
278 | section_transfer_matrix = np.array([[f11, f12], [f21, f22]])
279 | trx_mat = np.dot(trx_mat, section_transfer_matrix)
280 |
281 | return trx_mat
282 |
283 | def undeformed_fbg(self) -> dict:
284 | """
285 | Calculate the undeformed (original) reflection spectrum of the FBG.
286 |
287 | Returns
288 | -------
289 | dict
290 | Dictionary containing the undeformed reflection spectrum with keys 'wavelength' and 'reflec'.
291 | """
292 | reflection_spectrum = {"wavelength": [], "reflec": []}
293 | # ASSUMPTION: all columns have the same length
294 | M = len(self.fbg["FBG1"]["x"])
295 | # Cycle through all the FBG sensors using only the periods for this cycle
296 | for period in self.original_fbg_periods:
297 | # Number of sections the grating is divided into for the Transfer Matrix
298 | wavelengths = np.arange(self.min_bandwidth, self.max_bandwidth, self.resolution)
299 | for wl in wavelengths:
300 | trx_mat = self.transfer_matrix(count=M, use_period=period, wavelen=wl)
301 | PO, NO = trx_mat[0, 0], trx_mat[1, 0]
302 | reflectivity = abs(NO / PO) ** 2
303 |
304 | reflection_spectrum["wavelength"].append(wl)
305 | reflection_spectrum["reflec"].append(reflectivity)
306 |
307 | return reflection_spectrum
308 |
309 | def deformed_fbg(self, strain_type: StrainTypes, stress_type: StressTypes) -> dict:
310 | """
311 | Calculate the deformed reflection spectrum of the FBG considering strain and stress effects.
312 |
313 | Parameters
314 | ----------
315 | strain_type : StrainTypes
316 | Type of strain to consider: NONE, UNIFORM, or NON_UNIFORM.
317 | stress_type : StressTypes
318 | Type of stress to consider: NONE or INCLUDED.
319 |
320 | Returns
321 | -------
322 | dict
323 | Dictionary containing the deformed reflection spectrum with keys 'wavelength' and 'reflec'.
324 | """
325 | # Apply a theoretical temperature value if specified
326 | if self.emulate_temperature is not None:
327 | for i in range(self.fbg_count):
328 | self.fbg[f"FBG{i+1}"]["T"][:] = self.emulate_temperature
329 |
330 | y_reflection = {"wavelength": [], "reflec": []}
331 | z_reflection = {"wavelength": [], "reflec": []}
332 | combined_reflection = {"wavelength": [], "reflec": []}
333 |
334 | # Compute the thermo-dynamic part
335 | thermo_dynamic_effect = (
336 | self.fiber_expansion_coefficient
337 | + (1 - self.photo_elastic_param)
338 | * (self.host_expansion_coefficient - self.fiber_expansion_coefficient)
339 | + self.thermo_optic
340 | )
341 |
342 | # Iterate over all the FBG sensors
343 | for i in range(self.fbg_count):
344 | sensor_data = self.fbg[f"FBG{i+1}"]
345 | M = len(sensor_data["x"])
346 |
347 | # Determine the FBG grating period based on the strain type
348 | if strain_type == StrainTypes.NONE:
349 | fbg_period = [self.grating_periods[i] for _ in range(M)]
350 | elif strain_type == StrainTypes.UNIFORM:
351 | strain_avg = np.mean(sensor_data["LE11"])
352 | temp_avg = np.mean(sensor_data["T"])
353 | new_wavelength = self.original_wavelengths[i] * (
354 | 1
355 | + (1 - self.photo_elastic_param) * strain_avg
356 | + thermo_dynamic_effect * (temp_avg - self.ambient_temperature)
357 | )
358 | fbg_period = [
359 | new_wavelength / (2.0 * self.initial_refractive_index) for _ in range(M)
360 | ]
361 | elif strain_type == StrainTypes.NON_UNIFORM:
362 | fbg_period = [
363 | self.original_wavelengths[i]
364 | * (
365 | 1
366 | + (1 - self.photo_elastic_param) * sensor_data["LE11"][j]
367 | + thermo_dynamic_effect * (sensor_data["T"][j] - self.ambient_temperature)
368 | )
369 | / (2.0 * self.initial_refractive_index)
370 | for j in range(M)
371 | ]
372 | else:
373 | raise ValueError(f"Invalid strain_type: {strain_type}.")
374 |
375 | # Determine the change in effective refractive index based on the stress type
376 | self.dneff_y = np.zeros(M)
377 | self.dneff_z = np.zeros(M)
378 | if stress_type == StressTypes.INCLUDED:
379 | coef = -(self.initial_refractive_index**3.0) / (2 * self.youngs_mod)
380 | factor1 = (
381 | self.directional_refractive_p11
382 | - 2 * self.poissons_coefficient * self.directional_refractive_p12
383 | )
384 | factor2 = (
385 | (1 - self.poissons_coefficient) * self.directional_refractive_p12
386 | - self.poissons_coefficient * self.directional_refractive_p11
387 | )
388 | self.dneff_y = coef * (
389 | factor1 * sensor_data["S22"]
390 | + factor2 * (sensor_data["S33"] + sensor_data["S11"])
391 | )
392 | self.dneff_z = coef * (
393 | factor1 * sensor_data["S33"]
394 | + factor2 * (sensor_data["S22"] + sensor_data["S11"])
395 | )
396 | elif stress_type != StressTypes.NONE:
397 | raise ValueError(f"Invalid stress_type: {stress_type}.")
398 |
399 | # Simulate for Y and Z waves
400 | wavelengths = np.arange(self.min_bandwidth, self.max_bandwidth, self.resolution)
401 | for wl in wavelengths:
402 | trx_y = self.transfer_matrix(
403 | count=M, use_period=fbg_period, wavelen=wl, use_dneff=self.dneff_y
404 | )
405 | PO_y, NO_y = trx_y[0, 0], trx_y[1, 0]
406 | reflectivity_y = abs(NO_y / PO_y) ** 2
407 | y_reflection["wavelength"].append(wl)
408 | y_reflection["reflec"].append(reflectivity_y)
409 |
410 | trx_z = self.transfer_matrix(
411 | count=M, use_period=fbg_period, wavelen=wl, use_dneff=self.dneff_z
412 | )
413 | PO_z, NO_z = trx_z[0, 0], trx_z[1, 0]
414 | reflectivity_z = abs(NO_z / PO_z) ** 2
415 | z_reflection["wavelength"].append(wl)
416 | z_reflection["reflec"].append(reflectivity_z)
417 |
418 | # Combine the Y and Z wave reflections
419 | combined_reflection["wavelength"] = y_reflection["wavelength"]
420 | combined_reflection["reflec"] = np.add(
421 | np.divide(y_reflection["reflec"], 2.0), np.divide(z_reflection["reflec"], 2.0)
422 | )
423 | combined_reflection["Y_split"] = np.divide(y_reflection["reflec"], 2.0)
424 | combined_reflection["Z_split"] = np.divide(z_reflection["reflec"], 2.0)
425 |
426 | return combined_reflection
427 |
428 | def _calculate_strain_stats(self):
429 | """
430 | Calculates statistics related to strain and stress for each FBG sensor.
431 |
432 | For each FBG sensor, the function computes the average, maximum, and minimum
433 | values for different strain and stress types (LE11, LE22, LE33, S11, S22, S33, T).
434 |
435 | Returns
436 | -------
437 | dict
438 | A dictionary with the computed statistics for each FBG sensor.
439 | """
440 | stat_types = ["AV", "Max", "Min"]
441 | measures = ["LE11", "LE22", "LE33", "S11", "S22", "S33", "T"]
442 | operations = {"AV": np.mean, "Max": np.max, "Min": np.min}
443 |
444 | stats_dict = {}
445 | for i in range(self.fbg_count):
446 | fbg_key = f"FBG{i+1}"
447 | stats_dict[fbg_key] = {}
448 | for measure in measures:
449 | data_array = np.array(self.fbg[fbg_key][measure], dtype=np.float64)
450 | for stat in stat_types:
451 | if stat in {"Max", "Min"} and measure in {"S11", "S22", "S33", "T"}:
452 | # These are not needed
453 | continue
454 | if stat == "AV" and measure == "T" and self.emulate_temperature is not None:
455 | stats_dict[fbg_key][f"{stat}-{measure}"] = self.emulate_temperature
456 | else:
457 | stats_dict[fbg_key][f"{stat}-{measure}"] = operations[stat](data_array)
458 |
459 | return stats_dict
460 |
461 | def _calculate_wave_shift(
462 | self, strain_type: StrainTypes, fbg_stat: dict, original_wavelength: np.float64
463 | ) -> np.float64:
464 | """
465 | Calculate the wavelength shift for a given strain type.
466 |
467 | The method computes the wavelength shift based on the provided strain type. For `StrainTypes.NONE`,
468 | the shift is determined solely by the thermo-optic effect. For other strain types, the shift
469 | is influenced by various factors including photo-elastic parameters, fiber and host expansion
470 | coefficients, and thermo-optic effects.
471 |
472 | Parameters
473 | ----------
474 | strain_type : StrainTypes
475 | Type of strain to consider. Options are: NONE, UNIFORM, or NON_UNIFORM.
476 | fbg_stat : dict
477 | Dictionary containing statistics related to Fiber Bragg Gratings (FBG).
478 | Expected to contain keys like "AV-T" for average temperature and "AV-LE11" for average longitudinal strain.
479 | original_wavelength : float
480 | The original wavelength of the FBG before any strain or temperature effects.
481 |
482 | Returns
483 | -------
484 | float
485 | The calculated wavelength shift based on the provided parameters.
486 |
487 | Notes
488 | -----
489 | - The calculation is based on the assumption that strain and temperature changes are small
490 | enough to be considered linear.
491 | - The method uses class attributes such as `self.thermo_optic`, `self.photo_elastic_param`,
492 | `self.fiber_expansion_coefficient`, `self.host_expansion_coefficient`, and `self.ambient_temperature`
493 | for its calculations.
494 | """
495 | temperature_diff = fbg_stat["AV-T"] - self.ambient_temperature
496 |
497 | if strain_type == StrainTypes.NONE:
498 | return original_wavelength * self.thermo_optic * temperature_diff
499 | else:
500 | common_term = (1 - self.photo_elastic_param) * fbg_stat["AV-LE11"] + (
501 | self.fiber_expansion_coefficient
502 | + (1 - self.photo_elastic_param)
503 | * (self.host_expansion_coefficient - self.fiber_expansion_coefficient)
504 | + self.thermo_optic
505 | ) * temperature_diff
506 | return original_wavelength * common_term
507 |
508 | def _calculate_grating_periods(
509 | self, strain_type: StrainTypes, fbg_stat: dict, original_wavelength: np.float64
510 | ) -> tuple:
511 | """
512 | Calculate the grating periods for the provided strain type.
513 |
514 | For `StrainTypes.NONE` and `StrainTypes.UNIFORM`, both the maximum and
515 | minimum grating periods are the same. For `StrainTypes.NON_UNIFORM`, the
516 | grating periods are determined separately for the maximum and minimum strains.
517 |
518 | Parameters
519 | ----------
520 | strain_type : StrainTypes
521 | Type of strain to consider. Options are: NONE, UNIFORM, or NON_UNIFORM.
522 | fbg_stat : dict
523 | Dictionary containing statistics related to Fiber Bragg Gratings (FBG).
524 | Expected to contain keys like "AV-T" for average temperature, "AV-LE11" for average
525 | longitudinal strain, "Max-LE11" for maximum longitudinal strain, and "Min-LE11" for minimum
526 | longitudinal strain.
527 | original_wavelength : float
528 | The original wavelength of the FBG before any strain or temperature effects.
529 |
530 | Returns
531 | -------
532 | tuple
533 | A tuple containing two values: the maximum grating period and the minimum grating period.
534 |
535 | Notes
536 | -----
537 | The calculation is based on the assumption that strain and temperature
538 | changes are small enough to be considered linear.
539 | """
540 | temperature_diff = fbg_stat["AV-T"] - self.ambient_temperature
541 |
542 | common_term = (
543 | original_wavelength
544 | / (2 * self.initial_refractive_index)
545 | * (
546 | 1
547 | + (1 - self.photo_elastic_param) * fbg_stat["AV-LE11"]
548 | + self.thermo_optic * temperature_diff
549 | )
550 | )
551 |
552 | if strain_type in [StrainTypes.NONE, StrainTypes.UNIFORM]:
553 | return common_term, common_term
554 | elif strain_type == StrainTypes.NON_UNIFORM:
555 | grating_period_max = (
556 | original_wavelength
557 | / (2 * self.initial_refractive_index)
558 | * (
559 | 1
560 | + (1 - self.photo_elastic_param) * fbg_stat["Max-LE11"]
561 | + self.thermo_optic * temperature_diff
562 | )
563 | )
564 | grating_period_min = (
565 | original_wavelength
566 | / (2 * self.initial_refractive_index)
567 | * (
568 | 1
569 | + (1 - self.photo_elastic_param) * fbg_stat["Min-LE11"]
570 | + self.thermo_optic * temperature_diff
571 | )
572 | )
573 | return grating_period_max, grating_period_min
574 |
575 | def _calculate_peak_width(
576 | self,
577 | strain_type: StrainTypes,
578 | stress_type: StressTypes,
579 | fbg_stat: dict,
580 | original_wavelength: np.float64,
581 | grating_period_max: np.float64,
582 | grating_period_min: np.float64,
583 | ) -> np.float64:
584 | """
585 | Computes the peak width of a Fiber Bragg Grating (FBG) based on strain and
586 | stress considerations. The width is influenced by non-uniform strain (if
587 | present) and by the transverse stress (if included).
588 |
589 | Parameters
590 | ----------
591 | strain_type : StrainTypes
592 | Type of strain to consider. Options are: NONE, UNIFORM, or NON_UNIFORM.
593 | stress_type : StressTypes
594 | Type of stress to consider. Options are: NONE or INCLUDED.
595 | fbg_stat : dict
596 | Dictionary containing statistics related to Fiber Bragg Gratings (FBG).
597 | Expected to contain keys like "AV-S33" and "AV-S22" for stress values
598 | in different directions.
599 | original_wavelength : float
600 | The original wavelength of the FBG before any strain or temperature effects.
601 | grating_period_max : float
602 | Maximum grating period calculated based on strain effects.
603 | grating_period_min : float
604 | Minimum grating period calculated based on strain effects.
605 |
606 | Returns
607 | -------
608 | float
609 | The calculated peak width for the FBG based on the provided strain and stress types.
610 |
611 | Notes
612 | -----
613 | The method considers the peak width contributions only if the corresponding
614 | strain or stress type is specified.
615 | """
616 | peak_width_1 = (
617 | 2 * self.initial_refractive_index * (grating_period_max - grating_period_min)
618 | if strain_type == StrainTypes.NON_UNIFORM
619 | else 0
620 | )
621 | peak_width_2 = (
622 | (
623 | abs(fbg_stat["AV-S33"] - fbg_stat["AV-S22"])
624 | * (original_wavelength / (2 * self.initial_refractive_index))
625 | * (
626 | (1 + self.poissons_coefficient) * self.directional_refractive_p12
627 | - (1 + self.poissons_coefficient) * self.directional_refractive_p11
628 | )
629 | * self.initial_refractive_index**3
630 | / self.youngs_mod
631 | )
632 | if stress_type == StressTypes.INCLUDED
633 | else 0
634 | )
635 |
636 | return peak_width_1 + peak_width_2
637 |
638 | def compute_fbg_shifts_and_widths(
639 | self, strain_type: StrainTypes, stress_type: StressTypes
640 | ) -> dict:
641 | """
642 | Calculate the wavelength shift and peak spliting per sensor.
643 |
644 | This method computes the wavelength shift and peak width for each FBG in
645 | the set based on the given strain and stress types. The calculations are
646 | determined using helper methods for wave shift, grating periods, and peak
647 | width.
648 |
649 | Parameters
650 | ----------
651 | strain_type : StrainTypes
652 | Type of strain to consider. Options are: NONE, UNIFORM, or NON_UNIFORM.
653 | stress_type : StressTypes
654 | Type of stress to consider. Options are: NONE or INCLUDED.
655 |
656 | Returns
657 | -------
658 | dict
659 | A dictionary containing the calculated wavelength shift and peak width
660 | for each FBG. The keys are FBG identifiers (e.g., "FBG1", "FBG2", ...),
661 | and the values are dictionaries with keys "wave_shift" and "wave_width",
662 | each containing a list of corresponding values.
663 |
664 | Raises
665 | ------
666 | ValueError
667 | If the provided strain_type or stress_type is not valid.
668 | """
669 | if strain_type not in StrainTypes._value2member_map_:
670 | raise ValueError(f"{strain_type} is not a valid strain type.")
671 |
672 | if stress_type not in StressTypes._value2member_map_:
673 | raise ValueError(f"{strain_type} is not a valid stress type.")
674 |
675 | fbg_stats = self._calculate_strain_stats()
676 | self._fbg_stats = fbg_stats
677 |
678 | output = {
679 | f"FBG{i+1}": {
680 | "wave_shift": np.empty(self.fbg_count, dtype=np.float64),
681 | "wave_width": np.empty(self.fbg_count, dtype=np.float64),
682 | }
683 | for i in range(self.fbg_count)
684 | }
685 |
686 | for i in range(self.fbg_count):
687 | key = f"FBG{i+1}"
688 | fbg_stat = fbg_stats[key]
689 | original_wavelength = self.original_wavelengths[i]
690 |
691 | wavelength_shift = self._calculate_wave_shift(
692 | strain_type, fbg_stat, original_wavelength
693 | )
694 | grating_period_max, grating_period_min = self._calculate_grating_periods(
695 | strain_type, fbg_stat, original_wavelength
696 | )
697 | peak_width_total = self._calculate_peak_width(
698 | strain_type,
699 | stress_type,
700 | fbg_stat,
701 | self.original_wavelengths[i],
702 | grating_period_max,
703 | grating_period_min,
704 | )
705 |
706 | output[key]["wave_shift"] = wavelength_shift
707 | output[key]["wave_width"] = peak_width_total
708 |
709 | return output
710 |
--------------------------------------------------------------------------------
/osa/old_simulator.py:
--------------------------------------------------------------------------------
1 | """
2 | Simulatation of reflected FBG spectrum using coupled-mode theory
3 |
4 | Copyright (C) 2021 Ben Frey
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 |
19 | Email: freynben@gmail.com
20 | """
21 |
22 | # Packages
23 | import numpy as np
24 | import math
25 | import cmath
26 |
27 |
28 | class OSASimulation(object):
29 | def __init__(
30 | self,
31 | filename,
32 | NumberFBG,
33 | FBGLength,
34 | Tolerance,
35 | SkipRow,
36 | FBGPosition,
37 | InputUnits,
38 | ):
39 | """Initialized the classe
40 | This will load the file with the stress and strain, and create a variable
41 | per FBG with the correspondent Strain and Stress
42 |
43 | Parameters:
44 | ----------
45 | Filename:string (Mandatory)
46 | Path to the file
47 | NumberFBG: int (Mandatory)
48 | Number of FBG per Optical fibre
49 | FBG length:float (Mandatory)
50 | Length of the Gratting
51 | Tolerance: float (Mandatory)
52 | Tolerance in the FBG length
53 | SkipRow:Int (Mandatory)
54 | How any rows will be skip to load the file
55 | FBGPosition:List (Mandatory)
56 | Position of each FBG from the beggin of the Path
57 | InputUnits:Int (Mandatory)
58 | 0: meters; 1: mm
59 |
60 | In this Class everything will be converted to (mm)
61 | """
62 | self.filename = str(filename)
63 | self.NumberFBG = NumberFBG
64 | self.FBGLength = FBGLength
65 | self.Tolerance = Tolerance
66 | self.SkipRow = SkipRow
67 | self.FBGPosition = FBGPosition
68 | self.InputUnits = InputUnits
69 |
70 | # Loading the File
71 | names = ("x", "LE11", "LE22", "LE33", "S11", "S22", "S33", "T")
72 | formats = ("f8", "f8", "f8", "f8", "f8", "f8", "f8", "f8")
73 | dtypes = {"names": names, "formats": formats}
74 | self.RawData = np.loadtxt(self.filename, dtype=dtypes, skiprows=self.SkipRow)
75 |
76 | """------------------------------------------------------------------------------
77 | Creating FBG array, and give them the correspondent Data
78 | FBGArray['xx']['yy'][zz]
79 | xx- Number of the FBG-1
80 | yy- variable 'x','LE11','LE22','LE33','S11','S22','S33','T'
81 | zz line(number of elements per grating)
82 | """
83 | # Naming the Array
84 | self.FBGArray = {}
85 | for b in np.arange(1, self.NumberFBG + 1):
86 | self.FBGArray["FBG" + str(b)] = {}
87 | self.FBGArray["FBG" + str(b)]["x"] = []
88 | self.FBGArray["FBG" + str(b)]["LE11"] = []
89 | self.FBGArray["FBG" + str(b)]["LE22"] = []
90 | self.FBGArray["FBG" + str(b)]["LE33"] = []
91 | self.FBGArray["FBG" + str(b)]["S11"] = []
92 | self.FBGArray["FBG" + str(b)]["S22"] = []
93 | self.FBGArray["FBG" + str(b)]["S33"] = []
94 | self.FBGArray["FBG" + str(b)]["T"] = []
95 |
96 | # Converting tolerance and FBG length to the SI if in meters
97 | if self.InputUnits == 0:
98 | self.FBGLength = self.FBGLength / 1000.0
99 | self.Tolerance = self.Tolerance / 1000.0
100 |
101 | # Sorting Data for each FBG
102 | for b in np.arange(0, self.NumberFBG):
103 | for f in np.arange(0, len(self.RawData)):
104 | # Check the lines inside the FBG length+tolerance
105 | # if self.RawData['x'][f]>self.FBGPosition[b]-self.Tolerance and self.RawData['x'][f]