diff --git a/.gitlab/issue_templates/Default.md b/.gitlab/issue_templates/Default.md new file mode 100644 index 0000000000000000000000000000000000000000..ed6f8d8cfb4c948a3cb438fb92d89159e2d1a352 --- /dev/null +++ b/.gitlab/issue_templates/Default.md @@ -0,0 +1,18 @@ +<!-- Title: Provide a concise and descriptive title for the issue incl. tool or library name --> + +## Choose Your Issue Template +Before creating an issue, please review existing issues to avoid duplicates! +ALso, select the **appropriate type for your issue in the desciption drop-down**. +- Bug Report Template +- Feature Request Template +- TODO Template +- Documentation Request Template +- Testing Request Template + +If not suitable, use the sections below and contact the owners. + +## Description +Provide a concise description of the issue. + +## Additional Context +Add screenshots, logs, or relevant information here. diff --git a/.gitlab/issue_templates/bug_report.md b/.gitlab/issue_templates/bug_report.md new file mode 100644 index 0000000000000000000000000000000000000000..b906703dce8a5a8d1ca99bd5a36d980f6a2fc26a --- /dev/null +++ b/.gitlab/issue_templates/bug_report.md @@ -0,0 +1,22 @@ +<!-- Title: Provide a concise and descriptive title for the issue incl. tool or library name --> +# Bug Report + +## Description +Describe the bug clearly. What happened? + +## Steps to Reproduce +1. [Step 1] +2. [Step 2] +3. [Step 3] + +## Expected Behavior +Explain what you expected to see. + +## Environment +- **OS**: [e.g., Windows 10] +- **Version/Branch**: [e.g., v1.2.3] + +## Additional Context +Attach any logs, screenshots, or context. + +/label ~"type::bug" diff --git a/.gitlab/issue_templates/documentation_request.md b/.gitlab/issue_templates/documentation_request.md new file mode 100644 index 0000000000000000000000000000000000000000..bc94cf6d704aa0645ae950ba690cc716b81659f1 --- /dev/null +++ b/.gitlab/issue_templates/documentation_request.md @@ -0,0 +1,14 @@ +<!-- Title: Provide a concise and descriptive title for the issue --> +# Documentation + +## Summary +Explain what documentation is missing. + +- **Unicado Version**: vx.x.x +- **Page**: page-to-change + +## Additional Context +Attach any logs, screenshots, or context. + +/label ~"type::documentation" + diff --git a/.gitlab/issue_templates/feature_request.md b/.gitlab/issue_templates/feature_request.md new file mode 100644 index 0000000000000000000000000000000000000000..2c12fdb6bfc6f26eec57a4c7b1b228b65d991e24 --- /dev/null +++ b/.gitlab/issue_templates/feature_request.md @@ -0,0 +1,17 @@ +<!-- Title: Provide a concise and descriptive title for the issue incl. tool or library name --> +# Feature Request + +## Summary +What feature are you requesting? + +## Why? +Explain the problem this feature solves or the value it adds. + +## Acceptance Criteria +- [ ] Define measurable outcomes for success. +- [ ] List specific requirements. + +## Additional Notes +Include references, examples, or diagrams if applicable. + +/label ~"type::feature" diff --git a/.gitlab/issue_templates/testing_request.md b/.gitlab/issue_templates/testing_request.md new file mode 100644 index 0000000000000000000000000000000000000000..0289f4df34cec1c786d637480d7456bbf20b3d08 --- /dev/null +++ b/.gitlab/issue_templates/testing_request.md @@ -0,0 +1,24 @@ +<!-- Title: Provide a concise and descriptive title for the issue incl. tool or library name --> +# Testing Issue + +## Summary +Provide a brief overview of what should be tested or changed in the test process. Also think about what is the goal of this test? E.g. +- Verify that [feature/bug fix/module] works as expected. +- Ensure that [specific requirement] is met. + +## Related Issues or Merge Requests +- Issue(s): #[Issue ID] +- Merge Request(s): #[Merge Request ID] + +## Expected Results +- [Outcome 1]: [What should happen]. +- [Outcome 2]: [Another expected result]. + +## Environment +- **OS**: [e.g., Windows 10] +- **Version/Branch**: [e.g., v1.2.3] + +## Additional Context +Attach any logs, screenshots, or context. + +/label ~"type::testing" diff --git a/.gitlab/issue_templates/todo.md b/.gitlab/issue_templates/todo.md new file mode 100644 index 0000000000000000000000000000000000000000..07bdd0f8b2e7294d7949344698e4426530efc826 --- /dev/null +++ b/.gitlab/issue_templates/todo.md @@ -0,0 +1,16 @@ +<!-- Title: Provide a concise and descriptive title for the issue incl. tool or library name --> +# TODO + +## Summary +Briefly describe the task. Provide any background information or related issues. + +## Subtasks +- [ ] Step 1 +- [ ] Step 2 +- [ ] Step 3 + +## Acceptance Criteria +- [ ] Define measurable outcomes for success. +- [ ] List specific requirements. + +/label ~"type::todo" diff --git a/.gitlab/merge_request_templates/Default.md b/.gitlab/merge_request_templates/Default.md new file mode 100644 index 0000000000000000000000000000000000000000..00be17dc34a7fc90bb7096112e57c895a2f6d4bf --- /dev/null +++ b/.gitlab/merge_request_templates/Default.md @@ -0,0 +1,29 @@ +<!-- Title: Use an imperative, clear title (e.g., "Fix login bug" or "Add new analytics feature") --> + +## Description +Provide a concise explanation of the changes made in this merge request. + +## Related Issue(s) +- Closes #[feature issues] +- Fixes #[bug report issue] +- Resolves #[any other issues] + +### Other Changes +- [Mention refactoring, tests, etc.] + +## Screenshots/Logs +Attach screenshots or log outputs if applicable. + +## Testing Instructions +1. [Step 1: How to test] +2. [Step 2: Expected outcome] +3. [Step 3: Additional steps if required] + +## Developer Checklist +- [ ] Code has been tested locally and/or in pipeline. +- [ ] (if applicable) documentation updated. +- [ ] (if applicable) impact of new dependencies reviewed and included in project. +- [ ] Merge conflicts resolved with the target branch. + +## Additional Notes +Add any information reviewers should focus on, e.g., specific files, functions, or changes of interest. diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000000000000000000000000000000000000..8359155d27a9d274b8dacb9685439aa0770c8d64 --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,9 @@ +# Repository-specific code ownership + * @Florian.Schueltke @AndiGob + +# File-specific code ownership +.gitattributes @Florian.Schueltke +.gitignore @Florian.Schueltke +CODEOWNERS @Florian.Schueltke +LICENSE @Florian.Schueltke +README.md @Florian.Schueltke diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..e06ae69696acc3a0209f8fb93f7e4203fd960279 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 2025 UNICADO consortium + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) 2025 UNICADO consortium + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<https://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<https://www.gnu.org/licenses/why-not-lgpl.html>. diff --git a/README.md b/README.md index a6e281f7b2f63c596f095fd21fa472272435817f..dc94c803236a78231be2b6b99a0ec41108f3a59a 100644 --- a/README.md +++ b/README.md @@ -1 +1,37 @@ -Welcome to UNICADO RCE Workflow ✈ +# Welcome to UNICADO RCE Workflow :airplane: +The RCE workflow repository includes all the files which are relevant for executing the UNICADO workflow with RCE. + +> → Checkout your [UNICADO website](https://unicado.io/) for more information! + +## Installation + +### For User +You want to use UNICADO to get familiar with the workflow and see first results? Great :fire: Then check out the [Installation Guide](https://unicado.pages.rwth-aachen.de/unicado.gitlab.io/download/installation/) and the [Cleared for Take-Off](https://unicado.pages.rwth-aachen.de/unicado.gitlab.io/download/takeoff/). It includes the prerequisites, troubleshooting hints and a standalone installer. + +### For Developer +We welcome contributions! :sparkles: Please read our [developer guide](https://unicado.pages.rwth-aachen.de/unicado.gitlab.io/developer/developer-installation/). It explains step-by-step what you need to install, how to get the source code, how to build it, how to contribute and how to create the installer. + +## License +This project is licensed under the GNU General Public License, Version 3 License - see the [LICENSE](LICENSE) file for details. + +## Acknowledgments and Funding +This project is a collaborative effort by +- RWTH Aachen, Chair and Institute of Aerospace Systems +- TU Berlin + - Aircraft Design and Aerostructures + - Flight Mechanics, Flight Control and Aeroelasticity +- TU Braunschweig, Chair of Overall Aircraft Design +- TU Hamburg, Institute of Air Transportation Systems +- TU Munich, Chair of Aircraft Design +- University of Stuttgart, Institute of Aircraft Design + +including its associated partner +- Airbus SE +- Collins Aerospace +- TGM Lightweight Solutions GmbH + +and is funded by the Federal Ministry of Economic Affairs and Climate Action on the basis of a decision by the German Bundestag. + +## Contact +For questions or support, feel free to contact us :email: **E-Mail:** [contacts@unicado.io](mailto:contacts@unicado.io). + diff --git a/UNICADOworkflow/.project b/UNICADOworkflow/.project new file mode 100644 index 0000000000000000000000000000000000000000..b3e6903f8494bf21b1f622d11d7a0092ca520afc --- /dev/null +++ b/UNICADOworkflow/.project @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>UNICADOworkflow</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + </buildSpec> + <natures> + </natures> +</projectDescription> diff --git a/UNICADOworkflow/UNICADOworkflow.json b/UNICADOworkflow/UNICADOworkflow.json new file mode 100644 index 0000000000000000000000000000000000000000..67ef289cda1bb7e9d4b61ae1b41b13787e8dfcfb --- /dev/null +++ b/UNICADOworkflow/UNICADOworkflow.json @@ -0,0 +1,5 @@ +{ + "de.rcenvironment.script/3.5" : { + "pythonExecutionPath" : "C:/Program Files/Python311/python.exe" + } +} \ No newline at end of file diff --git a/UNICADOworkflow/UNICADOworkflow.wf b/UNICADOworkflow/UNICADOworkflow.wf new file mode 100644 index 0000000000000000000000000000000000000000..81ba64d653a9df7e6f86e4aac645c11b80a62aa2 --- /dev/null +++ b/UNICADOworkflow/UNICADOworkflow.wf @@ -0,0 +1,6177 @@ +{ + "identifier" : "b4e0b0af-f210-48a9-ae71-396ec78d335c", + "workflowVersion" : "5", + "name" : "UNICADOworkflow_2025-02-26_13:49:11_07", + "nodes" : [ { + "identifier" : "f1d90e37-bf7c-41b6-981a-44c70e8b6f17", + "name" : "aerodynamic_analysis", + "location" : "945:321", + "zIndex" : "40", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.aerodynamic_analysis", + "version" : "allTime", + "name" : "aerodynamic_analysis" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "ee2528b1-3e9d-4302-868b-033120790ef6", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "1944ec89-950a-4d31-adea-d761e05192c3", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "8a71c6da-657c-4477-82a0-49891a14be4c", + "name" : "aerodynamic_analysis_calibration", + "location" : "1217:21", + "zIndex" : "41", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.aerodynamic_analysis", + "version" : "allTime", + "name" : "aerodynamic_analysis" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "a3cc874b-0c30-4202-840b-2cabea2f6d60", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "bfb01312-476c-482c-ae4e-3f00a72c279b", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "e349ce89-8a54-4872-991c-4620d62163b8", + "name" : "after_calibration_joiner", + "location" : "1277:229", + "zIndex" : "23", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.joiner", + "version" : "3.3", + "name" : "Joiner" + }, + "configuration" : { + "datatype" : "SmallTable", + "inputCount" : "2", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "766ce404-9e94-4d57-a9f5-d73199786fed", + "name" : "Input 001", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "SmallTable" + }, { + "identifier" : "e802ff8c-fd84-43c3-a80d-b4376a94ae9a", + "name" : "Input 002", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "SmallTable" + } ], + "staticOutputs" : [ { + "identifier" : "751e462c-4a7e-4db7-abb6-3c3954aa0b71", + "name" : "Joined", + "datatype" : "SmallTable" + } ] + }, { + "identifier" : "e090fc9b-501e-4c4c-9cf1-b2f871649bef", + "name" : "after_calibration_trigger_switch", + "location" : "1314:321", + "zIndex" : "22", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read RCE inputs for script execution '''\r\n\r\ncurrent_workflow_name = RCE.read_input(\"current_workflow_name\")\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npath_of_working_directory_rce = RCE.read_input(\"path_of_working_directory_rce\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n# import for python\r\nimport os\r\n\r\ndesign_mode = int(([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1])\r\n\r\n# check if selected design mode equal to 3 or if exist a tool execution error -> if true: skip design sizing tool execution and trigger mission analysis loop\r\nif design_mode == 3 or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'):\r\n\tRCE.write_output(\"skip_design_sizing_flag\", current_workflow_name)\r\nelse:\r\n\tRCE.write_output(\"current_workflow_name\", current_workflow_name)\r\n\tRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "186abed3-cc90-4c42-8a74-2053591fe983", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "e886940e-cf3a-4177-b0b9-b97040d71952", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "a8b3f797-9727-4935-a87d-252b02a0d600", + "name" : "path_of_working_directory_rce", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "81ac2cf9-fa50-4167-b723-d1c6bacbb006", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "ebd6cb13-4d54-42b4-b39d-055f51c0290f", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "7cbb1605-b099-4bde-b0b2-9c09f1ff20e1", + "name" : "skip_design_sizing_flag", + "epIdentifier" : "default", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "name" : "calibration_converger", + "location" : "1201:140", + "zIndex" : "11", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.converger", + "version" : "6", + "name" : "Converger" + }, + "configuration" : { + "epsA" : "0.01", + "epsR" : "0.01", + "failLoopOnly-NAV_5e0ed1cd" : "false", + "faultTolerance-NAV_5e0ed1cd" : "Fail", + "finallyFailIfDiscarded-NAV_5e0ed1cd" : "false", + "isNestedLoop_5e0ed1cd" : "true", + "iterationsToConsider" : "1", + "maxRerunBeforeFail-NAV_5e0ed1cd" : "1", + "notConvFail" : "false", + "notConvIgnore" : "true", + "notConvNotAValue" : "false", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "bad0087e-cd88-4857-9f50-ad3e5ddfa83d", + "name" : "calibration_factors", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "85ca0f75-8b8e-4fc9-b334-f9cb64623f30", + "name" : "calibration_factors_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "21a3ffb1-e742-44e2-a6a2-fe7f8009d289", + "name" : "calibration_settings", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "d027b84c-2f0c-42e1-89bf-35b80766c8d5", + "name" : "calibration_settings_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "8b73bc0d-408e-4b00-94ac-954ee883e6e4", + "name" : "count_of_calibration", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "b097dd1a-d97c-42b9-8cfd-bcdfecc37466", + "name" : "count_of_calibration_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "68b5b61c-2843-4115-9d48-204b81e4d808", + "name" : "current_workflow_name", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "c4a7d10d-7312-49ce-98ff-1e71cf02b5b3", + "name" : "current_workflow_name_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "222bc266-e497-4c14-9148-1d0075e598c3", + "name" : "ome_calibration_flag", + "epIdentifier" : "valueToConverge", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "hasStartValue" : "false", + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single", + "startValue" : "-" + } + }, { + "identifier" : "68459e5a-8f12-4fb1-96ea-0e2b806f24cb", + "name" : "ome_calibration_flag_start", + "epIdentifier" : "startToConverge", + "group" : "startValues", + "datatype" : "Float" + }, { + "identifier" : "e7780bc4-2879-4324-b36f-06ba971ae8ea", + "name" : "ome_loop_vector", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "000b283d-9406-4e4a-b663-524fc8620627", + "name" : "ome_loop_vector_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "1b6369d1-3e84-497f-b9f5-2288e88dcf08", + "name" : "outer_loop_trigger_flag", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Boolean", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "725a7752-9fb9-4da3-8315-07ef8b95c1e0", + "name" : "outer_loop_trigger_flag_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Boolean", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "3cd16a12-115c-4bcb-a4c2-44d585584954", + "name" : "parameter_for_design_case", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "86f860cf-1e94-4cc6-9348-239b5e3def0f", + "name" : "parameter_for_design_case_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "4e2e94ad-d761-4c2f-b5c5-ff364e8a8bdd", + "name" : "paths_and_names", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "92cd1e9c-7aea-4952-a959-f6da2f3c1f59", + "name" : "paths_and_names_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "3091b26e-fb72-4c7f-8dfe-7e4760dfdceb", + "name" : "perform_calibration", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "89074ab3-c473-49ea-9151-1f7d411a1fa3", + "name" : "perform_calibration_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "1860f6e0-1f17-4719-995b-57474ac99506", + "name" : "skip_moe_calibration", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "16d88892-c896-4288-964a-9894d547ea27", + "name" : "skip_moe_calibration_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ], + "staticOutputs" : [ { + "identifier" : "7e7a22a0-de1e-4bbb-8d3b-210f5561e65e", + "name" : "Converged", + "datatype" : "Boolean" + }, { + "identifier" : "ed217314-bd83-4164-8801-0510160b83c2", + "name" : "Converged absolute", + "datatype" : "Boolean" + }, { + "identifier" : "de3604bd-81c1-4817-a7f1-a0f7dd0c4513", + "name" : "Converged relative", + "datatype" : "Boolean" + }, { + "identifier" : "9b6ef1b6-cb07-4142-a5c1-8b533da04d5d", + "name" : "Done", + "datatype" : "Boolean" + } ], + "dynamicOutputs" : [ { + "identifier" : "19e3d4f7-8c0d-4c74-8a44-bbf84eaedd14", + "name" : "calibration_factors", + "epIdentifier" : "toForward", + "datatype" : "Vector" + }, { + "identifier" : "ab6c8349-fd6e-472e-bee8-5b0489ec6755", + "name" : "calibration_factors_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Vector" + }, { + "identifier" : "d1e13946-ad12-4c76-a5e2-daada6966719", + "name" : "calibration_settings", + "epIdentifier" : "toForward", + "datatype" : "SmallTable" + }, { + "identifier" : "de861e33-555c-4050-b703-ddbb874e9e73", + "name" : "calibration_settings_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable" + }, { + "identifier" : "317c3f50-7aef-478b-8f43-77e755d2699d", + "name" : "count_of_calibration", + "epIdentifier" : "toForward", + "datatype" : "Integer" + }, { + "identifier" : "d3214613-1f58-49dd-9d7f-320c57eddcde", + "name" : "count_of_calibration_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Integer" + }, { + "identifier" : "4ed7c7bd-e6c5-4538-be5e-de177427d12b", + "name" : "current_workflow_name", + "epIdentifier" : "toForward", + "datatype" : "ShortText" + }, { + "identifier" : "51f7eedc-d73c-4fe8-aef8-dfca5b8a08ff", + "name" : "current_workflow_name_converged", + "epIdentifier" : "finalToForward", + "datatype" : "ShortText" + }, { + "identifier" : "9f25b478-7c6d-4c4c-8366-b9ede21dfa21", + "name" : "ome_calibration_flag", + "epIdentifier" : "valueToConverge", + "datatype" : "Float" + }, { + "identifier" : "57e4dad1-8bbf-4041-9720-796f47606c73", + "name" : "ome_calibration_flag_converged", + "epIdentifier" : "finalToConverge", + "datatype" : "Float" + }, { + "identifier" : "7b856f34-3e9c-42c9-ba80-22da2232a0b5", + "name" : "ome_calibration_flag_is_converged", + "epIdentifier" : "auxiliaryValue", + "datatype" : "Boolean" + }, { + "identifier" : "44963723-13ce-4346-b039-520f94913532", + "name" : "ome_loop_vector", + "epIdentifier" : "toForward", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "21cb3d28-683a-4d0b-bb62-f7a918296ab5", + "name" : "ome_loop_vector_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "67d461cf-3fd4-45fc-a413-cebf477faba1", + "name" : "outer_loop_trigger_flag", + "epIdentifier" : "toForward", + "datatype" : "Boolean" + }, { + "identifier" : "91db51f1-e2dd-455f-8e11-0e8cfdcb29ba", + "name" : "outer_loop_trigger_flag_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Boolean" + }, { + "identifier" : "b6800cc0-15b7-4dc7-98b7-3131063a6c80", + "name" : "parameter_for_design_case", + "epIdentifier" : "toForward", + "datatype" : "SmallTable" + }, { + "identifier" : "916169ee-19eb-43df-a660-bac558030233", + "name" : "parameter_for_design_case_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable" + }, { + "identifier" : "949919fb-0ff1-43bb-b64c-734a6a023a78", + "name" : "paths_and_names", + "epIdentifier" : "toForward", + "datatype" : "SmallTable" + }, { + "identifier" : "1285e7fe-e3df-4c88-bd1e-7e92154c5a76", + "name" : "paths_and_names_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable" + }, { + "identifier" : "05839f5d-d3be-468a-bfc2-5e5ad87a2fe0", + "name" : "perform_calibration", + "epIdentifier" : "toForward", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "db0a4a43-c5c0-49bd-8b75-2cb456f8f2a5", + "name" : "perform_calibration_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "c0c43fac-65b4-4b06-9e1d-ce1d8d335bfb", + "name" : "skip_moe_calibration", + "epIdentifier" : "toForward", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "ea7be8ef-be2b-454d-89d6-911f6cb2c427", + "name" : "skip_moe_calibration_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ] + }, { + "identifier" : "4ddb93ef-f271-4b8d-8c34-8ce11a6e6fbb", + "name" : "calibration_output_switch", + "location" : "1315:140", + "zIndex" : "18", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read RCE inputs for script execution '''\r\n\r\ncurrent_workflow_name = RCE.read_input(\"current_workflow_name\")\r\nperform_calibration = RCE.read_input(\"perform_calibration\")\r\nskip_moe_calibration = RCE.read_input(\"skip_moe_calibration\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\nif perform_calibration == 1 and skip_moe_calibration == 0:\r\n\tRCE.write_output(\"current_workflow_name\", current_workflow_name)\r\nelse:\r\n\tRCE.write_output(\"skip_calibration\", current_workflow_name)\r\n\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "fb7cdb30-bc05-4bee-b70c-52d45cda667d", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "5c605d19-5b7b-4940-9d9b-2571d403e3e0", + "name" : "perform_calibration", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "9cce0d22-b8b1-48ac-a518-9ece29c15187", + "name" : "skip_moe_calibration", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "eb08140f-80c3-49ad-b4bc-1292074b48ad", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "41dbb087-9c35-452c-9f8d-2cc65c93b4aa", + "name" : "skip_calibration", + "epIdentifier" : "default", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "15d0bff5-e2ad-46e7-875f-f22bdd9e3b51", + "name" : "check_mode_for_constraint_analysis", + "location" : "1517:439", + "zIndex" : "59", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "ScriptWhitespaceBox" : "true", + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "#------------------------------------------------------------------------------------------------------------------------\n\n''' read RCE inputs for script execution '''\n\ncurrent_workflow_name = RCE.read_input(\"current_workflow_name\")\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\n\n#------------------------------------------------------------------------------------------------------------------------\n\n# import for python\nimport os\n\nbridge_constraint_analysis = int(([item for item in parameter_for_design_case if 'bridge_constraint_analyzer' in item])[-1][-1])\n\n# check switch bridge_constraint_analysis -> if true: -> skip execution of constraint analysis module\nif bridge_constraint_analysis:\n\tRCE.write_output(\"current_workflow_name_constraint_analysis_joiner\", current_workflow_name)\nelse:\n\tRCE.write_output(\"current_workflow_name_constraint_analysis\", current_workflow_name)\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "7a9f9695-54e8-41cb-9f27-cb5b9c984c75", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "11cb3355-786a-430f-a928-5e85327ea15d", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "c427327e-2529-411b-8ae4-bddbbd14057a", + "name" : "current_workflow_name_constraint_analysis", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "4981f85e-9022-4a4d-8060-5defab91e9c0", + "name" : "current_workflow_name_constraint_analysis_joiner", + "epIdentifier" : "default", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "name" : "check_ome_calibration", + "location" : "1201:321", + "zIndex" : "10", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read input values '''\r\ncalibration_factors = RCE.read_input(\"calibration_factors\")\r\ncalibration_settings = RCE.read_input(\"calibration_settings\")\r\ncount_of_iteration = RCE.read_input(\"count_of_iteration\")\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npaths_and_names = RCE.read_input(\"paths_and_names\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read and set system path for python scripts '''\r\n\r\n# import for python\r\nimport sys\r\n\r\nsys.path.insert(1, ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1])\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read calibration flag from calibration settings to activate or skip calibration '''\r\ncalibration_check_flag = ([item for item in calibration_settings if 'free_variable_OME_calibration' in item])[-1][-1] > 0 or ([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1] > 0\r\ncurrent_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1]\r\n\r\n# check if calibration flag is set to active -> if true: -> perform calibration)\r\nif calibration_check_flag:\r\n\tcount_of_calibration = 1\r\n\tome_loop_vector = []\r\n\t\r\n\tome_loop_vector.append(([item for item in calibration_settings if 'current_value' in item])[-1][-1])\r\n\t\r\n\tif count_of_iteration == 0:\r\n\t\tlog_file_list = []\r\n\t\tome_loop_vector = []\r\n\t\tcalibration_factors = []\r\n\t\tcalibration_factors.append(([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1])\r\n\t\t\r\n\t\tpath_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1]\r\n\t\r\n\t\t# write log-file to system \r\n\t\tlog_file_list.append('************************************************ perform calibration ***********************************************')\r\n\t\tlog_file_list.append('')\r\n\t\tlog_file_list.append(\"--- Start iteration for OME calibration: \" + str(count_of_calibration) + \" ---\")\r\n\t\r\n\t\tlog_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a')\r\n\t\tfor row in log_file_list:\r\n\t\t\tlog_file.write(row + '\\n')\r\n\t\tlog_file.close()\r\n\t\t\r\n\t\t#------------------------------------------------------------------------------------------------------------------------\r\n\r\n\t\t''' perform first steps of OME iteration loop '''\r\n\t\t\r\n\t\t# import python script\r\n\t\tfrom calibration.perform_ome_iteration import perform_ome_iteration\r\n\t\t\r\n\t\t# function call tp perform ome iteration steps and -> set values of first ome loop\r\n\t\t# inputs: paths_and_names, calibration_settings, ome_loop_vector, convergence_criteria, parameter_for_design_case, count_of_calibration\r\n\t\t# returns: calibration_settings, ome_loop_vector, calibration_factors\r\n\t\t\r\n\t\tcalibration_settings, ome_loop_vector, calibration_factors = perform_ome_iteration(paths_and_names, calibration_settings, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tome_loop_vector, parameter_for_design_case, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcalibration_factors, count_of_calibration)\r\n\t\t\r\n\t\t#------------------------------------------------------------------------------------------------------------------------\r\n\t\r\n\t\tRCE.write_output(\"calibration_factors\", calibration_factors)\r\n\t\tRCE.write_output(\"calibration_factors_mtom_calibration\", calibration_factors)\r\n\t\tRCE.write_output(\"calibration_settings\", calibration_settings)\r\n\t\tRCE.write_output(\"calibration_settings_mtom_calibration\", calibration_settings)\r\n\t\tRCE.write_output(\"count_of_calibration\", count_of_calibration)\r\n\t\tRCE.write_output(\"count_of_iteration\", count_of_iteration)\r\n\t\tRCE.write_output(\"ome_calibration_flag\", 0)\r\n\t\tRCE.write_output(\"ome_loop_vector\", ome_loop_vector)\r\n\t\tRCE.write_output(\"output_flag_check_calibration\", 1)\r\n\t\tRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\r\n\t\tRCE.write_output(\"paths_and_names\", paths_and_names)\r\n\t\t\r\n\t#------------------------------------------------------------------------------------------------------------------------\r\n\t\t\r\n\telse:\r\n\t\tRCE.write_output(\"calibration_factors_mtom_calibration\", calibration_factors)\r\n\t\tRCE.write_output(\"calibration_settings_mtom_calibration\", calibration_settings)\r\n\t\tRCE.write_output(\"output_flag_check_calibration\", 0)\r\n\t\tRCE.write_output(\"output_flag_check_ome_calibration\", 1)\r\n\t\tRCE.write_output(\"parameter_for_design_case_trigger\", parameter_for_design_case)\r\n\t\t\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\t\t\r\n# calibration done or skipped -> send trigger signal to mission_analysis module\r\nelse:\r\n\tRCE.write_output(\"calibration_factors_mtom_calibration\", calibration_factors)\r\n\tRCE.write_output(\"calibration_settings_mtom_calibration\", calibration_settings)\r\n\tif count_of_iteration == 0:\r\n\t\tome_loop_vector = [0]\r\n\t\tRCE.write_output(\"calibration_factors\", calibration_factors)\r\n\t\tRCE.write_output(\"calibration_settings\", calibration_settings)\r\n\t\tRCE.write_output(\"count_of_calibration\", 0)\r\n\t\tRCE.write_output(\"count_of_iteration\", count_of_iteration)\r\n\t\tRCE.write_output(\"ome_calibration_flag\", 0)\r\n\t\tRCE.write_output(\"ome_loop_vector\", ome_loop_vector)\r\n\t\tRCE.write_output(\"output_flag_check_calibration\", 0)\r\n\t\tRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\r\n\t\tRCE.write_output(\"paths_and_names\", paths_and_names)\r\n\t\r\n\tif count_of_iteration > 0:\r\n\t\tRCE.write_output(\"output_flag_check_ome_calibration\", 1)\r\n\t\tRCE.write_output(\"parameter_for_design_case_trigger\", parameter_for_design_case)\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\nRCE.write_output(\"current_workflow_name\", current_workflow_name)\r\nRCE.write_output(\"path_of_working_directory_rce\", ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1])\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "16409b06-a5c4-463b-b597-8bcc0ca4c35c", + "name" : "calibration_factors", + "epIdentifier" : "default", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "abdb0d5a-a1ef-42f7-89a1-bcc7d15f4aa6", + "name" : "calibration_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "8b28e89d-ed0d-4295-81a5-2c134af5ee83", + "name" : "count_of_iteration", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "cfaf2a25-dd31-4d1b-ad67-37a819079e6d", + "name" : "input_flag_check_calibration", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "8e467da2-b754-4af1-82f1-95d44c84650d", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "38327c32-03e4-4fa3-bc44-cfeb6a31e29b", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "fcb361e6-8cf0-4fe9-bcc1-61c83a81c7ac", + "name" : "calibration_factors", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "6363d86a-58c3-4526-b647-653c156fd598", + "name" : "calibration_factors_mtom_calibration", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "79d97dba-3f66-4142-9181-241891cb75cd", + "name" : "calibration_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "fcc31ce6-0707-4c81-b17c-5eea81d11a54", + "name" : "calibration_settings_mtom_calibration", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "0cb1fc40-4e7c-4076-a59d-cab779e4d370", + "name" : "count_of_calibration", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "ea56447a-2564-433a-8257-8ab24e67ad7a", + "name" : "count_of_iteration", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "5c0a8a4f-12b4-4b28-9b8c-63ee03211906", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "bafc942c-1020-42ac-90f1-4189ceecf968", + "name" : "ome_calibration_flag", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "43cb6c61-cc87-4100-a77c-683f094134e5", + "name" : "ome_loop_vector", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "d07b0f6d-cc5c-499c-8d6b-5254ad938c73", + "name" : "output_flag_check_calibration", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "5ed85b92-5c17-4d2b-af4b-cfba24fc2b52", + "name" : "output_flag_check_ome_calibration", + "epIdentifier" : "default", + "datatype" : "Boolean" + }, { + "identifier" : "492faca2-c689-441f-bcc8-1c2f0755bae1", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "7d0db335-571f-44eb-ae1d-139321ee7ab9", + "name" : "parameter_for_design_case_trigger", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "297dc37c-1970-460b-b62c-de3e4007c258", + "name" : "path_of_working_directory_rce", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "560ccc89-d0d0-4740-b8ec-3c1eaffc0559", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable" + } ] + }, { + "identifier" : "fdb39adf-3696-4e67-9e75-b0a79d7b3953", + "name" : "check_tlars_and_gradients", + "location" : "1380:800", + "zIndex" : "8", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "ScriptWhitespaceBox" : "true", + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read input flag '''\r\naccuracy_list = RCE.read_input(\"accuracy_list\")\r\ncontrol_settings = RCE.read_input(\"control_settings\")\r\ncurrent_workflow_name = RCE.read_input(\"current_workflow_name\")\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npaths_and_names = RCE.read_input(\"paths_and_names\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read and set system path for python scripts '''\r\n\r\n# import for python\r\nimport os\r\nimport sys\r\n\r\nsys.path.insert(1, ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1])\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\npath_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1]\r\n\r\n# check if a tool execution error exist -> if true: skip mission study loop and trigger post operations of workflow\r\nif os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat') or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/pre_sizing_error.dat') or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/design_sizing_error.dat') or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/mission_study_error.dat'):\r\n\tif os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'):\r\n\t\t# genereate error status flag of post operations\r\n\t\tpost_operation_error_dat = open(path_of_working_directory_rce + current_workflow_name + '/temp/post_operation_error.dat', 'a+')\r\n\t\tpost_operation_error_dat.close()\r\n\t\r\n\tif not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'):\r\n\t\t# genereate error status flag of workflow execution\r\n\t\terror_dat = open(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat', 'a+')\r\n\t\terror_dat.close()\r\n\r\n''' checks whether the tlars and gradients have been observed '''\r\n\r\n# import python script\r\nfrom post_operations.check_tlars_and_gradients import check_tlars_and_gradients\r\n\r\n# function call for check tlars and gradients -> checks whether the tlars and gradients have been observed\r\n# inputs: paths_and_names, parameter_for_design_case\r\n# returns: none\r\n\r\n# check if the design sizing loop is not failed\r\nif not os.path.isfile(path_of_working_directory_rce + '/temp/pre_sizing_error.dat') and not os.path.isfile(path_of_working_directory_rce + '/temp/design_sizing_error.dat'):\r\n\tcheck_tlars_and_gradients(paths_and_names, parameter_for_design_case)\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' outputs for workflow '''\r\n# set check_tlars_and_gradients results to RCE outputs\r\nRCE.write_output(\"accuracy_list\", accuracy_list)\r\nRCE.write_output(\"control_settings\", control_settings)\r\nRCE.write_output(\"current_workflow_name\", current_workflow_name)\r\nRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\r\nRCE.write_output(\"paths_and_names\", paths_and_names)\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW", + "xor" : "false" + }, + "dynamicInputs" : [ { + "identifier" : "fe78d694-64e3-4bc9-82d1-ad4e4213bb9d", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "6dbac510-6ca9-4393-bf8a-0fea5687aa4e", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "d78b0adb-311f-4d13-ad62-fbd8dd8df448", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "e6d39819-517c-43dc-8c79-dfea4a97ce67", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "ffbf6e03-3c0a-4981-819e-553c53bf9b7f", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "e8a12278-9c06-4e0b-ac4f-b3e63e8ee979", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "c20cbe58-f83f-41b4-b46a-cc2de8b62f27", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "d67fbd36-3587-4129-9099-83063db6ed0f", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "3a9817c4-04d0-4651-bb94-dcae4bded043", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "b69215d8-f495-4b6c-8d44-4727621b5e2d", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable" + } ] + }, { + "identifier" : "955adf0b-210c-4210-a984-04d66ab792ec", + "name" : "constraint_analysis", + "location" : "1631:321", + "zIndex" : "58", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.constraint_analysis", + "version" : "allTime", + "name" : "constraint_analysis" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "true" + }, + "staticInputs" : [ { + "identifier" : "43c8f405-ef97-4323-8cd0-53d18ece953b", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "546f80b7-6aa0-4e74-a787-e6aad690f6de", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "785ca8d3-bb68-4f0e-a2ac-0ecf3375037b", + "name" : "cost_estimation", + "location" : "1120:800", + "zIndex" : "52", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.cost_estimation", + "version" : "allTime", + "name" : "cost_estimation" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "true" + }, + "staticInputs" : [ { + "identifier" : "3dcd1902-d6c3-4bd5-a55c-4cf81bc5b59e", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "8f0c00d3-1072-41b0-afbd-9fbb163a1fdd", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "14d3858b-82ae-47f5-aa33-9501f7341409", + "name" : "create_mission_xml", + "location" : "721:426", + "zIndex" : "29", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.create_mission_xml", + "version" : "allTime", + "name" : "create_mission_xml" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "63e8b1e3-4d79-4473-9370-6e8de7f0c34f", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "eaa67876-34a0-494d-9b89-5ff6f0743393", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "30de1370-ff4a-460f-a74c-16c06e9ef2f5", + "name" : "create_mission_xml_calibration", + "location" : "1427:140", + "zIndex" : "31", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.create_mission_xml", + "version" : "allTime", + "name" : "create_mission_xml" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "5ab7f7a5-72be-4789-bfc6-42e12f3cca65", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "3ec3b035-fa94-4fb4-951c-25bfdfa491fe", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "28defe30-f45f-4a6c-9c4d-117e96fede0b", + "name" : "create_mission_xml_reqs", + "location" : "722:800", + "zIndex" : "56", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.create_mission_xml", + "version" : "allTime", + "name" : "create_mission_xml" + }, + "configuration" : { + "storeComponentHistoryData" : "true" + }, + "staticInputs" : [ { + "identifier" : "5afa2be4-e393-4f0e-a845-43e248bb43a3", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "c078f515-d20e-4c72-b49e-f212365e2cc6", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "947b6847-a819-4c53-b4a2-14189fa2cfac", + "name" : "create_mission_xml_study", + "location" : "721:621", + "zIndex" : "30", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.create_mission_xml", + "version" : "allTime", + "name" : "create_mission_xml" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "89ef62b0-4026-4797-896d-18626b7dc471", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "0e386a25-2cfe-4eee-b337-c64927019041", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "name" : "design_sizing_loop", + "location" : "440:300", + "zIndex" : "1", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.converger", + "version" : "6", + "name" : "Converger" + }, + "configuration" : { + "epsA" : "0.01", + "epsR" : "0.0001", + "failLoopOnly-NAV_5e0ed1cd" : "false", + "faultTolerance-NAV_5e0ed1cd" : "Fail", + "finallyFailIfDiscarded-NAV_5e0ed1cd" : "false", + "isNestedLoop_5e0ed1cd" : "true", + "iterationsToConsider" : "1", + "loopFaultTolerance_5e0ed1cd" : "Fail", + "maxConvChecks" : "", + "maxRerunBeforeFail-NAV_5e0ed1cd" : "1", + "notConvFail" : "false", + "notConvIgnore" : "true", + "notConvNotAValue" : "false", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "6583c056-dcb9-41e7-8865-bb8f54d67b2a", + "name" : "accuracy_list", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "1636954f-2bc2-43a9-885e-7fa3f0e10565", + "name" : "accuracy_list_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "33877e48-87d5-4549-982c-9d0de1e8b82b", + "name" : "calibration_factors", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "dc605c7a-095c-411f-a6f1-74420fe41815", + "name" : "calibration_factors_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "d9e1391b-38db-463a-82cb-9428d929e36b", + "name" : "calibration_settings", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "db8d3c8a-0ffc-43c8-b052-c80f142b7573", + "name" : "calibration_settings_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "35716001-de65-49f4-ad8d-06f113af2ff3", + "name" : "cm_criuise", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "b68997ec-b2dd-4be5-9f23-5dca89c17dec", + "name" : "cm_criuise_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "ccc74d90-a965-4367-b2a7-868e991cd280", + "name" : "control_settings", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "bbd1d9d9-851b-4bf3-9505-7b2a28bc756a", + "name" : "control_settings_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "640949f1-7633-4785-939e-39b6e5fbe676", + "name" : "count_of_iteration", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "b960a680-9864-41b3-a86a-658df2b4e31d", + "name" : "count_of_iteration_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "ea776d0a-efa8-43c8-ab6f-67fecad1deb3", + "name" : "design_sizing_iteration_flag", + "epIdentifier" : "valueToConverge", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "hasStartValue" : "false", + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single", + "startValue" : "-" + } + }, { + "identifier" : "c950b61b-9947-4dde-9b8d-61a575fba946", + "name" : "design_sizing_iteration_flag_start", + "epIdentifier" : "startToConverge", + "group" : "startValues", + "datatype" : "Float" + }, { + "identifier" : "d5c3aa8b-c6d2-4cd7-825a-d58b2dbbc633", + "name" : "i_stab", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "7ecfd6fa-4ae0-4c4e-9db1-96e69c428514", + "name" : "i_stab_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "150a469e-2f3d-4c6b-8026-91ebd14a2cda", + "name" : "m_operating_empty_last", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "3469cd78-6ab0-40c0-a797-0fe805be23af", + "name" : "m_operating_empty_last_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "302d0238-826f-4a23-9266-1c7e53af3919", + "name" : "m_take_off_max_last", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "d895b097-3528-4831-8f5d-861103ae2ac4", + "name" : "m_take_off_max_last_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "e0a44e95-1a7b-4c2f-8dd1-44c62a15a571", + "name" : "mission_energy_last", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "8be52fd7-55cc-4187-b0bd-37960f867e9f", + "name" : "mission_energy_last_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "4654849e-20b1-4355-8275-bb4c3e0b78b9", + "name" : "module_list_of_sizing_loop", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "fbf1a57f-913a-4a36-8f5a-86b847b98c90", + "name" : "module_list_of_sizing_loop_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "f364243b-e947-41bf-a3dc-69c59d520780", + "name" : "mtom_loop_vector", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "a46ef22d-48af-42e6-8477-633e04722b6e", + "name" : "mtom_loop_vector_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "37a5f9ce-3fb5-4ec1-a69c-1b645698cf21", + "name" : "parameter_for_design_case", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "edd8e1ff-a43e-426a-93ad-4def45ac5928", + "name" : "parameter_for_design_case_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "dca29a23-e52f-43ba-8ef2-cb5d9597bfc8", + "name" : "paths_and_names", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "0e8ca26e-157a-4eaf-9d39-9d8462bb5c32", + "name" : "paths_and_names_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "6d1c8342-d5cd-4444-9d48-686d7abafdf9", + "name" : "trim_parameter_list", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "e05079fb-af2d-47a3-b58f-61f43209f9ff", + "name" : "trim_parameter_list_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "154e4935-f6cb-4c0b-bbf4-6914de746e5d", + "name" : "x_center_of_gravity_last", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "956a3ecc-f505-484e-ac25-e7e388199c04", + "name" : "x_center_of_gravity_last_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ], + "staticOutputs" : [ { + "identifier" : "3257a49c-b60b-4495-a1d0-306117e1346d", + "name" : "Converged", + "datatype" : "Boolean" + }, { + "identifier" : "ca8b35d3-6738-442b-b4ed-f8ff96313940", + "name" : "Converged absolute", + "datatype" : "Boolean" + }, { + "identifier" : "4dec3b91-4a18-4d85-b577-ac42f03fee18", + "name" : "Converged relative", + "datatype" : "Boolean" + }, { + "identifier" : "74444d72-67d4-4024-adf5-b2da3cc33357", + "name" : "Done", + "datatype" : "Boolean" + } ], + "dynamicOutputs" : [ { + "identifier" : "682fe369-864a-43c8-803b-28953e3bb98e", + "name" : "accuracy_list", + "epIdentifier" : "toForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "2c734a35-25bb-49dc-9541-2c204dbfeebd", + "name" : "accuracy_list_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "716e6d4c-63ab-4f40-9093-795b415d5c7b", + "name" : "calibration_factors", + "epIdentifier" : "toForward", + "datatype" : "Vector" + }, { + "identifier" : "751bb9ff-69fc-435d-a03c-88c1719e19aa", + "name" : "calibration_factors_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Vector" + }, { + "identifier" : "0e441ba5-d8cf-4b55-b583-14cd42abec47", + "name" : "calibration_settings", + "epIdentifier" : "toForward", + "datatype" : "SmallTable" + }, { + "identifier" : "7a8cc3d3-00f1-4974-8661-c99d1c2b7012", + "name" : "calibration_settings_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable" + }, { + "identifier" : "08c25001-21ee-439f-a18d-897ce2f19dbc", + "name" : "cm_criuise", + "epIdentifier" : "toForward", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "77c225cc-154f-4f6a-af9a-6bdcccd9bf2d", + "name" : "cm_criuise_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "e257f8d3-28df-4497-89ef-3a93421db21f", + "name" : "control_settings", + "epIdentifier" : "toForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "74e07ce5-9ad7-4d3a-b34f-66715320cd1e", + "name" : "control_settings_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "5f51ff00-b28a-4cae-8f04-2cf3277ce44e", + "name" : "count_of_iteration", + "epIdentifier" : "toForward", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "fa690dde-2dc7-4fde-b66d-08c3befe930a", + "name" : "count_of_iteration_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "a11c718f-550d-4158-a29f-a2e890003d08", + "name" : "design_sizing_iteration_flag", + "epIdentifier" : "valueToConverge", + "datatype" : "Float" + }, { + "identifier" : "accb5a3d-34c4-4232-94ad-f55c04eb400c", + "name" : "design_sizing_iteration_flag_converged", + "epIdentifier" : "finalToConverge", + "datatype" : "Float" + }, { + "identifier" : "893867fe-3f15-4d51-bc25-4db3a7a3b55a", + "name" : "design_sizing_iteration_flag_is_converged", + "epIdentifier" : "auxiliaryValue", + "datatype" : "Boolean" + }, { + "identifier" : "c12adbae-0974-4aa4-89f3-1f11fef1b188", + "name" : "i_stab", + "epIdentifier" : "toForward", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "02e39235-8bb7-483c-aadf-e561b699e88b", + "name" : "i_stab_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "09780450-0acc-4e67-8bff-a34c4b98800a", + "name" : "m_operating_empty_last", + "epIdentifier" : "toForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "d148b583-b70a-42fb-af1d-7d662bc8fa9c", + "name" : "m_operating_empty_last_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "21870ea7-d446-44ca-a636-7f0b692d5044", + "name" : "m_take_off_max_last", + "epIdentifier" : "toForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "cb62fb83-cf5d-4588-bf6b-fc66052be823", + "name" : "m_take_off_max_last_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "e764df4a-192f-40df-9642-a1ab3bd21f36", + "name" : "mission_energy_last", + "epIdentifier" : "toForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "467ebdc5-c690-4905-bf4e-f8143ae9672d", + "name" : "mission_energy_last_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "74e28b0b-0dbb-4381-a1db-e23ee96f45e5", + "name" : "module_list_of_sizing_loop", + "epIdentifier" : "toForward", + "datatype" : "SmallTable" + }, { + "identifier" : "2e7add2a-64ca-4733-b93f-b5ec981d9ab6", + "name" : "module_list_of_sizing_loop_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable" + }, { + "identifier" : "a6cd3ad4-cd5d-4431-afd6-691e095230f2", + "name" : "mtom_loop_vector", + "epIdentifier" : "toForward", + "datatype" : "Vector" + }, { + "identifier" : "24d085af-68f0-4aed-870d-4165cc6dae75", + "name" : "mtom_loop_vector_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Vector" + }, { + "identifier" : "0efa89f1-5a9b-43bb-8c35-45f9093a26b0", + "name" : "parameter_for_design_case", + "epIdentifier" : "toForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "f96c55de-f0b0-4dbd-8921-2743c93174a8", + "name" : "parameter_for_design_case_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "1ad2d3ce-d1e9-4c2f-93fa-b7ee8e19b3fd", + "name" : "paths_and_names", + "epIdentifier" : "toForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "f4e2a88c-1480-4b3d-9c78-05c0c6ddc963", + "name" : "paths_and_names_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "bd7d2bba-6de5-4ae7-be6e-b7d15b40d3b4", + "name" : "trim_parameter_list", + "epIdentifier" : "toForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "04c55dd5-8c43-4a78-b11d-096542820c78", + "name" : "trim_parameter_list_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "cddde916-3761-450e-96e5-a1b9f1b68279", + "name" : "x_center_of_gravity_last", + "epIdentifier" : "toForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "64954a3b-4039-4795-a58e-14dbdc8a1842", + "name" : "x_center_of_gravity_last_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ] + }, { + "identifier" : "edf5cb5c-763e-47b6-8c4e-ed9caad67051", + "name" : "design_sizing_trigger_switch", + "location" : "501:426", + "zIndex" : "19", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read RCE inputs for script execution '''\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npaths_and_names = RCE.read_input(\"paths_and_names\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n# import for python\r\nimport os\r\n\r\ncurrent_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1]\r\ndesign_mode = int(([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1])\r\npath_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1]\r\n\r\n# check if selected design mode equal to 3 or if exist a tool execution error -> if true: skip design sizing tool execution and trigger mission analysis loop\r\nif design_mode == 3 or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'):\r\n\tRCE.write_output(\"skip_design_sizing_flag\", current_workflow_name)\r\nelse:\r\n\tRCE.write_output(\"current_workflow_name\", current_workflow_name)\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "e5ff2ccd-a89f-4220-8116-e43ce9e52ef1", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "306c62a0-49b3-428c-9ab5-045bd249beec", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "8419db9e-bd31-4300-90a5-cb74c8151bc3", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "8792830c-790d-4731-89be-cc8ba7babc4c", + "name" : "skip_design_sizing_flag", + "epIdentifier" : "default", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "e6a4d26e-4d4b-4372-a75d-ebf2506c5fb5", + "name" : "ecological_assessment", + "location" : "1220:800", + "zIndex" : "51", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.ecological_assessment", + "version" : "allTime", + "name" : "ecological_assessment" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "true" + }, + "staticInputs" : [ { + "identifier" : "ac0ccefd-f1a5-4733-9d52-3fba7b59d19e", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "c8476e8b-c101-4b97-8de1-1cfd877d96a9", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "c19fa814-5c75-4125-a806-4f001b7ef00c", + "name" : "empennage_design", + "location" : "1021:426", + "zIndex" : "34", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.empennage_design", + "version" : "allTime", + "name" : "empennage_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "fce55bb5-eef6-4063-a880-95e76d04fba0", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "127cab9e-75e6-47d7-8744-b13a001a5f97", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "6c7d11a2-ff6b-411c-a7c4-5853d6471740", + "name" : "empennage_design_calibration", + "location" : "1525:21", + "zIndex" : "35", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.empennage_design", + "version" : "allTime", + "name" : "empennage_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "91c34b43-f459-4147-950e-c806bb4fc012", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "17e2ed99-0023-42b9-b4c3-5083dd119805", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "name" : "final_operations_of_mission_study_loop", + "location" : "380:729", + "zIndex" : "26", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "ScriptWhitespaceBox" : "true", + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read input values '''\r\n\r\naccuracy_list = RCE.read_input(\"accuracy_list\")\r\ncontrol_settings = RCE.read_input(\"control_settings\")\r\ncount_of_mission_study_loop = RCE.read_input(\"count_of_mission_study_loop\")\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npaths_and_names = RCE.read_input(\"paths_and_names\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read and set system path for python scripts '''\r\n\r\n# import for python\r\nimport os\r\nimport sys\r\n\r\nsys.path.insert(1, ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1])\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' final steps of mission study analysis loop '''\r\n\r\n# import python script\r\nfrom mission_study_loop.final_operations_of_study_loop import final_operations_of_study_loop\r\ncurrent_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1]\r\npath_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1]\r\n\r\n# function call for final operations of the mission study analysis loop -> combines results to a csv file\r\n# inputs: paths_and_names, control_settings\r\n# returns: none\r\n\r\nfinal_operations_of_study_loop(paths_and_names, control_settings, parameter_for_design_case)\r\n([item for item in parameter_for_design_case if 'count_of_mission_study_loop' in item])[-1][-1] = count_of_mission_study_loop\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' outputs for workflow '''\r\n# check if a tool execution error exist -> if true: skip mission study loop and trigger post operations of workflow\r\nif os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat') or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/pre_sizing_error.dat') or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/design_sizing_error.dat'):\r\n\tif os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'):\r\n\t\t# genereate error status flag of mission study analysis loop\r\n\t\tmission_study_error_dat = open(path_of_working_directory_rce + current_workflow_name + '/temp/mission_study_error.dat', 'a+')\r\n\t\tmission_study_error_dat.close()\r\n\t\r\n\t\t# delete old error status flag\r\n\t\tos.remove(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat')\r\n\r\n\r\n\tRCE.write_output(\"skip_post_operations_flag\", current_workflow_name)\r\n\tRCE.write_output(\"control_settings\", control_settings)\r\n\tRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\r\n\tRCE.write_output(\"paths_and_names\", paths_and_names)\r\n\tRCE.write_output(\"accuracy_list\", accuracy_list)\r\nelse:\r\n\t# set final_operations_of_mission_study_loop results to RCE outputs\r\n\tRCE.write_output(\"accuracy_list\", accuracy_list)\r\n\tRCE.write_output(\"current_workflow_name\", current_workflow_name)\r\n\tRCE.write_output(\"control_settings\", control_settings)\r\n\tRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\r\n\tRCE.write_output(\"paths_and_names\", paths_and_names)\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "f1962cf4-f57f-495c-a32e-c8354f9a29fb", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "81c72d11-9eea-41ff-b2db-ced65f32bc34", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "14a3a9e9-6af2-49c6-afce-d72b2c170670", + "name" : "count_of_mission_study_loop", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "dcbcae17-9f15-4e2a-9aae-0d6c29c1468f", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "48cf0d95-4fa0-40d0-82cd-d8d4aebe922b", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "755d4508-8019-44da-87be-7ebe24332fe2", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "e1888fda-8c50-4a32-a05a-9c97028d6b2b", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "ceb4e534-01ef-4dc2-9c22-46026321a3ec", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "81fdc0a4-19df-4206-b0c7-fd757759d82c", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "70dfcec6-e41d-4196-845f-c902e42544c3", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "0ad0138a-52de-4868-b98c-aceeb960b1a2", + "name" : "skip_post_operations_flag", + "epIdentifier" : "default", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "9e1e145e-2348-49ae-88d5-94ffbf0bbcc4", + "name" : "final_operations_of_sizing_loop", + "location" : "380:426", + "zIndex" : "6", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "ScriptWhitespaceBox" : "true", + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read input values '''\r\naccuracy_list = RCE.read_input(\"accuracy_list\")\r\ncontrol_settings = RCE.read_input(\"control_settings\")\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npaths_and_names = RCE.read_input(\"paths_and_names\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read and set system path for python scripts '''\r\n\r\n# import for python\r\nimport sys\r\n\r\nsys.path.insert(1, ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1])\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' final steps of design sizing loop '''\r\ndesign_mode = int(([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1])\r\n\r\n# check if selected design mode is not equal to 3 -> if true: skip final operations of design sizing loop\r\nif not design_mode == 3:\r\n\tstatus_flag_to_skip = True\r\n\r\n\t# import python script\r\n\tfrom design_sizing_loop.final_operations_of_sizing_loop import final_operations_of_sizing_loop\r\n\t\r\n\t# function call for final operations of the desig sizing loop -> combines results to a csv file\r\n\t# inputs: paths_and_names\r\n\t# returns: none\r\n\t\r\n\tfinal_operations_of_sizing_loop(paths_and_names)\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\nRCE.write_output(\"output_flag_design_sizing_complete\", 1)\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "23ccac1c-147e-4abb-b0a4-f38c58227cfe", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "15508c4d-b775-49fd-8a9b-71bd1220aecf", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "16aa0097-47d2-47a6-9a2b-230a5a321783", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "779b50ba-f3e6-4d4e-920d-5f09a3a0d1ad", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "8ca02537-9b99-4ccc-9ba8-24e053dcf915", + "name" : "output_flag_design_sizing_complete", + "epIdentifier" : "default", + "datatype" : "Boolean" + } ] + }, { + "identifier" : "a8f0662b-83ca-45ed-b29a-2331931148ee", + "name" : "fuselage_design", + "location" : "821:426", + "zIndex" : "27", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.fuselage_design", + "version" : "allTime", + "name" : "fuselage_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "e5f2df51-817f-4394-a96a-e8e04a5abbe1", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "e845278f-088d-454d-9454-de118f4fbc67", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "8609525a-c3d9-4b70-97cc-e8889652b357", + "name" : "fuselage_design_calibration", + "location" : "1534:140", + "zIndex" : "61", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.fuselage_design", + "version" : "allTime", + "name" : "fuselage_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "true" + }, + "staticInputs" : [ { + "identifier" : "9d2e8fba-6e6b-48f1-ab40-d5742a26b38e", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "32e9f1d0-c0c4-419f-8baf-59cdf23368f9", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "df71fc65-60d1-4dcb-9bfc-67424c6db107", + "name" : "initial_sizing", + "location" : "480:112", + "zIndex" : "28", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.initial_sizing", + "version" : "allTime", + "name" : "initial_sizing" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "cc578fb7-01fc-441a-9e7c-6d8a6cf03ac8", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "058d22a8-e8cf-48c7-8ac3-85d328edf4c1", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "name" : "initialize_design_sizing_loop", + "location" : "320:300", + "zIndex" : "0", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "ScriptWhitespaceBox" : "true", + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read RCE inputs for script execution '''\r\naccuracy_list = RCE.read_input(\"accuracy_list\")\r\ncalibration_settings = RCE.read_input(\"calibration_settings\")\r\ncontrol_settings = RCE.read_input(\"control_settings\")\r\nmodule_list_of_sizing_loop = RCE.read_input(\"module_list_of_sizing_loop\")\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npaths_and_names = RCE.read_input(\"paths_and_names\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read and set system path for python scripts '''\r\n\r\n# import for python\r\nimport os\r\nimport sys\r\nfrom datetime import datetime\r\n\r\nsys.path.insert(1, ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1])\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' set values to initialize design sizing loop and auto-trim function '''\r\n\r\n# import python script\r\nfrom design_sizing_loop.initialize_design_sizing_loop import initialize_design_sizing_loop\r\n\r\n# function call for initialize design sizing loop and auto-trim function -> set initial values and auto-trim parameter\r\n# inputs: paths_and_names, parameter_for_design_case, control_settings\r\n# returns: design_variables, trim_parameter_list, mtom_loop_vector\r\n\r\ndesign_variables, trim_parameter_list, mtom_loop_vector = initialize_design_sizing_loop(paths_and_names, parameter_for_design_case, control_settings)\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' set values to initialize calibartion and set initial values for calibration loop '''\r\n\r\n# import python script\r\nfrom design_sizing_loop.initialize_calibration import initialize_calibration\r\n\r\n# read OME and MTOM calibration flag from calibration settings to activate or skip calibration\r\nperform_calibration = int(([item for item in calibration_settings if 'free_variable_OME_calibration' in item])[-1][-1] > 0 or ([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1] > 0)\r\n\r\n# check if perform_calibration flag is set to active -> if true: -> initialize calibration mode\r\nif perform_calibration:\r\n\t# function call for initialize calibartion -> set initial values for calibration loop\r\n\t# inputs: paths_and_names, parameter_for_design_case, control_settings\r\n\t# returns: calibration_settings\r\n\t\r\n\tcalibration_settings = initialize_calibration(paths_and_names, calibration_settings)\r\n\t\r\nelse:\r\n\tcalibration_settings.append(['calibrate_ome_flag', int(0)])\r\n\tcalibration_settings.append(['calibrate_mtom_flag', int(0)])\r\n\tcalibration_settings.append(['number_of_final_runs', int(0)])\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' check for error handling '''\r\n\r\ncurrent_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1]\r\npath_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1]\r\n\r\n# check if error in tool execution -> if true: -> print error message to workflow log-file and console\r\nif os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'):\r\n\t# genereate error status flag of pre-sizing steps\r\n\tpre_sizing_error_dat = open(path_of_working_directory_rce + current_workflow_name + '/temp/pre_sizing_error.dat', 'a+')\r\n\tpre_sizing_error_dat.close()\r\n\t\r\n\t# delete old error status flag\r\n\tos.remove(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat')\r\n\r\n\t# generate log-file ouput\r\n\tlog_file_list = []\r\n\tcharacter_length_of_date_and_time = 21\r\n\t\r\n\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Error in pre-sizing tool execution!')\r\n\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': At least one of the enabled pre-sizing tools has send an error. The actual design sizing loop is failed and will be canceled!')\r\n\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': If parameter study or optimization is selected, current loop of iteration will skipped and the next iteration will be performed!')\r\n\t\r\n\t## write log-file to system\r\n\tlog_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a')\r\n\t# loop across all elements of log-file list to print to workflow console and write to workflow log-file\r\n\tfor row in log_file_list:\r\n\t# print current log-file list entry to workflow console\r\n\t\tprint(row[character_length_of_date_and_time:])\r\n\r\n\t# write current entry of log-file list to workflow log-file\r\n\t\tlog_file.write(row + '\\n')\r\n\tlog_file.close()\r\n\r\n\r\n''' outputs for workflow '''\r\n# set initialize_design_sizing_loop results to RCE outputs\r\nRCE.write_output(\"accuracy_list\", accuracy_list)\r\nRCE.write_output(\"calibration_settings\", calibration_settings)\r\nRCE.write_output(\"calibration_factors\", [0.0])\r\nRCE.write_output(\"cm_cruise\", ([item for item in trim_parameter_list if 'cm_cruise' in item])[-1][-1])\r\nRCE.write_output(\"control_settings\", control_settings)\r\nRCE.write_output(\"count_of_iteration\", ([item for item in parameter_for_design_case if 'count_of_iteration' in item])[-1][-1])\r\nRCE.write_output(\"design_sizing_iteration_flag\", 0.0)\r\nRCE.write_output(\"i_stab\", ([item for item in trim_parameter_list if 'i_stab' in item])[-1][-1])\r\nRCE.write_output(\"mission_energy\", ([item for item in design_variables if 'mission_energy' in item])[-1][-1])\r\nRCE.write_output(\"m_operating_empty\", ([item for item in design_variables if 'm_operating_empty' in item])[-1][-1])\r\nRCE.write_output(\"m_take_off_max\", ([item for item in design_variables if 'm_take_off_max' in item])[-1][-1])\r\nRCE.write_output(\"module_list_of_sizing_loop\", module_list_of_sizing_loop)\r\nRCE.write_output(\"mtom_loop_vector\", mtom_loop_vector)\r\nRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\r\nRCE.write_output(\"paths_and_names\", paths_and_names)\r\ntrim_parameter_list.remove(['cm_cruise', ([item for item in trim_parameter_list if 'cm_cruise' in item])[-1][-1]])\r\ntrim_parameter_list.remove(['i_stab', ([item for item in trim_parameter_list if 'i_stab' in item])[-1][-1]])\r\nRCE.write_output(\"trim_parameter_list\", trim_parameter_list)\r\nRCE.write_output(\"x_center_of_gravity\", ([item for item in design_variables if 'x_center_of_gravity' in item])[-1][-1])\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW", + "xor" : "false" + }, + "dynamicInputs" : [ { + "identifier" : "7990a966-1476-40e1-bcbb-81bdd7f49380", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "6c580b92-0035-42e9-85b9-7abc17ef738e", + "name" : "calibration_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "727b53e3-5430-4328-ad44-b639878fc14f", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "0fc7f8f7-2f8e-4017-8941-e971cbbb1681", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "379aa1c7-3afe-4381-a199-9e46a762afd4", + "name" : "module_list_of_sizing_loop", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "fb8d926e-91e3-4e22-a9c6-4c2c1e8521b7", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "dc9f124c-35db-4e94-9eab-cf0a537821de", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "e6338d1b-e34e-42cf-aa5e-f00d34bf33a8", + "name" : "trigger_signal", + "epIdentifier" : "default", + "datatype" : "Boolean", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "RequiredIfConnected", + "inputHandling_73b1056e" : "Single" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "ca24ddc6-34a5-439a-9757-90693255d91a", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "1808c4c8-286d-4665-ac5a-32c698f285b5", + "name" : "calibration_factors", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "9da1a5a7-637f-4bf0-8aad-77b599b1e3b2", + "name" : "calibration_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "32520df2-079b-4976-a100-08c0944877cb", + "name" : "cm_cruise", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "2c78d2e1-589c-419f-8ad1-8cf60f6c14cc", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "40a0386c-a4d1-4435-84c0-3b88030d451a", + "name" : "count_of_iteration", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "b34da647-0654-4218-8e0c-49d5128ae7b7", + "name" : "design_sizing_iteration_flag", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "ac95f46f-e42e-4049-9514-90f2c9424b3d", + "name" : "i_stab", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "dfb96afb-22d2-46f8-aedd-a9a124d69c99", + "name" : "m_operating_empty", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "313efdc9-70e0-4a43-938a-b9a3605be47f", + "name" : "m_take_off_max", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "a5a5e791-280e-4008-88c0-1ae45c44fd6e", + "name" : "mission_energy", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "fa0bd568-e34b-4212-a4c2-2ae2ff553df5", + "name" : "module_list_of_sizing_loop", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "763ac133-1b9d-4014-8ef3-a5b985d7ab59", + "name" : "mtom_loop_vector", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "21003046-697c-42e6-95d4-cd5704721fc1", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "5d6a4e15-5230-43df-95c0-691592bec82b", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "6048ca28-60b2-4b2c-ba76-e8db612dca14", + "name" : "trim_parameter_list", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "78a4fc90-03f2-4214-9628-11261c364e31", + "name" : "x_center_of_gravity", + "epIdentifier" : "default", + "datatype" : "Float" + } ] + }, { + "identifier" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "name" : "initialize_mission_study_analysis", + "location" : "320:621", + "zIndex" : "3", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "ScriptWhitespaceBox" : "true", + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read input values '''\r\n\r\naccuracy_list = RCE.read_input(\"accuracy_list\")\r\ncontrol_settings = RCE.read_input(\"control_settings\")\r\nmodule_list_of_sizing_loop = RCE.read_input(\"module_list_of_sizing_loop\")\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npaths_and_names = RCE.read_input(\"paths_and_names\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read and set system path for python scripts '''\r\n\r\n# import for python\r\nimport os\r\nimport sys\r\n\r\nsys.path.insert(1, ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1])\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\ncurrent_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1]\r\npath_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1]\r\n\r\n# check if a tool execution error exist -> if true: skip mission study loop and trigger post operations of workflow\r\nif os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat') or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/pre_sizing_error.dat'):\r\n\tif os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'):\r\n\t\t# genereate error status flag of design sizing loop\r\n\t\tdesign_sizing_error_dat = open(path_of_working_directory_rce + current_workflow_name + '/temp/design_sizing_error.dat', 'a+')\r\n\t\tdesign_sizing_error_dat.close()\r\n\t\r\n\t\t# delete old error status flag\r\n\t\tos.remove(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat')\r\n\t\r\n\t# set exeption paramter to skip mission study analysis \r\n\tmission_study_variables = [['m_take_off_max_study', 0.0],\r\n\t\t\t\t\t\t\t\t['mission_energy_study', 0.0],\r\n\t\t\t\t\t\t\t\t['range_study', 0.0],\r\n\t\t\t\t\t\t\t\t['fl_initial_cruise_study', 0.0]]\r\n\t\r\nelse:\r\n\t''' initialize the mission study sizing loop to perform off design analysis '''\r\n\t# import python script\r\n\tfrom mission_study_loop.initialize_mission_study_analysis import initialize_mission_study_analysis\r\n\t\r\n\t# function call for initialize mission study analysis loop -> set initial design variables of mission study analysis to output list of lists\r\n\t# inputs: paths_and_names, control_settings, parameter_for_design_case\r\n\t# returns: mission_study_variables\r\n\t\r\n\tmission_study_variables = initialize_mission_study_analysis(paths_and_names, control_settings, parameter_for_design_case, module_list_of_sizing_loop)\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' outputs for workflow '''\r\n# set initalize_mission_study_analysis results to RCE outputs\r\nRCE.write_output(\"accuracy_list\", accuracy_list)\r\nRCE.write_output(\"control_settings\", control_settings)\r\nRCE.write_output(\"count_of_mission_study_loop\", 0)\r\nRCE.write_output(\"convergence_criteria\", ([item for item in parameter_for_design_case if 'convergence_criteria' in item])[-1][-1])\r\nRCE.write_output(\"fl_initial_cruise_study\", ([item for item in mission_study_variables if 'fl_initial_cruise_study' in item])[-1][-1])\r\nRCE.write_output(\"mission_energy_study\", ([item for item in mission_study_variables if 'mission_energy_study' in item])[-1][-1])\r\nRCE.write_output(\"m_take_off_max_study\", ([item for item in mission_study_variables if 'm_take_off_max_study' in item])[-1][-1])\r\nRCE.write_output(\"mission_study_iteration_flag\", 0)\r\nRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\r\nRCE.write_output(\"paths_and_names\", paths_and_names)\r\nRCE.write_output(\"range_study\", ([item for item in mission_study_variables if 'range_study' in item])[-1][-1])\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW", + "xor" : "false" + }, + "dynamicInputs" : [ { + "identifier" : "8b4c4b74-d5b4-482f-9449-bfcfcddce96b", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "e96b6156-6ef7-416b-a707-f1d22898adcb", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "dcf6e010-cf9e-45c8-b065-e1213eb00575", + "name" : "input_flag_initalize_mission_study", + "epIdentifier" : "default", + "datatype" : "Boolean", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "RequiredIfConnected", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "fdc7d4fd-8d9e-410f-a570-22a27d6a023e", + "name" : "module_list_of_sizing_loop", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "54504ea4-9974-47da-b223-770bc1ee3c58", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "27344f89-5ec6-44f4-9a6d-42c626ee63e5", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "4a3aebf6-4d93-426b-a321-2eab306e03cc", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "bd9ee66f-7a48-4547-ba42-7e86204c511a", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "5b06959c-faff-4d03-a6e7-ac1949ecc35f", + "name" : "convergence_criteria", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "ce22ba8c-8d85-4a45-9f67-5f9878ac57da", + "name" : "count_of_mission_study_loop", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "a27abc62-af66-4756-92f3-2fcc12b9836d", + "name" : "fl_initial_cruise_study", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "d7152fad-be82-435b-95bd-51bb1157908e", + "name" : "m_take_off_max_study", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "de9a7e75-a928-4049-8e81-bf93cb63d27a", + "name" : "mission_energy_study", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "7fd4a49c-19a6-4212-956b-9386965dc368", + "name" : "mission_study_iteration_flag", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "72b17cdf-ef01-4d67-b365-bd1f9dfb5605", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "cbd1b14f-e34a-48e8-aadd-c01091d66b0d", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "01c7e151-a74e-4ee1-9849-b2888927937f", + "name" : "range_study", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "b2bdfac6-11ac-4039-8d4e-f1c4dd5e5a2d", + "name" : "reset_control_settings_at_exit", + "epIdentifier" : "default", + "datatype" : "Boolean" + } ] + }, { + "identifier" : "23f0a309-d793-4b6c-871c-483486428971", + "name" : "landing_gear_design", + "location" : "845:321", + "zIndex" : "38", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.landing_gear_design", + "version" : "allTime", + "name" : "landing_gear_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "59410051-cf52-4d79-8ce4-5c6a6de4bbb1", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "e98ca659-d6e6-4588-a48e-baca06fc038f", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "993a2aeb-4334-4b80-9ca0-29f1c1d22051", + "name" : "landing_gear_design_calibration", + "location" : "1320:21", + "zIndex" : "39", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.landing_gear_design", + "version" : "allTime", + "name" : "landing_gear_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "b29edafa-8aba-4815-b671-57983057d591", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "b302a2c7-909c-4a87-9ae3-63657bcf2d7c", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "16d82d24-4bb4-43d0-bc7d-18c8d64907f0", + "name" : "mission_analysis", + "location" : "1416:321", + "zIndex" : "46", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.mission_analysis", + "version" : "allTime", + "name" : "mission_analysis" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "d027ba57-01ea-46f2-b527-34b2ab979283", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "75b47bd7-9c07-4380-9425-b538b322868c", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "be1fbd21-d6c5-4c72-9dc2-8569dd06be27", + "name" : "mission_analysis_reqs", + "location" : "921:800", + "zIndex" : "55", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.mission_analysis", + "version" : "allTime", + "name" : "mission_analysis" + }, + "configuration" : { + "storeComponentHistoryData" : "true" + }, + "staticInputs" : [ { + "identifier" : "e8035ea0-32fb-4bc9-abfe-1a01a5907268", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "7cf80042-5928-4e85-8089-a2eb13e2efb7", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "1c0c576d-5990-479a-9153-95a741ed9974", + "name" : "mission_analysis_study", + "location" : "921:621", + "zIndex" : "47", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.mission_analysis", + "version" : "allTime", + "name" : "mission_analysis" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "f69149ea-2f1d-4155-b2f3-6ddc62688a60", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "23f0992b-0d4e-4051-a869-27a98296f60e", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "name" : "mission_study_analysis_loop", + "location" : "441:621", + "zIndex" : "4", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.converger", + "version" : "6", + "name" : "Converger" + }, + "configuration" : { + "epsA" : "0.01", + "epsR" : "0.0001", + "failLoopOnly-NAV_5e0ed1cd" : "false", + "faultTolerance-NAV_5e0ed1cd" : "Fail", + "finallyFailIfDiscarded-NAV_5e0ed1cd" : "false", + "isNestedLoop_5e0ed1cd" : "true", + "iterationsToConsider" : "1", + "maxRerunBeforeFail-NAV_5e0ed1cd" : "1", + "notConvFail" : "false", + "notConvIgnore" : "true", + "notConvNotAValue" : "false", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "242fac67-7f81-4f4c-b95a-39f6dfbfd645", + "name" : "accuracy_list", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "b8459983-1bca-4289-b4ab-4f071d2201f5", + "name" : "accuracy_list_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "791c2a6a-aa7f-4fb8-bf16-71776ebe9752", + "name" : "control_settings", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "fa5d0ad1-dcfa-4172-8406-d12ba4ec274d", + "name" : "control_settings_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "eb8849b3-6930-4552-93cc-89a9a23c7a17", + "name" : "convergence_criteria", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "7bc1ff55-6103-4c4d-b2d8-7cbb2b3f4ab6", + "name" : "convergence_criteria_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "a84331da-9be9-41d1-9946-2df6f617528e", + "name" : "count_of_mission_study_loop", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "6985ecc3-fa99-45df-9f47-24cd146b1179", + "name" : "count_of_mission_study_loop_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "f4e56642-289e-4733-b647-b944caf25307", + "name" : "fl_initial_cruise_study_backUp", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "1291b281-dbdf-40f4-8702-c84f4fcbab87", + "name" : "fl_initial_cruise_study_backUp_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "3bbb41a9-42bb-4393-869a-58b995e0ef30", + "name" : "m_take_off_max_study_backUp", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "0b1957f4-fe2d-43ed-9a1c-63a7dd394f2e", + "name" : "m_take_off_max_study_backUp_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "2bc5348d-9f21-4ecf-aa31-a08b6194ef31", + "name" : "mission_energy_study_backUp", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "8b35a366-4b08-4dd5-bd77-be6cf8c2784d", + "name" : "mission_energy_study_backUp_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "338d261f-e913-4897-9b50-2896fcfe34c5", + "name" : "mission_study_iteration_flag", + "epIdentifier" : "valueToConverge", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "hasStartValue" : "false", + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single", + "startValue" : "-" + } + }, { + "identifier" : "a3dfd495-8558-496b-91c8-22cbe9d08e0c", + "name" : "mission_study_iteration_flag_start", + "epIdentifier" : "startToConverge", + "group" : "startValues", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required" + } + }, { + "identifier" : "afb1f9eb-4034-4893-8d5d-0f8030d66a3d", + "name" : "parameter_for_design_case", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "22c49d66-3621-4809-8042-ee14250cacdf", + "name" : "parameter_for_design_case_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "341d1d71-802f-4e4e-980c-648758531829", + "name" : "paths_and_names", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "8e23ab3b-e27e-4150-ba34-1d5b8307a94a", + "name" : "paths_and_names_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "bd009583-baf5-4dee-8b9b-94e056818f0b", + "name" : "range_study_backUp", + "epIdentifier" : "toForward", + "group" : "valuesToConverge", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "cb4785f2-820f-4d31-902d-94aa3672bbe0", + "name" : "range_study_backUp_start", + "epIdentifier" : "startToForward", + "group" : "startValues", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ], + "staticOutputs" : [ { + "identifier" : "82f334bc-923f-4ed8-883b-56e68ee23310", + "name" : "Converged", + "datatype" : "Boolean" + }, { + "identifier" : "72a50669-e853-4923-ab7c-a6ca204fccf7", + "name" : "Converged absolute", + "datatype" : "Boolean" + }, { + "identifier" : "508fb050-737b-44b1-90cf-5e1c57fbceca", + "name" : "Converged relative", + "datatype" : "Boolean" + }, { + "identifier" : "0203adea-9da4-4393-853f-503904ec196b", + "name" : "Done", + "datatype" : "Boolean" + } ], + "dynamicOutputs" : [ { + "identifier" : "be11fe82-0d5d-4930-b8db-cb273d8017cb", + "name" : "accuracy_list", + "epIdentifier" : "toForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "d227f8e2-e09d-4586-a2fd-6077bc69fef6", + "name" : "accuracy_list_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "b176fb50-afe8-47a0-9f8a-617e2974818f", + "name" : "control_settings", + "epIdentifier" : "toForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "bcce8b67-d5aa-411c-8878-4baae70bef06", + "name" : "control_settings_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "6e9e6d71-b3fb-4def-8be5-3034be6fcbc5", + "name" : "convergence_criteria", + "epIdentifier" : "toForward", + "datatype" : "Float" + }, { + "identifier" : "b84f2502-9870-45e2-81ee-fd9bee94b920", + "name" : "convergence_criteria_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Float" + }, { + "identifier" : "caa15f3e-e102-4773-be31-97a1b3abd023", + "name" : "count_of_mission_study_loop", + "epIdentifier" : "toForward", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "9feb2dfe-0bb2-442f-b519-f46920e03628", + "name" : "count_of_mission_study_loop_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "7daa4d82-fb53-43d1-b9e5-6ee49a4734a6", + "name" : "fl_initial_cruise_study_backUp", + "epIdentifier" : "toForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "23f2fd34-de62-4663-a24d-4f46d75a66ea", + "name" : "fl_initial_cruise_study_backUp_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "3b3383f9-58b7-43f7-bc89-d40f9db4aac9", + "name" : "m_take_off_max_study_backUp", + "epIdentifier" : "toForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "ce4f74c7-ad92-4c25-9f6b-993532e418d8", + "name" : "m_take_off_max_study_backUp_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "a35a2ffc-55fd-4262-a82f-33b0e4c6f4a5", + "name" : "mission_energy_study_backUp", + "epIdentifier" : "toForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "bdc4a1b2-f02a-413b-8db6-a002e66670a8", + "name" : "mission_energy_study_backUp_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "988c519e-6c29-4839-afcf-06e6aa6c8d7d", + "name" : "mission_study_iteration_flag", + "epIdentifier" : "valueToConverge", + "datatype" : "Float" + }, { + "identifier" : "f446fb1f-6554-4eb0-85bb-05714e18d296", + "name" : "mission_study_iteration_flag_converged", + "epIdentifier" : "finalToConverge", + "datatype" : "Float" + }, { + "identifier" : "bc160d50-2d0e-45bc-9feb-e1097f2a1386", + "name" : "mission_study_iteration_flag_is_converged", + "epIdentifier" : "auxiliaryValue", + "datatype" : "Boolean" + }, { + "identifier" : "75d9b559-894f-4726-a771-bcd2d70ef697", + "name" : "parameter_for_design_case", + "epIdentifier" : "toForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "9053b71b-c081-469c-bdc6-61ee126209cf", + "name" : "parameter_for_design_case_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "45cfd1f4-eef3-44a6-a38a-8e69895448db", + "name" : "paths_and_names", + "epIdentifier" : "toForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "9b2a2be5-d704-4b0b-8292-caf14662ed49", + "name" : "paths_and_names_converged", + "epIdentifier" : "finalToForward", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "211923a4-8df8-4502-a1f2-7f035c9ac79a", + "name" : "range_study_backUp", + "epIdentifier" : "toForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "c6d39ae6-894a-4691-bbdd-fb1e6a49e8ba", + "name" : "range_study_backUp_converged", + "epIdentifier" : "finalToForward", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ] + }, { + "identifier" : "c9104e19-a903-48f7-819a-6268462a5b26", + "name" : "mission_study_trigger_joiner", + "location" : "660:540", + "zIndex" : "25", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.joiner", + "version" : "3.3", + "name" : "Joiner" + }, + "configuration" : { + "datatype" : "ShortText", + "inputCount" : "2", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "950760b1-4eb4-4be3-8946-4c39b3c83386", + "name" : "Input 001", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + }, { + "identifier" : "44f3f882-9ab5-4586-869a-9d41816bfce5", + "name" : "Input 002", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "25af7c46-672b-4bc1-a34d-4e5972069549", + "name" : "Joined", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "492e4c3a-c719-44af-b20a-9e1b9ff89bfe", + "name" : "mission_study_trigger_switch", + "location" : "501:729", + "zIndex" : "24", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read RCE inputs for script execution '''\r\n\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npaths_and_names = RCE.read_input(\"paths_and_names\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' import for python '''\r\n\r\nimport os\r\n\r\ncurrent_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1]\r\ndesign_mode = int(([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1])\r\npath_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1]\r\n\r\n# check if selected design mode equal to 4 or if exist a tool execution error -> if true: skip mission study tool execution and trigger post operations of workflow\r\nif design_mode == 4 or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat') or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/pre_sizing_error.dat') or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/design_sizing_error.dat'):\r\n\tRCE.write_output(\"skip_mission_study_flag\", current_workflow_name)\r\nelse:\r\n\tRCE.write_output(\"current_workflow_name\", current_workflow_name)\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "2a2ee247-7f95-4af6-915d-9cc32b948ee5", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "7558d879-a8f0-4c56-a1e0-3693baeac211", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "333b4005-e00e-4bc1-bfe6-f32acf3ce542", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "2bd06159-cb0f-48b4-b73d-6c692467806f", + "name" : "skip_mission_study_flag", + "epIdentifier" : "default", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "a8816b37-0dd8-45aa-bb19-4a13fe74ee31", + "name" : "moe_calibration_joiner", + "location" : "1033:160", + "zIndex" : "16", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.joiner", + "version" : "3.3", + "name" : "Joiner" + }, + "configuration" : { + "datatype" : "ShortText", + "inputCount" : "2", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "46974d86-e51e-406a-bcde-3c5dd45b9df4", + "name" : "Input 001", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + }, { + "identifier" : "d42c609e-1c3d-4c5d-a3b4-47ebc6fc16ae", + "name" : "Input 002", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "e9115015-6833-4ba6-8d30-2d13eca1c6a7", + "name" : "Joined", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "name" : "nested_loop_control", + "location" : "161:300", + "zIndex" : "13", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read input values '''\r\nglobal_loop_counter = RCE.read_input(\"global_loop_counter\")\r\nidentifier = RCE.read_input(\"identifier\")\r\noptimization_status_flag = RCE.read_input(\"optimization_status_flag\")\r\nouter_loop_counter = RCE.read_input(\"outer_loop_counter\")\r\nparameter_study_status_flag = RCE.read_input(\"parameter_study_status_flag\")\r\nstudy_counter = RCE.read_input(\"study_counter\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n''' read and set system path for python scripts '''\r\n\r\n# import for python\r\nimport os\r\nimport sys\r\nimport shutil\r\nimport time\r\nimport xml.etree.ElementTree\r\nfrom datetime import datetime\r\n\r\n# read sys path for python scripts\r\nuser_path_string = os.path.expanduser(\"~\")\r\n\r\n# convert path of curent working directory to a python path -> \\ to /\r\nuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n# generate sys paths from file in .rce-directory\r\ninstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\ninstall_path_directory = str(install_path.read())\r\ninstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n# path of workflow python scripts\r\npath_to_python_scripts = install_path_directory + 'workingDirectoryRCE/UNICADOworkflow/src'\r\nsys.path.insert(1, path_to_python_scripts)\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' initialize local paramter '''\r\nparameter_name = str('no parameter')\r\nnew_value_of_input = float(0.0)\r\nglobal_loop_counter_old = global_loop_counter\r\nidentifier_old = identifier\r\n\r\n# check if the calculation of the reference case is not successful finished \r\n# -> if true: -> set global_loop_counter to abort the parameter study and abort the workflow\r\nif global_loop_counter == 2:\r\n\tabort_flag = False\r\n\tpreparation_status = 0\r\n\t# read current workflow name from identifier *.dat file\r\n\tidentifier_file = open(install_path_directory + 'workingDirectoryRCE/identifier/' + str(identifier) + '.dat', 'r')\r\n\tcurrent_workflow_name = identifier_file.read()\r\n\tidentifier_file.close()\r\n\tpath_to_temp = install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/temp/'\r\n\r\n\tif os.path.isfile(path_to_temp + 'convergenceError.dat') or os.path.isfile(path_to_temp + 'workflowExecutionError.dat'):\r\n\t\tglobal_loop_counter = outer_loop_counter + 1\r\n\t\tabort_flag = True\r\n\t\r\n\t# check if optimization should be perfomed\r\n\tif optimization_status_flag == 1 and not abort_flag:\r\n\t\t# import for python\r\n\t\tfrom pre_condition.prepare_optimization import prepare_optimization \r\n\t\t\r\n\t\t# call function to reset parameter for next optimization loop\r\n\t\t# inputs: install_path_directory, current_workflow_name, global_loop_counter\r\n\t\t# returns: preparation_status\r\n\t\tpreparation_status = prepare_optimization(install_path_directory, current_workflow_name, global_loop_counter)\r\n\t\t\r\n\t\t# copy src code of optimization framework to current working directory\r\n\t\twhile_count = 0\r\n\t\twhile True:\r\n\t\t\t#if os.path.isdir(install_path_directory + 'workingDirectoryRCE/UNICADOworkflow/src/optimization'):\r\n\t\t\ttry:\r\n\t\t\t\tshutil.copytree(install_path_directory + 'workingDirectoryRCE/UNICADOworkflow/src/optimization',\r\n\t\t\t\t\t\t\t\tinstall_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/optimization')\r\n\t\t\t\tprint('The optimization directory was copied successfully.')\r\n\t\t\t\tbreak\r\n\t\t\texcept OSError:\r\n\t\t\t\tif while_count == 10:\r\n\t\t\t\t\tprint('Warning: The optimization directory could not be copied. Copy operation is skipped.')\r\n\t\t\t\t\tbreak\r\n\t\t\t\twhile_count += 1\r\n\t\t\t\tprint('Warning: Try to copy the optimization directory to the temporary working directory, but no response from the system.')\r\n\t\t\t\tprint('Retry ' + str(while_count) + ' of 10!')\r\n\t\t\t\ttime.sleep(3)\t\r\n\t\t\t#else:\r\n\t\t\t\t#perform_workflow_execution = 0\r\n\t\t\t\t#abort_flag = True\r\n\t\t\t\t#break\r\n\t\t\t\r\n\t\tif not abort_flag and preparation_status == 1:\r\n\t\t\t# generate semaphore flags for workflow and optimizer to wait for execution\r\n\t\t\tif not os.path.isfile(path_to_temp + 'semaphoreFlagOptimization.dat'):\r\n\t\t\t\tsemaphore_optimization = open(path_to_temp + 'semaphoreFlagOptimization.dat', 'w')\r\n\t\t\t\tsemaphore_optimization.close()\r\n\t\t\t\t\r\n\t\t\tif not os.path.isfile(path_to_temp + 'semaphoreFlagWorkflowExecution.dat'):\r\n\t\t\t\tsemaphore_workflow = open(path_to_temp + 'semaphoreFlagWorkflowExecution.dat', 'w')\r\n\t\t\t\tsemaphore_workflow.close()\r\n\t\t\t\t\r\n\t\t\tperform_workflow_execution = 1\r\n\t\t\touter_loop_counter = outer_loop_counter + 1\r\n\t\t\tRCE.write_output(\"identifier_for_clean_up\", identifier)\r\n\t\t\tRCE.write_output(\"start_optimization\", current_workflow_name)\r\n\t\telif abort_flag or preparation_status == 0:\r\n\t\t\tprint('Error: Something went wrong during preparation of optimization. Abort workflow!')\t\r\n\t\t\tperform_workflow_execution = 0\r\n\r\n\t\r\n\telif optimization_status_flag == 1 and (abort_flag or preparation_status == 0):\r\n\t\tperform_workflow_execution = 0\r\n\r\n#----------------------------------------------------------------------------------------------------------------\r\n\r\n# perform first design prozess to generate reference aircraft\r\nif global_loop_counter == 1:\r\n\t# import for python\r\n\tfrom pre_condition.generate_identifier import generate_identifier\r\n\r\n\t''' generate workflow name of current execution '''\r\n\tcurrent_workflow_name = 'UNICADOworkflow_' + str(datetime.now().strftime('%Y-%m-%d_%H-%M-%S_%f')[:-4])\r\n\t\r\n\t# call function to genertate the identifier dat-file of current workflow execution\r\n\t# inputs: install_path_directory, current_workflow_name\r\n\t# returns: identifier\r\n\tidentifier = generate_identifier(install_path_directory, current_workflow_name)\r\n\t\r\n\t''' create a new temporary status folder '''\r\n\tif not os.path.isdir(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name):\r\n\t\tos.makedirs(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/temp')\r\n\t\r\n\t''' copy current workflow configuration file to temporary working directory '''\r\n\twhile_count = 0\r\n\twhile True:\r\n\t\tif not os.path.isfile(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/unicado_workflow_conf.xml'):\r\n\t\t\tif not os.path.isfile(install_path_directory + 'workingDirectoryRCE/UNICADOworkflow/unicado_workflow_conf.xml'):\r\n\t\t\t\tperform_workflow_execution = 0\r\n\t\t\t\tbreak\r\n\t\t\t\t\r\n\t\t\telse:\r\n\t\t\t\ttry:\r\n\t\t\t\t\tshutil.copyfile(install_path_directory + 'workingDirectoryRCE/UNICADOworkflow/unicado_workflow_conf.xml', \r\n\t\t\t\t\t\t\t\t\tinstall_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/unicado_workflow_conf.xml')\r\n\t\t\t\t\tprint('The unicado_workflow_conf.xml file was copied successfully.')\r\n\t\t\t\t\tbreak\r\n\t\t\t\t\t\r\n\t\t\t\texcept OSError:\r\n\t\t\t\t\tif while_count == 10:\r\n\t\t\t\t\t\tprint('Warning: The unicado_workflow_conf.xml could not be copied. Copy operation is skipped.')\r\n\t\t\t\t\t\tbreak\r\n\t\t\t\t\twhile_count += 1\r\n\t\t\t\t\tprint('Warning: Try to copy the unicado_workflow_conf.xml to the temporary working directory, but no response from the system.')\r\n\t\t\t\t\tprint('Retry ' + str(while_count) + ' of 10!')\r\n\t\t\t\t\ttime.sleep(3)\r\n\t\telse:\r\n\t\t\tbreak\r\n\t\t\r\n\t''' read xml-file as element tree '''\r\n\twhile_count = 0\r\n\twhile True:\r\n\t\tif os.path.isfile(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/unicado_workflow_conf.xml'):\r\n\t\t\ttry:\r\n\t\t\t\txml_tree = xml.etree.ElementTree.ElementTree(file=install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/unicado_workflow_conf.xml')\r\n\t\t\t\troot_of_workflow_tree = xml_tree.getroot()\r\n\t\t\t\t_program_mode = root_of_workflow_tree.find(\"./program_settings/program_mode/value\").text\r\n\t\t\t\t\r\n\t\t\t\t# Translation of modes into human readable text\r\n\t\t\t\tprogram_mode_dict = {\r\n\t\t\t\t\t'mode_0' : 'standard_aircraft_design',\r\n\t\t\t\t\t'mode_1' : 'parameter_study',\r\n\t\t\t\t\t'mode_2' : 'optimization'\r\n\t\t\t\t} \t\t\t\r\n\t\t\t\t\r\n\t\t\t\tif program_mode_dict[_program_mode] == 'standard_aircraft_design':\r\n\t\t\t\t\tidentifier = identifier_old\r\n\t\t\t\tbreak\r\n\t\t\t\t\r\n\t\t\texcept OSError:\r\n\t\t\t\tif while_count == 10:\r\n\t\t\t\t\tprint('Warning: The unicado_workflow_conf.xml could not be opend. Initialization is skipped.')\r\n\t\t\t\t\tbreak\r\n\t\t\t\twhile_count += 1\r\n\t\t\t\tprint('Warning: Try to read unicado_workflow_conf.xml file, but no response from the system.')\r\n\t\t\t\tprint('Retry ' + str(while_count) + ' of 10!')\r\n\t\t\t\ttime.sleep(3)\r\n\t\telse:\r\n\t\t\tbreak\r\n\t\t\r\n\t\r\n\t''' copy range type specific factors file to temporary working directory '''\r\n\twhile_count = 0\r\n\twhile True:\r\n\t\tif not os.path.isfile(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/range_type_specific_factors.xml'):\r\n\t\t\ttry:\r\n\t\t\t\tshutil.copyfile(install_path_directory + 'workingDirectoryRCE/UNICADOworkflow/range_type_specific_factors.xml', \r\n\t\t\t\t\t\t\t\tinstall_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/range_type_specific_factors.xml')\r\n\t\t\t\tprint('The range_type_specific_factors.xml file was copied successfully.')\r\n\t\t\t\tbreak\t\r\n\t\t\t\r\n\t\t\texcept OSError:\r\n\t\t\t\tif while_count == 10:\r\n\t\t\t\t\tprint('Warning: The range_type_specific_factors.xml could not be copied. Copy operation is skipped.')\r\n\t\t\t\t\tbreak\r\n\t\t\t\twhile_count += 1\r\n\t\t\t\tprint('Warning: Try to copy the range_type_specific_factors.xml to the temporary working directory, but no response from the system.')\r\n\t\t\t\tprint('Retry ' + str(while_count) + ' of 10!')\r\n\t\t\t\ttime.sleep(3)\t\r\n\t\telse:\r\n\t\t\tbreak\r\n\t\t\t\t\r\n\t''' copy parameter study manager configuration file to temporary working directory '''\r\n\twhile_count = 0\r\n\twhile True:\r\n\t\tif not os.path.isfile(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/parameter_study_conf.xml'):\r\n\t\t\ttry:\r\n\t\t\t\tshutil.copyfile(install_path_directory + 'workingDirectoryRCE/UNICADOworkflow/parameter_study_conf.xml', \r\n\t\t\t\t\t\t\t\tinstall_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/parameter_study_conf.xml')\r\n\t\t\t\tprint('The parameter_study_conf.xml file was copied successfully.')\r\n\t\t\t\tbreak\r\n\t\t\t\t\r\n\t\t\texcept OSError:\r\n\t\t\t\tif while_count == 10:\r\n\t\t\t\t\tprint('Warning: The parameter_study_conf.xml could not be copied. Copy operation is skipped.')\r\n\t\t\t\t\tbreak\r\n\t\t\t\twhile_count += 1\r\n\t\t\t\tprint('Warning: Try to copy the parameter_study_conf.xml to the temporary working directory, but no response from the system.')\r\n\t\t\t\tprint('Retry ' + str(while_count) + ' of 10!')\r\n\t\t\t\ttime.sleep(3)\r\n\t\telse:\r\n\t\t\tbreak\r\n\t\t\t\r\n\t''' copy parameter study value file to temporary working directory '''\r\n\twhile_count = 0\r\n\twhile True:\r\n\t\tif not os.path.isfile(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/parameter_study_values.csv'):\r\n\t\t\ttry:\r\n\t\t\t\tshutil.copyfile(install_path_directory + 'workingDirectoryRCE/UNICADOworkflow/parameter_study_values.csv', \r\n\t\t\t\t\t\t\t\tinstall_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/parameter_study_values.csv')\r\n\t\t\t\tprint('The parameter_study_values.csv file was copied successfully.')\r\n\t\t\t\tbreak\r\n\t\t\t\t\r\n\t\t\texcept OSError:\r\n\t\t\t\tif while_count == 10:\r\n\t\t\t\t\tprint('Warning: The parameter_study_values.csv could not be copied. Copy operation is skipped.')\r\n\t\t\t\t\tbreak\r\n\t\t\t\twhile_count += 1\r\n\t\t\t\tprint('Warning: Try to copy the parameter_study_values.csv to the temporary working directory, but no response from the system.')\r\n\t\t\t\tprint('Retry ' + str(while_count) + ' of 10!')\r\n\t\t\t\ttime.sleep(3)\r\n\t\telse:\r\n\t\t\tbreak\r\n\t\r\n\t''' copy optimization configuration file to temporary working directory '''\r\n\twhile_count = 0\r\n\twhile True:\r\n\t\tif not os.path.isfile(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/optimization_conf.xml'):\r\n\t\t\ttry:\r\n\t\t\t\tshutil.copyfile(install_path_directory + 'workingDirectoryRCE/UNICADOworkflow/optimization_conf.xml', \r\n\t\t\t\t\t\t\t\tinstall_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/optimization_conf.xml')\r\n\t\t\t\tprint('The optimization_conf.xml file was copied successfully.')\r\n\t\t\t\tbreak\r\n\t\t\t\t\r\n\t\t\texcept OSError:\r\n\t\t\t\tif while_count == 10:\r\n\t\t\t\t\tprint('Warning: The optimization_conf.xml could not be copied. Copy operation is skipped.')\r\n\t\t\t\t\tbreak\r\n\t\t\t\twhile_count += 1\r\n\t\t\t\tprint('Warning: Try to copy the optimization_conf.xml to the temporary working directory, but no response from the system.')\r\n\t\t\t\tprint('Retry ' + str(while_count) + ' of 10!')\r\n\t\t\t\ttime.sleep(3)\r\n\t\telse:\r\n\t\t\tbreak\r\n\t\r\n\tperform_workflow_execution = 1\r\n\t\r\n\tRCE.write_output(\"identifier_for_clean_up\", identifier_old)\r\n\r\n#----------------------------------------------------------------------------------------------------------------\r\n\r\n# Perform further design iterations if optimization or parameter study has been selected.\r\nelif global_loop_counter <= outer_loop_counter:\r\n\t# read current workflow name from identifier *.dat file\r\n\tidentifier_file = open(install_path_directory + 'workingDirectoryRCE/identifier/' + str(identifier) + '.dat', 'r')\r\n\tcurrent_workflow_name = identifier_file.read()\r\n\tidentifier_file.close()\r\n\t\r\n\t# path to temp directory of current working directory\r\n\tpath_to_temp = install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/temp/'\r\n\t\r\n\t# check if parameter study should be perfomed\r\n\tif parameter_study_status_flag == 1:\r\n\t\t# import for python\r\n\t\tfrom parameter_study.perform_parameter_study import perform_parameter_study\r\n\t\t\r\n\t\tperform_workflow_execution = 1\r\n\t\tRCE.write_output(\"identifier_for_clean_up\", identifier)\r\n\t\t\r\n\t\t# Call function to Set parameter of current parameter study loop\t\r\n\t\t# inputs: install_path_directory, study_counter, outer_loop_counter, global_loop_counter_old, perform_workflow_execution\r\n\t\t# returns: outer_loop_counter, study_counter, parameter_name, new_value_of_input\r\n\t\touter_loop_counter, study_counter, parameter_name, new_value_of_input = perform_parameter_study(install_path_directory, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstudy_counter, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\touter_loop_counter, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tglobal_loop_counter_old, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tperform_workflow_execution, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcurrent_workflow_name)\r\n\t\t\r\n\t\t# remove old error flags for next run of parameter study\r\n\t\tif os.path.isfile(path_to_temp + 'workflowExecutionError.dat'):\r\n\t\t\tos.remove(path_to_temp + 'workflowExecutionError.dat')\r\n\t\tif os.path.isfile(path_to_temp + 'pre_sizing_error.dat'):\r\n\t\t\tos.remove(path_to_temp + 'pre_sizing_error.dat')\r\n\t\tif os.path.isfile(path_to_temp + 'design_sizing_error.dat'):\r\n\t\t\tos.remove(path_to_temp + 'design_sizing_error.dat')\r\n\t\tif os.path.isfile(path_to_temp + 'mission_study_error.dat'):\r\n\t\t\tos.remove(path_to_temp + 'mission_study_error.dat')\r\n\t\tif os.path.isfile(path_to_temp + 'post_operation_error.dat'):\r\n\t\t\tos.remove(path_to_temp + 'post_operation_error.dat')\r\n\r\n\tif global_loop_counter > 2:\r\n\t\t# check if the optimization should be performed -> if true: -> generate semaphore flags\r\n\t\tif optimization_status_flag == 1:\r\n\t\t\tpreparation_status = 0\r\n\t\t\t\r\n\t\t\t# import for python\r\n\t\t\tfrom pre_condition.prepare_optimization import prepare_optimization \r\n\t\t\r\n\t\t\t# call function to reset parameter for next optimization loop\r\n\t\t\t# inputs: install_path_directory, current_workflow_name, global_loop_counter\r\n\t\t\t# returns: preparation_status\r\n\t\t\tpreparation_status = prepare_optimization(install_path_directory, current_workflow_name, global_loop_counter)\r\n\t\t\r\n\t\t\t# remove semaphore flag to perform preperation steps of optimization framework\r\n\t\t\tif os.path.isfile(path_to_temp + 'semaphoreFlagOptimizationPreparation.dat'):\r\n\t\t\t\tos.remove(path_to_temp + 'semaphoreFlagOptimizationPreparation.dat')\r\n\t\t\t\r\n\t\t\t# check if the preparation for optimation was successful -> if true: -> set outputs to perform optimization and workflow execution\r\n\t\t\tif preparation_status == 1:\r\n\t\t\t\tperform_workflow_execution = 1\r\n\t\t\t\touter_loop_counter = outer_loop_counter + 1\r\n\t\t\t\tRCE.write_output(\"identifier_for_clean_up\", identifier)\r\n\t\t\t\r\n\t\t\t# else condtion: preparation for optimization failed -> termiate workflow and abort optimiaztion framework\r\n\t\t\telse:\r\n\t\t\t\tperform_workflow_execution = 0\r\n\r\n#----------------------------------------------------------------------------------------------------------------\r\n\t\r\n# terminates the workflow after finishing selected design process\r\nelse:\r\n\t# read current workflow name from identifier *.dat file\r\n\tidentifier_file = open(install_path_directory + 'workingDirectoryRCE/identifier/' + str(identifier) + '.dat', 'r')\r\n\tcurrent_workflow_name = identifier_file.read()\r\n\tidentifier_file.close()\r\n\t\r\n\tif parameter_study_status_flag == 1:\r\n\t\t# import for python\r\n\t\tfrom parameter_study.perform_parameter_study import perform_parameter_study\r\n\t\t\r\n\t\tperform_workflow_execution = 0\r\n\t\t\r\n\t\t# Call function to Set parameter of current parameter study loop\t\r\n\t\t# inputs: install_path_directory, study_counter, outer_loop_counter, global_loop_counter_old, perform_workflow_execution\r\n\t\t# returns: outer_loop_counter, study_counter, parameter_name, new_value_of_input\r\n\t\touter_loop_counter, study_counter, parameter_name, new_value_of_input = perform_parameter_study(install_path_directory, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tstudy_counter, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\touter_loop_counter, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tglobal_loop_counter_old, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tperform_workflow_execution, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcurrent_workflow_name)\r\n\telse:\r\n\t\tperform_workflow_execution = 0\r\n\t\r\n\t# delete identifier file of current workflow execution\r\n\tos.remove(install_path_directory + 'workingDirectoryRCE/identifier/' + str(identifier) + '.dat')\r\n\tif len(os.listdir(install_path_directory + 'workingDirectoryRCE/identifier/')) == 0:\r\n\t\ttry:\r\n\t\t\tos.rmdir(install_path_directory + 'workingDirectoryRCE/identifier/')\r\n\t\t\r\n\t\texcept OSError:\r\n\t\t\tprint('Identifier directory could not be deleted! Its currentlly in use by an other process!')\r\n\t\t\r\n\t# delete temporary workflow directory of current workflow execution\r\n\twhile_count = 0\r\n\twhile True:\r\n\t\ttry:\r\n\t\t\tshutil.rmtree(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name)\r\n\t\t\tprint('The temporary working directory was deleted successfully.')\r\n\t\t\tbreak\r\n\t\t\t\r\n\t\texcept OSError:\r\n\t\t\tif while_count == 10:\r\n\t\t\t\tprint('Warning: The temporary working directory could not be deleted. Delete operation is skipped.')\r\n\t\t\t\tbreak\r\n\t\t\twhile_count += 1\r\n\t\t\tprint('Warning: Try to delete the temporary working directory, but no response from the system.')\r\n\t\t\tprint('Retry ' + str(while_count) + ' of 10!')\r\n\t\t\ttime.sleep(3)\r\n\t\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' outputs for workflow '''\r\nRCE.write_output(\"current_workflow_name\", current_workflow_name)\r\nRCE.write_output(\"global_loop_counter\", global_loop_counter_old)\r\nRCE.write_output(\"identifier\", identifier)\r\nRCE.write_output(\"install_path_directory\", install_path_directory)\r\nRCE.write_output(\"new_value_of_input\", new_value_of_input)\r\nRCE.write_output(\"optimization_status_flag\", optimization_status_flag)\r\nRCE.write_output(\"outer_loop_counter\", outer_loop_counter)\r\nRCE.write_output(\"parameter_name\", parameter_name)\r\nRCE.write_output(\"parameter_study_status_flag\", parameter_study_status_flag)\r\nRCE.write_output(\"path_to_python_scripts\", path_to_python_scripts)\r\nRCE.write_output(\"perform_workflow_execution\", perform_workflow_execution)\r\nRCE.write_output(\"study_counter\", study_counter)\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "74b1a73c-a723-468f-8113-7d7c326ff791", + "name" : "global_loop_counter", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "RequiredIfConnected", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "3d69d4b8-2729-4e4e-8f35-e945f40dba35", + "name" : "identifier", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "a33bcfc2-92a4-47aa-8214-c36d3ddffe82", + "name" : "optimization_status_flag", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "RequiredIfConnected", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "cef6af4f-e718-4ea9-8323-098e6372519b", + "name" : "outer_loop_counter", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "RequiredIfConnected", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "df6e35c6-aa83-4fbb-840c-17440539ffad", + "name" : "outer_loop_status_flag", + "epIdentifier" : "default", + "datatype" : "Boolean", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "26bd5353-8194-4ab0-9963-35e32f0412c9", + "name" : "parameter_study_status_flag", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "549e15de-5e5b-4a59-864d-0bed12687070", + "name" : "study_counter", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "36b96c16-6b90-42e9-98d0-7ee5542950b9", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "966bb476-e753-4564-88d1-21ff42092c7b", + "name" : "global_loop_counter", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "f1817b7c-6edf-4d78-a085-067dd1deaba3", + "name" : "identifier", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "1dc950fd-7c78-4a64-86b4-de4f5b3ab580", + "name" : "identifier_for_clean_up", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "a79bf8d3-decc-4ddd-850e-9ba11b22263b", + "name" : "install_path_directory", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "96ee8c0d-7629-42c9-a66e-7e1aea4bdc09", + "name" : "new_value_of_input", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "f3230fa2-8f12-43a8-8742-8e457bcaf0c0", + "name" : "optimization_status_flag", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "98963b28-462e-4aa2-9784-182c0139fbfc", + "name" : "outer_loop_counter", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "29e2c7fc-43ac-4880-ad6b-6bd6e325aa7f", + "name" : "parameter_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "b18b05e2-5d79-4de4-8343-484ba76588ec", + "name" : "parameter_study_status_flag", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "63a83bb6-8d80-45d0-9334-87ab856721c3", + "name" : "path_to_python_scripts", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "af3cf777-aeb0-4d80-9051-71fc78393b3f", + "name" : "perform_workflow_execution", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "844951cf-4b50-49d9-9a4e-e02f6da15c16", + "name" : "start_optimization", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "dc83a264-f1e5-49bc-bd1c-f471165edbe7", + "name" : "study_counter", + "epIdentifier" : "default", + "datatype" : "Integer" + } ] + }, { + "identifier" : "8addc91f-83b8-4964-b588-72d53784d5ff", + "name" : "optimization", + "location" : "160:146", + "zIndex" : "49", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "\r\ncurrent_workflow_name = RCE.read_input(\"current_workflow_name\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read and set system path for python scripts '''\r\n\r\n# import for python\r\nimport os\r\nimport sys\r\nimport shutil\r\nimport time\r\nfrom datetime import datetime\r\n\r\n# read sys path for python scripts\r\nuser_path_string = os.path.expanduser(\"~\")\r\n\r\n# convert path of curent working directory to a python path -> \\ to /\r\nuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n# generate sys paths from file in .rce-directory\r\ninstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\ninstall_path_directory = str(install_path.read())\r\ninstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n# add working directory path to python paths\r\npath_to_python_optimization = install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/optimization'\r\nsys.path.insert(1, path_to_python_optimization)\r\n\r\n# read sys path for python scripts\r\nuser_path_string = os.path.expanduser(\"~\")\r\n\r\n# convert path of curent working directory to a python path -> \\ to /\r\nuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n# generate sys paths from file in .rce-directory\r\ninstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\ninstall_path_directory = str(install_path.read())\r\ninstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n# path of workflow python scripts\r\npath_to_python_scripts = install_path_directory + 'workingDirectoryRCE/UNICADOworkflow/src'\r\nsys.path.insert(1, path_to_python_scripts)\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' set paths for python scripts to generate '''\r\n\r\npath_to_userinput_file = install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/optimization/_userinput.py'\r\npath_to_new_userinput_file = install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/optimization/userinput.py'\r\npath_to_main_file = install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/optimization/_main.py'\r\npath_to_new_main_file = install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/optimization/main.py'\r\n\r\n# wait 5 seconds before check if the working directory exist to avoid runtime execution error in case of an error in the first loop execution\r\ntime.sleep(5)\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' write python script files for current workflow execution '''\r\n\r\nif os.path.isdir(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name):\r\n\t# set absolute path of the working directory of current workflow execution to the userinput.py function\r\n\tcontent_of_file = open(path_to_userinput_file, 'r')\r\n\tnew_file = open(path_to_new_userinput_file, 'w')\r\n\tpath_string = '\\ path_to_current_working_dir = ' + \"'\" + install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + \"'\" + '\\n'\r\n\t\r\n\tfor line in content_of_file:\r\n\t\tif line == \" path_to_current_working_dir = 'path'\\n\":\r\n\t\t\tnew_file.write(path_string[1:])\r\n\t\telse:\r\n\t\t\tnew_file.write(line)\r\n\t\t\r\n\tnew_file.close()\r\n\tcontent_of_file.close()\r\n\t\r\n\t# set absolute path of the working directory of current workflow execution to the main.py function\r\n\tcontent_of_file = open(path_to_main_file, 'r')\r\n\tnew_file = open(path_to_new_main_file, 'w')\r\n\tpath_string = '\\path_to_current_working_dir = ' + \"'\" + install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + \"'\" + '\\n'\r\n\t\r\n\tfor line in content_of_file:\r\n\t\tif line == \"path_to_current_working_dir = 'path'\\n\":\r\n\t\t\tnew_file.write(path_string[1:])\r\n\t\telse:\r\n\t\t\tnew_file.write(line)\r\n\t\t\r\n\tnew_file.close()\r\n\tcontent_of_file.close()\r\n\t\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' start the optimization framework '''\r\n\r\n# import for python\r\nimport main\r\n\r\n# call function to run the optimization framework\r\nmain()\r\n\r\n# remove temporary python path from python system paths\r\nsys.path.remove(path_to_python_scripts)\r\n\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "79250d52-28db-4296-89cc-f39f9d5ebc48", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ] + }, { + "identifier" : "85d83a8f-a440-45a9-bb41-aa819f6971e5", + "name" : "outer_loop_joiner", + "location" : "181:520", + "zIndex" : "15", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.joiner", + "version" : "3.3", + "name" : "Joiner" + }, + "configuration" : { + "datatype" : "Integer", + "inputCount" : "2", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "9a800c80-ada8-4f24-853c-86257dbb01f7", + "name" : "Input 001", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "Integer" + }, { + "identifier" : "3e154e0d-1b8d-42ec-93fa-1f3df7dc1317", + "name" : "Input 002", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "Integer" + } ], + "staticOutputs" : [ { + "identifier" : "6f80ad4d-8ecd-4a9b-b170-b86c132806b9", + "name" : "Joined", + "datatype" : "Integer" + } ] + }, { + "identifier" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "name" : "parameter_study_and_optimization_loop", + "location" : "161:401", + "zIndex" : "14", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.converger", + "version" : "6", + "name" : "Converger" + }, + "configuration" : { + "epsA" : "0.1", + "epsR" : "0.1", + "failLoopOnly-NAV_5e0ed1cd" : "false", + "finallyFailIfDiscarded-NAV_5e0ed1cd" : "false", + "isNestedLoop_5e0ed1cd" : "false", + "iterationsToConsider" : "1", + "maxRerunBeforeFail-NAV_5e0ed1cd" : "1", + "notConvFail" : "false", + "notConvIgnore" : "true", + "notConvNotAValue" : "false", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "a0c66ab2-8251-4efc-8ff4-146060523828", + "name" : "global_loop_counter", + "epIdentifier" : "valueToConverge", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "hasStartValue" : "true", + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single", + "startValue" : "1" + } + }, { + "identifier" : "3deb37ee-aa02-4f86-b8e3-afcb670ebaab", + "name" : "identifier", + "epIdentifier" : "valueToConverge", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "hasStartValue" : "true", + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single", + "startValue" : "0" + } + }, { + "identifier" : "eea0fca0-3bbd-43da-bbe5-e9d1c9f0cc8b", + "name" : "optimization_status_flag", + "epIdentifier" : "valueToConverge", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "hasStartValue" : "true", + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single", + "startValue" : "0" + } + }, { + "identifier" : "96e44b99-4408-4d9f-a5c1-a114b1f75147", + "name" : "outer_loop_counter", + "epIdentifier" : "valueToConverge", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "hasStartValue" : "true", + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single", + "startValue" : "2" + } + }, { + "identifier" : "d9ff462e-00ac-4bcf-a803-ef6320f3573d", + "name" : "parameter_study_status_flag", + "epIdentifier" : "valueToConverge", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "hasStartValue" : "true", + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single", + "startValue" : "0" + } + }, { + "identifier" : "a24bac44-e8c5-43bb-aab8-29c9c0d8b7a6", + "name" : "study_counter", + "epIdentifier" : "valueToConverge", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "hasStartValue" : "true", + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single", + "startValue" : "0" + } + }, { + "identifier" : "77675aa6-f349-41bb-86fa-f9e1bae105aa", + "name" : "workflow_status", + "epIdentifier" : "valueToConverge", + "group" : "valuesToConverge", + "datatype" : "Integer", + "metadata" : { + "hasStartValue" : "true", + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single", + "startValue" : "1" + } + } ], + "staticOutputs" : [ { + "identifier" : "d1e042f8-c183-4c31-be3b-1b72dab4d548", + "name" : "Converged", + "datatype" : "Boolean" + }, { + "identifier" : "d3aecf79-d07a-4dc0-9f7c-66862bb62d64", + "name" : "Converged absolute", + "datatype" : "Boolean" + }, { + "identifier" : "b00fa0ae-2f9c-468d-8530-f9d15fcea386", + "name" : "Converged relative", + "datatype" : "Boolean" + }, { + "identifier" : "7f88683c-7840-4a0b-a0f0-d7b7d42d914f", + "name" : "Done", + "datatype" : "Boolean" + } ], + "dynamicOutputs" : [ { + "identifier" : "f720d7b0-1138-4128-ad7d-9646441ae362", + "name" : "global_loop_counter", + "epIdentifier" : "valueToConverge", + "datatype" : "Integer" + }, { + "identifier" : "0dea6d17-3586-489b-9e79-4addcac7f1d3", + "name" : "global_loop_counter_converged", + "epIdentifier" : "finalToConverge", + "datatype" : "Integer" + }, { + "identifier" : "7f651e4f-8728-4dff-8420-afb0f97a73e4", + "name" : "global_loop_counter_is_converged", + "epIdentifier" : "auxiliaryValue", + "datatype" : "Boolean" + }, { + "identifier" : "9b0f7feb-d595-453b-891b-d8cf44ba44c1", + "name" : "identifier", + "epIdentifier" : "valueToConverge", + "datatype" : "Integer" + }, { + "identifier" : "968838c1-470c-4065-a5e8-291579276ad3", + "name" : "identifier_converged", + "epIdentifier" : "finalToConverge", + "datatype" : "Integer" + }, { + "identifier" : "7ea6f71b-a6f7-4369-86c1-e097ec02226d", + "name" : "identifier_is_converged", + "epIdentifier" : "auxiliaryValue", + "datatype" : "Boolean" + }, { + "identifier" : "23502b9d-a83c-4748-bda2-c527e24c74cc", + "name" : "optimization_status_flag", + "epIdentifier" : "valueToConverge", + "datatype" : "Integer" + }, { + "identifier" : "5960fc75-c28e-4408-8a10-c90ac47c3fc8", + "name" : "optimization_status_flag_converged", + "epIdentifier" : "finalToConverge", + "datatype" : "Integer" + }, { + "identifier" : "cd24ab93-eaa2-456a-9c88-f735efdc4ba4", + "name" : "optimization_status_flag_is_converged", + "epIdentifier" : "auxiliaryValue", + "datatype" : "Boolean" + }, { + "identifier" : "4b25f2d1-2c2c-4106-b646-702ed9d3b3dd", + "name" : "outer_loop_counter", + "epIdentifier" : "valueToConverge", + "datatype" : "Integer" + }, { + "identifier" : "ba83bff2-cb9f-46bf-b0c6-f9041f9ff864", + "name" : "outer_loop_counter_converged", + "epIdentifier" : "finalToConverge", + "datatype" : "Integer" + }, { + "identifier" : "7af74b17-d21c-46c6-aa25-75e4d303d80a", + "name" : "outer_loop_counter_is_converged", + "epIdentifier" : "auxiliaryValue", + "datatype" : "Boolean" + }, { + "identifier" : "01ce0bfa-1b5a-4993-bbb1-0e720dd1cec1", + "name" : "parameter_study_status_flag", + "epIdentifier" : "valueToConverge", + "datatype" : "Integer" + }, { + "identifier" : "dc684dca-a8f1-4635-b4ab-2d0ca0f6b449", + "name" : "parameter_study_status_flag_converged", + "epIdentifier" : "finalToConverge", + "datatype" : "Integer" + }, { + "identifier" : "8fd72b84-7102-4bda-ac80-6bc9e1533bf5", + "name" : "parameter_study_status_flag_is_converged", + "epIdentifier" : "auxiliaryValue", + "datatype" : "Boolean" + }, { + "identifier" : "9c73eb58-8157-4e2e-9ef9-9002f8610c1b", + "name" : "study_counter", + "epIdentifier" : "valueToConverge", + "datatype" : "Integer" + }, { + "identifier" : "63c445a8-5423-4e0c-9ff2-3a0ceb81aea4", + "name" : "study_counter_converged", + "epIdentifier" : "finalToConverge", + "datatype" : "Integer" + }, { + "identifier" : "5f9194c1-ecfe-4c32-b260-90fc07568664", + "name" : "study_counter_is_converged", + "epIdentifier" : "auxiliaryValue", + "datatype" : "Boolean" + }, { + "identifier" : "d569eca8-aa5a-4183-b059-61afd9a6897e", + "name" : "workflow_status", + "epIdentifier" : "valueToConverge", + "datatype" : "Integer" + }, { + "identifier" : "bbff1f6c-e200-4116-885f-ecef7728b379", + "name" : "workflow_status_converged", + "epIdentifier" : "finalToConverge", + "datatype" : "Integer" + }, { + "identifier" : "d86aa6b3-f798-471d-9d2a-78ec0af1cddf", + "name" : "workflow_status_is_converged", + "epIdentifier" : "auxiliaryValue", + "datatype" : "Boolean" + } ] + }, { + "identifier" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "name" : "perform_ome_calibration", + "location" : "1095:140", + "zIndex" : "12", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "\n#------------------------------------------------------------------------------------------------------------------------\n\n''' read input values '''\ncurrent_workflow_name = RCE.read_input(\"current_workflow_name\")\ncalibration_factors = RCE.read_input(\"calibration_factors\")\nome_calibration_flag = RCE.read_input(\"ome_calibration_flag\")\ncalibration_settings = RCE.read_input(\"calibration_settings\")\ncount_of_calibration = RCE.read_input(\"count_of_calibration\")\nome_loop_vector = RCE.read_input(\"ome_loop_vector\")\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\npaths_and_names = RCE.read_input(\"paths_and_names\")\nperform_calibration = RCE.read_input(\"perform_calibration\")\nskip_moe_calibration = RCE.read_input(\"skip_moe_calibration\")\n\nold_ome_calibration_flag = ome_calibration_flag\n\n#------------------------------------------------------------------------------------------------------------------------\n\n''' read and set system path for python scripts '''\n\n# import for python\nimport os\nimport sys\n\nsys.path.insert(1, ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1])\n\n#------------------------------------------------------------------------------------------------------------------------\n\nfrom datetime import datetime\n\nlog_file_list = []\ncount_of_calibration = count_of_calibration + 1\npath_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1]\n\n# check if moe-calibration must be performed\nif perform_calibration == 1 and skip_moe_calibration == 0:\n\tif count_of_calibration == 2:\n\t\tprint(\"--- Start iteration for OME calibration: 2 ---\")\n\t\tlog_file_list.append(\"\")\n\t\tlog_file_list.append(\"--- Start iteration for OME calibration: 2 ---\")\n\t\tlog_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a')\n\t\tfor row in log_file_list:\n\t\t\tlog_file.write(row + '\\n')\n\t\tlog_file.close()\n\t\tlog_file_list = []\n\t\n\t''' perform next steps of OME iteration loop '''\n\t\n\t# import python script\n\tfrom calibration.perform_ome_iteration import perform_ome_iteration\n\t\n\t# function call tp perform ome iteration steps and -> set values of current ome loop\n\t# inputs: paths_and_names, calibration_settings, ome_loop_vector, convergence_criteria, parameter_for_design_case, count_of_calibration\n\t# returns: calibration_settings, ome_loop_vector, calibration_factors\n\t\t\t\n\tcalibration_settings, ome_loop_vector, calibration_factors, = perform_ome_iteration(paths_and_names, calibration_settings, \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tome_loop_vector, parameter_for_design_case, \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tcalibration_factors, count_of_calibration)\n\t\n\tcalibrate_ome_flag = ([item for item in calibration_settings if 'calibrate_ome_flag' in item])[-1][-1]\n\titeration_flag = ([item for item in calibration_settings if 'iteration_flag' in item])[-1][-1]\n\t\n\tif calibrate_ome_flag == 1:\n\t\tprint(\"--- Start iteration for OME calibration: \" + str(count_of_calibration + 1) + \" ---\")\n\t\tlog_file_list.append(\"\")\n\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ' --- Start iteration for OME calibration: ' + str(count_of_calibration + 1) + ' ---')\n\t\n\telse:\n\t\t([item for item in calibration_settings if 'iteration_flag' in item])[-1][-1] = int(1)\n\t\tlog_file_list.append(\"\")\n\n\t# check if workflowExecutionError.dat exist in the UNICADOworkflow directory -> if true: -> terminate ome calibration loop and skip design sizing loop iteration\n\tif os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'):\n\t\tprint('Tool error occured during the ome calibration!')\n\t\tprint('Calibration-, design sizing- and mission study loop will be skipped!')\n\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + 'Tool error occured during the ome calibration!')\n\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + 'Calibration-, design sizing- and mission study loop will be skipped!')\n\t\t\n\t\tRCE.write_output(\"ome_calibration_flag\", old_ome_calibration_flag)\n\t\t\n\t#------------------------------------------------------------------------------------------------------------------------\n\t\n\t# Else condition: No tool errors occurred -> check convergence criteria for ome calibration iteration\n\telse:\n\t\tif iteration_flag == 1 and calibrate_ome_flag == 0 and count_of_calibration > 3:\n\t\t\tcalibration_target_OME = ([item for item in calibration_settings if 'calibration_target_OME' in item])[-1][-1]\n\t\t\tprint('---')\n\t\t\tprint('Convergence successful. OME calibrated for given MTOM:')\n\t\t\tprint('OME set point: ' + str(calibration_target_OME) + ' kg')\n\t\t\tprint('OME actual value: ' + str(ome_loop_vector[-1]) + ' kg')\n\t\t\tprint('---')\n\t\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ' ---')\n\t\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ' Convergence successful. OME calibrated for given MTOM:')\n\t\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ' OME set point: ' + str(calibration_target_OME) + ' kg')\n\t\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ' OME actual value: ' + str(ome_loop_vector[-1]) + ' kg')\n\t\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ' ---')\n\t\t\tlog_file_list.append('')\n\t\t\n\t\t\tRCE.write_output(\"ome_calibration_flag\", ome_calibration_flag)\n\t\t\t\n\t\telse:\n\t\t\tif ome_calibration_flag%2 == 0:\n\t\t\t\tome_calibration_flag += 1\n\t\t\telse:\n\t\t\t\tome_calibration_flag -= 1\n\t\t\tRCE.write_output(\"ome_calibration_flag\", round(ome_calibration_flag, 0))\n\nelse:\n\tRCE.write_output(\"ome_calibration_flag\", old_ome_calibration_flag)\n\t\nlog_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a')\nfor row in log_file_list:\n\tlog_file.write(row + '\\n')\nlog_file.close()\n\n#------------------------------------------------------------------------------------------------------------------------\n\nRCE.write_output(\"calibration_factors\", calibration_factors)\nRCE.write_output(\"calibration_settings\", calibration_settings)\nRCE.write_output(\"count_of_calibration\", count_of_calibration)\nRCE.write_output(\"current_workflow_name\", current_workflow_name)\nRCE.write_output(\"ome_loop_vector\", ome_loop_vector)\nRCE.write_output(\"outer_loop_trigger_flag\", 1)\nRCE.write_output(\"output_trigger_flag\", 1)\nRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\nRCE.write_output(\"paths_and_names\", paths_and_names)\nRCE.write_output(\"perform_calibration\", perform_calibration)\nRCE.write_output(\"skip_moe_calibration\", skip_moe_calibration)\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "b5d6199a-2f90-4f19-ad2e-96f02b95d4e1", + "name" : "calibration_factors", + "epIdentifier" : "default", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "a429c8cb-910c-49b1-90f3-aece25ef185e", + "name" : "calibration_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "85a878f7-2e29-4d87-8d3e-8b7e31828cce", + "name" : "count_of_calibration", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "f76ce939-43dc-4cc9-be5d-add4c560af44", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "4bf3391e-fab1-4c0d-8171-fe9ffc9195f3", + "name" : "input_trigger", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "e0ff6dc1-47dc-412a-b3e4-39c08df4b6f3", + "name" : "ome_calibration_flag", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "8d855cd0-f2db-4c5d-93be-f4f4fd517a61", + "name" : "ome_loop_vector", + "epIdentifier" : "default", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "c9ee86d2-25b6-4447-85d6-5fb57cf26531", + "name" : "outer_loop_trigger_flag", + "epIdentifier" : "default", + "datatype" : "Boolean", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "aaa32404-3a24-415d-9bad-7620d8fa4e52", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "e8698e2e-8f54-48c0-9ace-5e850943fa7a", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "37b3ad54-2d53-47e3-95fd-52dd95e6a5a6", + "name" : "perform_calibration", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "caf8ff74-06e1-411f-b777-9ad0623d7d65", + "name" : "skip_moe_calibration", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "4dac1c16-7baa-4d3c-b9df-23d2378e45d9", + "name" : "calibration_factors", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "a2753cec-901b-4248-9456-4ebc1334df12", + "name" : "calibration_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "f7c60626-1541-47b6-ae3a-3c449570f0d0", + "name" : "count_of_calibration", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "2213355d-582b-45bc-9e0d-9feb4f1bd0d6", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "fc80dd02-4a9f-4621-9cc0-a4eabbc11bab", + "name" : "ome_calibration_flag", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "aea980e1-e4f2-4c30-832a-d9346b354b35", + "name" : "ome_loop_vector", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "bb931d85-55ae-4ab3-ae27-7e30f56b7fd0", + "name" : "outer_loop_trigger_flag", + "epIdentifier" : "default", + "datatype" : "Boolean" + }, { + "identifier" : "a132114b-cbe0-47d2-9420-95a3329eb70c", + "name" : "output_trigger_flag", + "epIdentifier" : "default", + "datatype" : "Boolean" + }, { + "identifier" : "ed680b37-42e1-4908-91ae-7ece97aa467c", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "0b89e6ec-2820-42c8-8178-aa0540afde78", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "b48956bf-87fa-4f0f-b239-abb7eff2a7ba", + "name" : "perform_calibration", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "98db32a2-b885-46c7-a62e-e476a346e81d", + "name" : "skip_moe_calibration", + "epIdentifier" : "default", + "datatype" : "Integer" + } ] + }, { + "identifier" : "d1de52bd-1aa4-4f4d-9b77-8286e8fd26fd", + "name" : "performance_assessment", + "location" : "1021:800", + "zIndex" : "50", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.performance_assessment", + "version" : "allTime", + "name" : "performance_assessment" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "7f77f127-73d8-45db-9fc5-03a42b90540f", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "c69a2d04-3e76-401f-a0b5-622a2dcfa304", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "59b94c21-6c41-4ead-996d-b63a98137535", + "name" : "post_operation_of_design_sizing", + "location" : "560:300", + "zIndex" : "2", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "ScriptWhitespaceBox" : "true", + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read input values and generate list of design variables '''\r\naccuracy_list = RCE.read_input(\"accuracy_list\")\r\ncalibration_factors = RCE.read_input(\"calibration_factors\")\r\ncalibration_settings = RCE.read_input(\"calibration_settings\")\r\ncm_cruise = RCE.read_input(\"cm_cruise\")\r\ncontrol_settings = RCE.read_input(\"control_settings\")\r\ndesign_sizing_iteration_flag = RCE.read_input(\"design_sizing_iteration_flag\")\r\ni_stab = RCE.read_input(\"i_stab\")\r\nmission_energy_last = RCE.read_input(\"mission_energy_last\")\r\nm_operating_empty_last = RCE.read_input(\"m_operating_empty_last\")\r\nm_take_off_max_last = RCE.read_input(\"m_take_off_max_last\")\r\nmodule_list_of_sizing_loop = RCE.read_input(\"module_list_of_sizing_loop\")\r\nmtom_loop_vector = RCE.read_input(\"mtom_loop_vector\")\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npaths_and_names = RCE.read_input(\"paths_and_names\")\r\ntrim_parameter_list = RCE.read_input(\"trim_parameter_list\")\r\nx_center_of_gravity_last = RCE.read_input(\"x_center_of_gravity_last\")\r\n\r\ndesign_variables = [['m_take_off_max_last', m_take_off_max_last],\r\n\t\t\t\t\t['m_operating_empty_last', m_operating_empty_last],\r\n\t\t\t\t\t['mission_energy_last', mission_energy_last],\r\n\t\t\t\t\t['x_center_of_gravity_last', x_center_of_gravity_last],\r\n\t\t\t\t\t['cm_cruise', ([item for item in trim_parameter_list if 'cm_cruise_current' in item])[-1][-1]],\r\n\t\t\t\t\t['i_stab', ([item for item in trim_parameter_list if 'i_stab_last' in item])[-1][-1]]]\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read and set system path for python scripts'''\r\n\r\n# import for python\r\nimport os\r\nimport sys\r\nfrom datetime import datetime\r\n\r\nsys.path.insert(1, ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1])\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\ncurrent_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1]\r\ndesign_mode = int(([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1])\r\npath_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1]\r\n\r\n# check if selected design mode eqaual to 3 or if exist a tool execution error -> if true: -> skip post operating of design sizing and close converger unit than perform mission analysis loop\r\nif design_mode == 3 or os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'):\r\n\tcount_of_iteration = int(([item for item in parameter_for_design_case if 'count_of_iteration' in item])[-1][-1])\r\n\t\r\n\tRCE.write_output(\"count_of_iteration\", 0)\r\n\tRCE.write_output(\"mission_energy\", 0)\r\n\tRCE.write_output(\"m_operating_empty\", 0)\r\n\tRCE.write_output(\"m_take_off_max\", 0)\r\n\tRCE.write_output(\"x_center_of_gravity\", 0)\r\n\t\r\n\t# check if error in tool execution -> if true: -> print error message to workflow log-file and console\r\n\tif os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat') and count_of_iteration > 0:\r\n\t\tlog_file_list = []\r\n\t\tcharacter_length_of_date_and_time = 21\r\n\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Error in design tool execution!')\r\n\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': At least one of the enabled design tools has send an error. The actual design loop is failed and will be canceled!')\r\n\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': If parameter study or optimization is selected, current loop of iteration will skipped and the next iteration will be performed!')\r\n\t\t\r\n\t\t# write log-file to system\r\n\t\tlog_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a')\r\n\t\t# loop across all elements of log-file list to print to workflow console and write to workflow log-file\r\n\t\tfor row in log_file_list:\r\n\t\t# print current log-file list entry to workflow console\r\n\t\t\tprint(row[character_length_of_date_and_time:])\r\n\r\n\t\t# write current entry of log-file list to workflow log-file\r\n\t\t\tlog_file.write(row + '\\n')\r\n\t\tlog_file.close()\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\nelse:\r\n\t''' prepare design variables for RCE converger to perform next steps '''\r\n\t\r\n\t# import python script\r\n\tfrom design_sizing_loop.post_operation_of_design_sizing import post_operation_of_design_sizing\r\n\t\r\n\t# function call for post operation of design sizing -> prepares design variables for converge component of RCE and calculates the residuals of design variables.\r\n\t# inputs: paths_and_names, parameter_for_design_case, design_variables, control_settings, module_list_of_sizing_loop, calibration_settings, mtom_loop_vector, calibration_factors, accuracy_list, trim_parameter_list, i_stab, cm_cruise, design_sizing_iteration_flag\r\n\t# returns: parameter_for_design_case, design_variables, calibration_settings, control_settings, mtom_loop_vector, calibration_factors, trim_parameter_list, i_stab, cm_cruise, design_sizing_iteration_flag\r\n\t\r\n\tparameter_for_design_case, design_variables, calibration_settings, control_settings, mtom_loop_vector, calibration_factors, trim_parameter_list, i_stab, cm_cruise, design_sizing_iteration_flag = \\\r\n\t\tpost_operation_of_design_sizing(paths_and_names, parameter_for_design_case, design_variables, control_settings, module_list_of_sizing_loop, calibration_settings, mtom_loop_vector, calibration_factors, \r\n\t\t\t\t\t\t\t\t\t\taccuracy_list, trim_parameter_list, i_stab, cm_cruise, design_sizing_iteration_flag)\r\n\t\r\n\t#------------------------------------------------------------------------------------------------------------------------\r\n\t\r\n\tstatus_flag_to_skip_design_sizing = int(([item for item in control_settings if 'status_flag_to_skip_design_sizing' in item])[-1][-1])\r\n\t\r\n\t''' outputs for workflow after execution of post operating '''\r\n\tif status_flag_to_skip_design_sizing == 0:\r\n\t\tRCE.write_output(\"count_of_iteration\", ([item for item in parameter_for_design_case if 'count_of_iteration' in item])[-1][-1])\r\n\t\tRCE.write_output(\"mission_energy\", ([item for item in design_variables if 'mission_energy' in item])[-1][-1])\r\n\t\tRCE.write_output(\"m_operating_empty\", ([item for item in design_variables if 'm_operating_empty' in item])[-1][-1])\r\n\t\tRCE.write_output(\"m_take_off_max\", ([item for item in design_variables if 'm_take_off_max' in item])[-1][-1])\r\n\t\tRCE.write_output(\"x_center_of_gravity\", ([item for item in design_variables if 'x_center_of_gravity' in item])[-1][-1])\t\r\n\telse:\r\n\t\tRCE.write_output(\"count_of_iteration\", ([item for item in parameter_for_design_case if 'count_of_iteration' in item])[-1][-1])\r\n\t\tRCE.write_output(\"mission_energy\", ([item for item in design_variables if 'mission_energy_last' in item])[-1][-1])\r\n\t\tRCE.write_output(\"m_operating_empty\", ([item for item in design_variables if 'm_operating_empty_last' in item])[-1][-1])\r\n\t\tRCE.write_output(\"m_take_off_max\", ([item for item in design_variables if 'm_take_off_max_last' in item])[-1][-1])\r\n\t\tRCE.write_output(\"x_center_of_gravity\", ([item for item in design_variables if 'x_center_of_gravity_last' in item])[-1][-1])\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' outputs for workflow '''\r\nRCE.write_output(\"accuracy_list\", accuracy_list)\r\nRCE.write_output(\"calibration_factors\", calibration_factors)\r\nRCE.write_output(\"calibration_settings\", calibration_settings)\r\nRCE.write_output(\"cm_cruise\", cm_cruise)\r\nRCE.write_output(\"control_settings\", control_settings)\r\nRCE.write_output(\"current_workflow_name\", current_workflow_name)\r\nRCE.write_output(\"design_sizing_iteration_flag\", design_sizing_iteration_flag)\r\nRCE.write_output(\"i_stab\", i_stab)\r\nRCE.write_output(\"module_list_of_sizing_loop\", module_list_of_sizing_loop)\r\nRCE.write_output(\"mtom_loop_vector\", mtom_loop_vector)\r\nRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\r\nRCE.write_output(\"paths_and_names\", paths_and_names)\r\nRCE.write_output(\"trim_parameter_list\", trim_parameter_list)\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW", + "xor" : "false" + }, + "dynamicInputs" : [ { + "identifier" : "1d3fb5f4-19bf-42ed-91ef-87851ed86467", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "69478b7f-df59-4d1c-ad89-47bdfd07c681", + "name" : "calibration_factors", + "epIdentifier" : "default", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "b2265167-a960-4361-a17a-a4cbe5bce403", + "name" : "calibration_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "26ded494-c001-4295-b255-d06869200f22", + "name" : "cm_cruise", + "epIdentifier" : "default", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "9bc417c7-8314-4141-b376-326966369e85", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "1304a325-8475-434f-8877-2789a2b4082d", + "name" : "design_sizing_iteration_flag", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "ab9a7852-5a75-4842-8a31-199bd751801e", + "name" : "i_stab", + "epIdentifier" : "default", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "300150d0-1d28-464e-b6e2-5a94e2b4a11c", + "name" : "input_flag_post_operation_of_design_sizing", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "RequiredIfConnected", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "68ec6baf-f1d9-48c8-be6d-8b55b03cc16d", + "name" : "m_operating_empty_last", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "bf5ec31b-00f5-45bf-9c44-836fe9296a2a", + "name" : "m_take_off_max_last", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "4669cecd-7947-4216-bcde-f92b980325a3", + "name" : "mission_energy_last", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "50e60488-5d3b-4307-a76a-d8ef5ca06abe", + "name" : "module_list_of_sizing_loop", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "6b87d29f-ccfb-4f33-b529-f1f8ce28fec4", + "name" : "mtom_loop_vector", + "epIdentifier" : "default", + "datatype" : "Vector", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "512cdf15-02fe-486b-bdc0-e2d46eea68a6", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "ba507e5a-9208-410b-be58-aea3a972799b", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "05dac670-b81b-4d54-96b8-5b941a680c94", + "name" : "trim_parameter_list", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "fcd82abc-4b65-4168-ae57-91289b416523", + "name" : "x_center_of_gravity_last", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "032691f2-c91a-4802-8570-3ceb51c67551", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "be463602-1e0c-47c3-a801-db062fbbc3bf", + "name" : "calibration_factors", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "d02022f7-3cda-4994-9644-80ae59aa8fc2", + "name" : "calibration_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "d1b18faf-61f9-4b88-9cba-d67cee47b152", + "name" : "cm_cruise", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "b7c93131-7ffb-4742-a2b2-843c220d03c0", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "2eced146-dcb9-4dda-a6a3-9d2e7b847032", + "name" : "count_of_iteration", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "291232b0-92a9-4cc2-ba83-ce98ef6b16e6", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "59e4483e-fce8-41b1-adfd-8918666178a0", + "name" : "design_sizing_iteration_flag", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "9ef1cf52-20c0-44cf-ab98-59324d791e69", + "name" : "i_stab", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "43319d92-d5b7-4b44-a14f-260bdbcd6fc5", + "name" : "m_operating_empty", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "a9512f69-22e1-4feb-98ff-80f6d8c8929a", + "name" : "m_take_off_max", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "f5f87451-abbb-42ff-a827-9b453748c11f", + "name" : "mission_energy", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "80de462a-f1a7-4053-8072-199127cda91d", + "name" : "module_list_of_sizing_loop", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "3c027a9c-97c4-4cd1-9ea3-e89bcd66d54e", + "name" : "mtom_loop_vector", + "epIdentifier" : "default", + "datatype" : "Vector" + }, { + "identifier" : "4d328456-8b5f-4aa8-a60b-4a9b0dbe3387", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "3f4ea7d6-91ed-43d2-b48f-8236ddf5b447", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "29ed4976-3c0e-49f0-9df9-94b96afd2742", + "name" : "trim_parameter_list", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "fb016221-45f6-4057-8ba2-30b78bb4d51b", + "name" : "x_center_of_gravity", + "epIdentifier" : "default", + "datatype" : "Float" + } ] + }, { + "identifier" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "name" : "post_operation_of_mission_study_analysis", + "location" : "560:621", + "zIndex" : "5", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "ScriptWhitespaceBox" : "true", + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read input values '''\r\n\r\naccuracy_list = RCE.read_input(\"accuracy_list\")\r\ncontrol_settings = RCE.read_input(\"control_settings\")\r\ncount_of_mission_study_loop = RCE.read_input(\"count_of_mission_study_loop\")\r\nconvergence_criteria = RCE.read_input(\"convergence_criteria\")\r\nfl_initial_cruise_study_last = RCE.read_input(\"fl_initial_cruise_study_last\")\r\ninput_flag_post_operation_mission_study_analysis = RCE.read_input(\"input_flag_post_operation_mission_study_analysis\")\r\nmission_energy_study_last = RCE.read_input(\"mission_energy_study_last\")\r\nm_take_off_max_study_last = RCE.read_input(\"m_take_off_max_study_last\")\r\nmission_study_iteration_flag = RCE.read_input(\"mission_study_iteration_flag\")\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npaths_and_names = RCE.read_input(\"paths_and_names\")\r\nrange_study_last = RCE.read_input(\"range_study_last\")\r\n\r\nold_mission_study_iteration_flag = mission_study_iteration_flag\r\n\r\nmission_study_variables = [['m_take_off_max_study_last', m_take_off_max_study_last],\r\n\t\t\t\t\t\t\t['mission_energy_study_last', mission_energy_study_last],\r\n\t\t\t\t\t\t\t['range_study_last', range_study_last],\r\n\t\t\t\t\t\t\t['fl_initial_cruise_study_last', fl_initial_cruise_study_last]]\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read and set system path for python scripts '''\r\n\r\n# import for python\r\nimport os\r\nimport sys\r\nfrom datetime import datetime\r\n\r\nsys.path.insert(1, ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1])\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' prepare mission study variables for RCE converger to perform next steps '''\r\n\r\ncurrent_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1]\r\ndesign_mode = int(([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1])\r\npath_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1]\r\n\r\n# check if mission study analysis should not be performed (design_mode == 4) or if exist a tool execution error -> if true: -> skip mission analysis loop and perform post operations of workflow\r\nif not design_mode == 4 and not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat') and not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/pre_sizing_error.dat') and not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/design_sizing_error.dat'):\r\n\t# import python script\r\n\tfrom mission_study_loop.post_operation_of_mission_study_analysis import post_operation_of_mission_study_analysis\r\n\t\r\n\t# function call for post operation of mission study analysis -> prepares design variables for converge component of RCE and calculates the residuals of design variables.\r\n\t# inputs: paths_and_names, mission_study_variables, control_settings, count_of_mission_study_loop, convergence_criteria, mission_study_iteration_flag\r\n\t# returns: mission_study_variables, control_settings, count_of_mission_study_loop, mission_study_iteration_flag\r\n\t\r\n\tmission_study_variables, control_settings, count_of_mission_study_loop, mission_study_iteration_flag = \\\r\n\t\tpost_operation_of_mission_study_analysis(paths_and_names, mission_study_variables, control_settings, \r\n\t\t\t\t\t\t\t\t\t\t\t\t\tcount_of_mission_study_loop, convergence_criteria, mission_study_iteration_flag)\r\n\t\r\n\t#------------------------------------------------------------------------------------------------------------------------\r\n\t\r\n\t# check if workflowExecutionError.dat exist in the UNICADOworkflow directory -> if true: -> terminate mission study loop and prepare final workflow steps\r\n\tif os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'):\r\n\t\tmission_study_iteration_flag = old_mission_study_iteration_flag\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\nelse:\r\n\tmission_study_variables = [['m_take_off_max_study', 0.0],\r\n\t\t\t\t\t\t\t\t['mission_energy_study', 0.0],\r\n\t\t\t\t\t\t\t\t['range_study', 0.0],\r\n\t\t\t\t\t\t\t\t['fl_initial_cruise_study', 0.0]]\r\n\r\n\tmission_study_iteration_flag = old_mission_study_iteration_flag\r\n\t\r\n\t# check if error in tool execution -> if true: -> print error message to workflow log-file and console\r\n\tif os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat') and count_of_mission_study_loop > 0:\r\n\t\tlog_file_list = []\r\n\t\tcharacter_length_of_date_and_time = 21\r\n\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Error in mission study tool execution!')\r\n\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': At least one of the enabled mission study tools has send an error. The actual mission study loop is failed and will be canceled!')\r\n\t\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': If parameter study or optimization is selected, current loop of iteration will skipped and the next iteration will be performed!')\r\n\t\t\r\n\t\t# write log-file to system\r\n\t\tlog_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a')\r\n\t\t# loop across all elements of log-file list to print to workflow console and write to workflow log-file\r\n\t\tfor row in log_file_list:\r\n\t\t# print current log-file list entry to workflow console\r\n\t\t\tprint(row[character_length_of_date_and_time:])\r\n\r\n\t\t# write current entry of log-file list to workflow log-file\r\n\t\t\tlog_file.write(row + '\\n')\r\n\t\tlog_file.close()\r\n\r\n'------------------------------------------------------------------------------------------------------------------------'\r\n\r\n''' outputs for workflow '''\r\nstatus_flag_to_skip_study_mission = int(([item for item in control_settings if 'status_flag_to_skip_study_mission' in item])[-1][-1])\r\n\r\nif status_flag_to_skip_study_mission == 0:\r\n\tRCE.write_output(\"fl_initial_cruise_study\", ([item for item in mission_study_variables if 'fl_initial_cruise_study' in item])[-1][-1])\r\n\tRCE.write_output(\"mission_energy_study\", ([item for item in mission_study_variables if 'mission_energy_study' in item])[-1][-1])\r\n\tRCE.write_output(\"m_take_off_max_study\", ([item for item in mission_study_variables if 'm_take_off_max_study' in item])[-1][-1])\r\n\tRCE.write_output(\"range_study\", ([item for item in mission_study_variables if 'range_study' in item])[-1][-1])\r\nelse:\r\n\tRCE.write_output(\"fl_initial_cruise_study\", ([item for item in mission_study_variables if 'fl_initial_cruise_study_last' in item])[-1][-1])\r\n\tRCE.write_output(\"mission_energy_study\", ([item for item in mission_study_variables if 'mission_energy_study_last' in item])[-1][-1])\r\n\tRCE.write_output(\"m_take_off_max_study\", ([item for item in mission_study_variables if 'm_take_off_max_study_last' in item])[-1][-1])\r\n\tRCE.write_output(\"range_study\", ([item for item in mission_study_variables if 'range_study_last' in item])[-1][-1])\r\n\r\n# set results of post operation of mission study analysis to RCE outputs\r\nRCE.write_output(\"accuracy_list\", accuracy_list)\r\nRCE.write_output(\"control_settings\", control_settings)\r\nRCE.write_output(\"count_of_mission_study_loop\", count_of_mission_study_loop + 1)\r\nRCE.write_output(\"convergence_criteria\", convergence_criteria)\r\nRCE.write_output(\"mission_study_iteration_flag\", mission_study_iteration_flag)\r\nRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\r\nRCE.write_output(\"paths_and_names\", paths_and_names)\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW", + "xor" : "false" + }, + "dynamicInputs" : [ { + "identifier" : "ea1214c5-2e39-4ff9-94f0-ebcdb5a8de0c", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "a570e7b2-4c72-4081-92e3-e8681786e987", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "342f85af-a6e3-485e-ac6d-ca70e6f3761e", + "name" : "convergence_criteria", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "900b5112-1386-4e12-a92c-7542e11991d5", + "name" : "count_of_mission_study_loop", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "b6e1e778-854b-4c33-a354-bb5bd556ca63", + "name" : "fl_initial_cruise_study_last", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "28880f28-ee94-41ba-b6cc-e57c0f577f56", + "name" : "input_flag_post_operation_mission_study_analysis", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "e32b5f2d-e71c-4432-814a-1c7557ffb5f6", + "name" : "m_take_off_max_study_last", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "3f02bf11-ca3c-4563-8129-f88f4d4181a3", + "name" : "mission_energy_study_last", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "a8e0bfb3-4ccb-4f97-9411-7a428103b523", + "name" : "mission_study_iteration_flag", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "44997c38-7c44-48a9-99ce-531ee4fd4c58", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "d03f24e2-f1ba-4868-8de6-53d3e3c9500f", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "20ce6a41-f626-477b-99d8-bc0d66e31c31", + "name" : "range_study_last", + "epIdentifier" : "default", + "datatype" : "Float", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "024cb0f0-46d9-4d47-8eff-2149047b037f", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "e56f7fa6-cdad-495d-96d8-723ef13c4a3b", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "992ffa3d-301d-4682-8d2e-5810d40cf5ad", + "name" : "convergence_criteria", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "c27146e1-a29a-47bf-ba33-6fee7cf4c811", + "name" : "count_of_mission_study_loop", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "0ce8f9b1-11bd-4a70-b871-21a97a97c193", + "name" : "fl_initial_cruise_study", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "14578be4-e463-4da4-9aa9-62e3fc8ebf7d", + "name" : "m_take_off_max_study", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "9750ec36-c262-4691-ad51-e8b1b51f6cf7", + "name" : "mission_energy_study", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "7baa6e61-4b83-456d-b26e-448aff2449b1", + "name" : "mission_study_iteration_flag", + "epIdentifier" : "default", + "datatype" : "Float" + }, { + "identifier" : "d2ade8b0-87fa-4fa5-aa1c-6410403010a8", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "a1f5c584-4374-4b5d-9aa3-4b6edc504b86", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "acf23b58-2215-4552-b315-e518a5cfc560", + "name" : "range_study", + "epIdentifier" : "default", + "datatype" : "Float" + } ] + }, { + "identifier" : "8b87e3bc-05e4-4933-998a-60d71cf0c423", + "name" : "post_operation_skip_joiner", + "location" : "1320:820", + "zIndex" : "62", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.joiner", + "version" : "3.3", + "name" : "Joiner" + }, + "configuration" : { + "datatype" : "ShortText", + "inputCount" : "2", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "65b9cde4-4265-4a1c-9700-6ad821a4caca", + "name" : "Input 001", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + }, { + "identifier" : "ac31c847-1fe5-43a9-9f86-6db8210637cc", + "name" : "Input 002", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "abc69e40-ce73-4d38-93ff-61c5dfc86526", + "name" : "Joined", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "c422c632-93db-479b-9185-d494be3b836b", + "name" : "post_operations_of_workflow", + "location" : "161:621", + "zIndex" : "7", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "ScriptWhitespaceBox" : "true", + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read input values '''\r\n\r\ncontrol_settings = RCE.read_input(\"control_settings\")\r\nidentifier = RCE.read_input(\"identifier_for_clean_up\")\r\nparameter_for_design_case = RCE.read_input(\"parameter_for_design_case\")\r\npaths_and_names = RCE.read_input(\"paths_and_names\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read and set system path for python scripts '''\r\n\r\n# import for python\r\nimport sys\r\n\r\nsys.path.insert(1, ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1])\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' post operation of workflow and clean up '''\r\n\r\n# import python script\r\nfrom clean_up.post_operations_of_workflow import post_operations_of_workflow\r\n\r\n# function call for post operations of workflow -> reates all output files and copies them to the result directory and deletes all temporary files\r\n# inputs: paths_and_names, control_settings, parameter_for_design_case\r\n# returns: none\r\n\r\npost_operations_of_workflow(paths_and_names, control_settings, parameter_for_design_case, identifier)\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' write output for optimization converger unit '''\r\n\r\nRCE.write_output(\"workflow_status\", 1)\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "4e20ba6e-6e15-4370-8a22-23b459baf43a", + "name" : "CPACS_final_input_flag", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "RequiredIfConnected", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "f8f6aa27-41b4-42fa-b3c3-71f14adac325", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "4f5f5492-612c-4ce5-8b9d-92ba8e9dcc31", + "name" : "identifier_for_clean_up", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "d4d98ea4-d68c-484a-adee-be71a49282d7", + "name" : "input_flag_post_operations_of_workflow", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "RequiredIfConnected", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "eca720fe-7281-45ca-8808-f0d39b47a79c", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + }, { + "identifier" : "9f764eab-16df-41cd-9202-319865728acc", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Single" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "1cd77081-e882-417e-92d2-cef4b2784f2f", + "name" : "workflow_status", + "epIdentifier" : "default", + "datatype" : "Integer" + } ] + }, { + "identifier" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "name" : "pre_condition", + "location" : "320:112", + "zIndex" : "9", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.script", + "version" : "3.5", + "name" : "Script" + }, + "configuration" : { + "pythonExecutionPath" : "${pythonExecutionPath}", + "script" : "#------------------------------------------------------------------------------------------------------------------------\r\n\r\n''' read input values '''\r\ncurrent_workflow_name = RCE.read_input(\"current_workflow_name\")\r\ninstall_path_directory = RCE.read_input(\"install_path_directory\")\r\nglobal_loop_counter = RCE.read_input(\"global_loop_counter\")\r\nnew_value_of_input = RCE.read_input(\"new_value_of_input\")\r\noptimization_status_flag = RCE.read_input(\"optimization_status_flag\")\r\nouter_loop_counter = RCE.read_input(\"outer_loop_counter\")\r\nparameter_name = RCE.read_input(\"parameter_name\")\r\nparameter_study_status_flag = RCE.read_input(\"parameter_study_status_flag\")\r\npath_to_python_scripts = RCE.read_input(\"path_to_python_scripts\")\r\nperform_workflow_execution = RCE.read_input(\"perform_workflow_execution\")\r\nstudy_counter = RCE.read_input(\"study_counter\")\r\n\r\n#------------------------------------------------------------------------------------------------------------------------\r\n\r\n# import for python\r\nimport os\r\nimport sys\r\nimport time\r\nfrom datetime import datetime\r\n\r\npaths_and_names = [['path_to_python_scripts', path_to_python_scripts]]\r\nsys.path.insert(1, ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1])\r\npath_to_python_scripts = ([item for item in paths_and_names if 'path_to_python_scripts' in item])[-1][-1]\r\npath_to_python_sub_function = install_path_directory + 'workingDirectoryRCE/UNICADOworkflow/src/sub_function'\r\nsys.path.insert(1, path_to_python_sub_function)\r\n\r\nouter_loop_counter_old = outer_loop_counter\r\n\r\n# check if the optizition mode is selected -> if true: -> whait for semaphore flag to continue workflow execution\r\nif optimization_status_flag == 1 and perform_workflow_execution == 1:\r\n\tif global_loop_counter > 2:\r\n\t\t# check if the semaphore wait flag for the optimization framework is existing -> if true: -> remove flag to execute optimization framework\r\n\t\tif os.path.isfile(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/temp/semaphoreFlagOptimization.dat'):\r\n\t\t\tos.remove(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/temp/semaphoreFlagOptimization.dat')\r\n\r\n\tif not os.path.isfile(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/temp/optimizationRuntimeError.dat'):\r\n\t\t# while loop to wait for deleted semaphore flag of optimization framework -> if true: -> break the loop and run the workflow execution\r\n\t\twhile True:\r\n\t\t\tif not os.path.isfile(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/temp/semaphoreFlagWorkflowExecution.dat'):\r\n\t\t\t\twith open(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/temp/semaphoreFlagWorkflowExecution.dat', 'w') as file:\r\n\t\t\t\t\tfile.close()\r\n\t\t\t\tbreak\r\n\t\t\telse:\r\n\t\t\t\ttime.sleep(5)\r\n\telse:\r\n\t\t# write error data to system\r\n\t\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\t\terror_dat.close()\r\n\t\t\r\n\t\t# write tool name to tool error list of current workflow loop\r\n\t\ttool_error_list = open(path_of_temp_working_directory + '/temp/toolErrorList.log', 'a+')\r\n\t\ttool_error_list.write('Error occurred in design tool: optimization framework' + '\\n')\r\n\t\ttool_error_list.close()\r\n\t\r\n\t# check if the optimnzation framework is finsihed -> if true: -> termiante workflow execution\r\n\tif os.path.isfile(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/temp/optimizationFinishFlag.dat'):\r\n\t\tperform_workflow_execution = 0\r\n\t\touter_loop_counter = outer_loop_counter - 1\r\n\r\n# check if parameter study is finished -> if true: -> terminate workflow\r\nif perform_workflow_execution == 0:\r\n\t# write final outputs to close outer loop converger unit\r\n\tRCE.write_output(\"global_loop_counter\", global_loop_counter)\r\n\tRCE.write_output(\"optimization_status_flag\", optimization_status_flag)\r\n\tRCE.write_output(\"outer_loop_counter\", outer_loop_counter)\r\n\tRCE.write_output(\"parameter_study_status_flag\", parameter_study_status_flag)\r\n\tRCE.write_output(\"workflow_status\", 1)\r\n\r\n# else condition: parameter study or single execution not finished -> prepare workflow execution for the next run\r\nelse:\r\n\r\n\tlog_file_list = [\r\n\t'********************************************* START OF UNICADO WORKFLOW ********************************************',\r\n\t'',\r\n\t'************************************************** generate paths **************************************************']\r\n\t\r\n\tlog_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Python scripts: ' + path_to_python_scripts)\r\n\tprint('current_workflow_name is: ' + current_workflow_name)\r\n\t\r\n\t# write log-file to system\r\n\tif os.path.isfile(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/unicado_workflow.log'):\r\n\t\tos.remove(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/unicado_workflow.log')\r\n\t\r\n\tlog_file = open(install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/unicado_workflow.log', 'a')\r\n\tfor row in log_file_list:\r\n\t\tlog_file.write(row + '\\n')\r\n\tlog_file.close()\r\n\t\r\n\t#------------------------------------------------------------------------------------------------------------------------\r\n\t\r\n\t''' generate paths '''\r\n\t\r\n\t# import python script\r\n\tfrom pre_condition.generate_paths import generate_paths\r\n\t\r\n\t# function call for generate_paths -> read and set paths for workflow\r\n\t# inputs: paths_and_names\r\n\t# returns: paths_and_names\r\n\t\r\n\tpaths_and_names = generate_paths(paths_and_names, current_workflow_name)\r\n\t\r\n\t#------------------------------------------------------------------------------------------------------------------------\r\n\t\r\n\t''' read and set workflow configuration parameter from workflow configuration file '''\r\n\t\r\n\t# import python script\r\n\tfrom pre_condition.set_configuration_parameter import set_configuration_parameter\r\n\t\r\n\t# function call for set configuration parameter -> reads workflow input parameter and makes them visible to all workflow components\r\n\t# inputs: paths_and_names, global_loop_counter\r\n\t# returns: accuracy_list, control_settings, parameter_for_design_case, paths_and_names, calibration_settings, module_list_of_sizing_loop\r\n\t\r\n\taccuracy_list, control_settings, parameter_for_design_case, paths_and_names, calibration_settings, module_list_of_sizing_loop = set_configuration_parameter(paths_and_names, global_loop_counter)\r\n\t\r\n\t#------------------------------------------------------------------------------------------------------------------------\r\n\t\r\n\t''' check design logic to prevent internal workflow errors '''\r\n\t\r\n\t# import python script\r\n\tfrom pre_condition.check_design_logic import check_design_logic\r\n\t\r\n\t# function call for check design logic -> checks switches in aircraft exchange- and config files for selected design mode -> if check fails -> set switches to correct position\r\n\t# inputs: paths_and_names, parameter_for_design_case, global_loop_counter\r\n\t# returns: parameter_for_design_case\r\n\tparameter_for_design_case, outer_loop_counter, perform_workflow_execution = check_design_logic(paths_and_names, parameter_for_design_case, control_settings, global_loop_counter, outer_loop_counter)\r\n\t\r\n\t#------------------------------------------------------------------------------------------------------------------------\r\n\t\r\n\t''' reset of important values for selected design mode '''\r\n\t\r\n\t# import python script\r\n\tfrom pre_condition.reset_of_important_values import reset_of_important_values\r\n\tprogram_mode = ([item for item in parameter_for_design_case if 'program_mode' in item])[-1][-1]\r\n\t\r\n\t# function call for reset of important values -> set switches in aircraft exchange to default values to perform design sizing loop -> if selected design mode not \"clean sheet design\", switches will not changed\r\n\t# inputs: paths_and_names, control_settings\r\n\t# returns: none\r\n\treset_of_important_values(paths_and_names, control_settings, program_mode)\r\n\t\r\n\t#------------------------------------------------------------------------------------------------------------------------\r\n\t\r\n\t''' check if optimization is selected in configuration file -> if false: -> close outer optimization loop '''\r\n\tdesign_mode = int(([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1])\r\n\tparameter_study_mode = int(([item for item in parameter_for_design_case if 'program_mode' in item])[-1][-1] == \"parameter_study\")\r\n\toptimization_mode = int(([item for item in parameter_for_design_case if 'program_mode' in item])[-1][-1] == \"optimization\")\r\n\tperform_calibration = int(([item for item in calibration_settings if 'free_variable_OME_calibration' in item])[-1][-1] > 0 or ([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1] > 0) \r\n\tskip_moe_calibration = int(([item for item in calibration_settings if 'free_variable_OME_calibration' in item])[-1][-1] == False)\r\n\t\r\n\tif design_mode == -1:\r\n\t\tRCE.write_output(\"workflow_status\", 1)\r\n\r\n\tif perform_workflow_execution == 1 and (optimization_mode == 1 or parameter_study_mode == 1):\r\n\t\t# if the first parameter study iteration run will performed set maximum number of parameter study iterations and status flag to true\r\n\t\tif global_loop_counter == 1 and parameter_study_mode == 1:\r\n\t\t\tparameter_study_status_flag = 1\r\n\t\t\t\r\n\t\t# if the first optimization iteration run will performed set the status flag to true\r\n\t\tif global_loop_counter == 1 and optimization_mode == 1:\r\n\t\t\toptimization_status_flag = 1\r\n\t\t\r\n\t\t# if termination not reached -> add + 1 to optimization counter \r\n\t\tglobal_loop_counter += 1\r\n\t\t\r\n\telif perform_workflow_execution == 0:\r\n\t\tcurrent_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1]\r\n\t\tpath_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1]\r\n\t\tpath_to_current_working_directory = path_of_working_directory_rce + '/' + current_workflow_name\r\n\t\t# write error data to system\r\n\t\terror_dat = open(path_to_current_working_directory + '/temp/workflowExecutionError.dat', 'a+')\r\n\t\terror_dat.close()\r\n\r\n\t\t# write tool name to tool error list of current workflow loop\r\n\t\ttool_error_list = open(path_to_current_working_directory + '/temp/toolErrorList.log', 'a+')\r\n\t\ttool_error_list.write('Error occurred in pre-condition script!' + '\\n')\r\n\t\ttool_error_list.close()\r\n\t\t\r\n\tparameter_for_design_case.append(['parameter_name', str(parameter_name)])\r\n\tparameter_for_design_case.append(['global_loop_counter', int(global_loop_counter-1)])\r\n\tparameter_for_design_case.append(['study_counter', int(study_counter)])\r\n\tparameter_for_design_case.append(['new_value_of_input', str(new_value_of_input)])\r\n\t\r\n\t#------------------------------------------------------------------------------------------------------------------------\r\n\t\r\n\t''' outputs for workflow '''\r\n\tRCE.write_output(\"current_workflow_name\", current_workflow_name)\r\n\tRCE.write_output(\"accuracy_list\", accuracy_list)\r\n\tRCE.write_output(\"calibration_settings\", calibration_settings)\r\n\tRCE.write_output(\"control_settings\", control_settings)\r\n\t\r\n\tif perform_workflow_execution == 1:\r\n\t\tRCE.write_output(\"design_mode\", design_mode)\r\n\telse:\r\n\t\tdesign_mode = int(3)\t\r\n\t\t([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1] = design_mode\r\n\t\touter_loop_counter = outer_loop_counter_old\r\n\t\tglobal_loop_counter = outer_loop_counter\r\n\t\tRCE.write_output(\"design_mode\", design_mode)\r\n\t\t\r\n\tRCE.write_output(\"module_list_of_sizing_loop\", module_list_of_sizing_loop)\r\n\tRCE.write_output(\"global_loop_counter\", global_loop_counter)\r\n\tRCE.write_output(\"optimization_status_flag\", optimization_status_flag)\r\n\tRCE.write_output(\"outer_loop_counter\", outer_loop_counter)\r\n\tRCE.write_output(\"output_flag_pre_condition\", 1)\r\n\tRCE.write_output(\"parameter_for_design_case\", parameter_for_design_case)\r\n\tRCE.write_output(\"parameter_study_status_flag\", parameter_study_status_flag)\r\n\tRCE.write_output(\"paths_and_names\", paths_and_names)\r\n\tRCE.write_output(\"perform_calibration\", perform_calibration)\r\n\tRCE.write_output(\"skip_moe_calibration\", skip_moe_calibration)\r\n\t\t\r\n\tif design_mode == 0 or design_mode == 1 or design_mode == 4:\r\n\t\tRCE.write_output(\"paths_for_tigl\", paths_and_names)\r\n\t\t\r\n\t\tif design_mode == 0 or design_mode == 1 or design_mode == 4:\r\n\t\t\tRCE.write_output(\"initial_sizing_trigger\", current_workflow_name)\r\n\t\r\n\telif design_mode == 2 or design_mode == 3:\r\n\t\tRCE.write_output(\"paths_for_tigl\", paths_and_names)\r\n\t\tRCE.write_output(\"pre_sizing_skip_flag\", current_workflow_name)\r\n", + "scriptLanguage" : "Python", + "storeComponentHistoryData" : "true", + "usageOfScript" : "NEW" + }, + "dynamicInputs" : [ { + "identifier" : "7b7c3051-b4d7-4145-87b8-a9eb3a9cdefc", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "2b2a355c-050a-4c16-9ee3-20cf26ecd03d", + "name" : "global_loop_counter", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "f3e9289e-d3b1-4fa7-9035-3da5dc3937e5", + "name" : "install_path_directory", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "58d1914c-1a0a-449e-a8bf-aa5f163e914a", + "name" : "new_value_of_input", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "7aed0ec9-9328-45a1-8431-5626b46e9af2", + "name" : "optimization_status_flag", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "7c61708f-dd5d-4836-b955-3d2dc325ab3a", + "name" : "outer_loop_counter", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "f22305a9-c47d-400a-a1e4-97765030e65a", + "name" : "parameter_name", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "5b995f5c-cf80-4072-bbee-efabd04e240a", + "name" : "parameter_study_status_flag", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "cf06059d-449c-4279-9079-2d5f12f80075", + "name" : "path_to_python_scripts", + "epIdentifier" : "default", + "datatype" : "ShortText", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "cabf72e0-601c-46f7-a388-65e64f95469e", + "name" : "perform_workflow_execution", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + }, { + "identifier" : "e5ca537f-783f-46d3-966f-caaef2ef2c6c", + "name" : "study_counter", + "epIdentifier" : "default", + "datatype" : "Integer", + "metadata" : { + "inputExecutionConstraint_4aae3eea" : "Required", + "inputHandling_73b1056e" : "Queue" + } + } ], + "dynamicOutputs" : [ { + "identifier" : "1b852eb3-6555-4c38-8226-955231802adc", + "name" : "accuracy_list", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "91ee93a9-618f-4f27-948e-b6627cfb7238", + "name" : "calibration_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "03040c5a-50ec-442e-8e1a-982bdd438f35", + "name" : "control_settings", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "adb29e96-d044-4a42-8210-5e02f3476f78", + "name" : "current_workflow_name", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "e30226ea-597e-4a18-9e82-6006cc5bf4d2", + "name" : "design_mode", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "be6cddd4-4425-4139-a984-914856714e4f", + "name" : "global_loop_counter", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "00e10e8c-31e3-4b9b-a888-02763f08d9d4", + "name" : "initial_sizing_trigger", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "23c00739-352b-4a53-8425-5d5eca96de22", + "name" : "module_list_of_sizing_loop", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "f039192c-5eea-4cfa-a82b-65758566fdfd", + "name" : "optimization_status_flag", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "ef1c8021-ea53-4f27-9035-7be65f93cdb1", + "name" : "outer_loop_counter", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "c1319f18-7fc4-4586-bd45-1de9e31adfc9", + "name" : "output_flag_pre_condition", + "epIdentifier" : "default", + "datatype" : "Boolean" + }, { + "identifier" : "81aac912-1551-4192-8082-2133b09cafae", + "name" : "parameter_for_design_case", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "326dfd2b-264d-4a47-9619-54d6e4300ed3", + "name" : "parameter_study_status_flag", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "32198062-4c91-44a0-9bf8-b3f41c658c7c", + "name" : "paths_and_names", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "dca67595-e8be-4421-994b-12683e426ddd", + "name" : "paths_for_tigl", + "epIdentifier" : "default", + "datatype" : "SmallTable" + }, { + "identifier" : "19e73c98-bda5-443f-8d84-b01b5fa153b0", + "name" : "perform_calibration", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "2cd5373c-8f3d-46be-9a51-b1ef9c41e62c", + "name" : "pre_sizing_skip_flag", + "epIdentifier" : "default", + "datatype" : "ShortText" + }, { + "identifier" : "27160aa5-22d5-40eb-881c-f778ca89189e", + "name" : "skip_moe_calibration", + "epIdentifier" : "default", + "datatype" : "Integer" + }, { + "identifier" : "1fc5c384-9224-4806-af93-40ea2f444f9b", + "name" : "workflow_status", + "epIdentifier" : "default", + "datatype" : "Integer" + } ] + }, { + "identifier" : "783b395e-13db-40b9-b3df-47bc933a3aa1", + "name" : "propulsion_design", + "location" : "745:321", + "zIndex" : "36", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.propulsion_design", + "version" : "allTime", + "name" : "propulsion_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "eaffcf73-2392-47a7-a240-890c55c91473", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "ed81a8d8-42af-4d1c-ba4a-d59a7563b0f3", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "cd51d621-4989-4ce5-afd9-038c035b64ba", + "name" : "propulsion_design_calibration", + "location" : "1423:21", + "zIndex" : "37", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.propulsion_design", + "version" : "allTime", + "name" : "propulsion_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "2c15323e-b730-4650-8e77-0718c6ad193d", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "b938f4e6-d3d0-49a2-a808-3935e5cf0e70", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "96f79610-adc4-49a4-8727-9133b99b54bf", + "name" : "report_generator", + "location" : "1481:800", + "zIndex" : "48", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.report_generator", + "version" : "allTime", + "name" : "report_generator" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "d80ece7f-c96e-498f-b29b-8d75ade28a14", + "name" : "current_workflow_name", + "datatype" : "ShortText" + }, { + "identifier" : "c330c0fa-d9ed-40b4-89ff-4eb4564bb6cb", + "name" : "optional_trigger_signal", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "23738ccf-101e-4ca4-b6f3-5ae8f800d00f", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "bfa607cd-accb-4d20-bfcc-f3de47a91d59", + "name" : "skip_constraint_analysis_joiner", + "location" : "1651:459", + "zIndex" : "60", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.joiner", + "version" : "3.3", + "name" : "Joiner" + }, + "configuration" : { + "datatype" : "ShortText", + "inputCount" : "2", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "8e7a3a22-6235-4baf-a466-decbdd71e660", + "name" : "Input 001", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + }, { + "identifier" : "5d38fdd9-4c8d-4100-a456-384f361135a1", + "name" : "Input 002", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "a4f0041a-9672-44c2-b5e1-7f3f5d5ac013", + "name" : "Joined", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "fdff1cbf-fa40-43af-a036-98a49caddde9", + "name" : "skip_design_sizing_joiner", + "location" : "659:228", + "zIndex" : "20", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.joiner", + "version" : "3.3", + "name" : "Joiner" + }, + "configuration" : { + "datatype" : "ShortText", + "inputCount" : "2", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "8888652c-cdef-46b5-b2c0-0e1cf06ec950", + "name" : "Input 001", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + }, { + "identifier" : "25466c68-9528-4068-af97-428f838b6652", + "name" : "Input 002", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "c2c2a8a0-81d5-431d-aea7-3c4105c2a03d", + "name" : "Joined", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "356159aa-26ed-4fb9-9a4d-07407007a0dc", + "name" : "skip_pre_sizing_joiner", + "location" : "420:212", + "zIndex" : "17", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.joiner", + "version" : "3.3", + "name" : "Joiner" + }, + "configuration" : { + "datatype" : "ShortText", + "inputCount" : "2", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "3bfa0676-38ed-4e63-b1f3-15a1d25d769b", + "name" : "Input 001", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + }, { + "identifier" : "6916e636-e58e-4fa9-ba6d-478f66e81438", + "name" : "Input 002", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "eb6814e5-b299-40f4-b0bd-7f3e9868964d", + "name" : "Joined", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "e2f129a4-31a4-4401-a018-3bb591d0c7c2", + "name" : "systems_design", + "location" : "1044:321", + "zIndex" : "43", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.systems_design", + "version" : "allTime", + "name" : "systems_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "dd053cb7-3f42-4781-beba-47f902d04e64", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "60b44531-2059-4a7b-ac7d-8343a1cc8aa4", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "46dafcea-298d-47f2-b071-bdb5bb390e9c", + "name" : "systems_design_calibration", + "location" : "1114:21", + "zIndex" : "45", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.systems_design", + "version" : "allTime", + "name" : "systems_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "a677f3ba-9863-422f-b763-ad146ec882c5", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "8840cdb6-a1cb-4197-a7dc-3767a3715730", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "95f86ae1-58f5-4427-94e0-11a7008004a6", + "name" : "systems_design_reqs", + "location" : "822:800", + "zIndex" : "57", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.systems_design", + "version" : "allTime", + "name" : "systems_design" + }, + "configuration" : { + "storeComponentHistoryData" : "true" + }, + "staticInputs" : [ { + "identifier" : "ba1837bb-2703-4738-bf93-80fc7a81181d", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "b3ee6691-1180-4c57-89aa-ee9cb770fd06", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "cf47b93a-2f0e-4004-ae12-31c46217a449", + "name" : "systems_design_study", + "location" : "821:621", + "zIndex" : "44", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.systems_design", + "version" : "allTime", + "name" : "systems_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "6adb49f9-b280-4dc7-bab1-ca30e8475877", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "0f34af58-3bf0-482c-96c0-311b38eff259", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "85c7f63c-605a-4091-8924-e1b93b15043b", + "name" : "tank_design", + "location" : "1120:426", + "zIndex" : "53", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.tank_design", + "version" : "allTime", + "name" : "tank_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "true" + }, + "staticInputs" : [ { + "identifier" : "1a9f3756-c915-4804-94cb-a4d51957bc06", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "b6b70c4e-8787-4e5b-be03-5ee401b01a19", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "2fafd9a2-c992-4a1a-84e3-7367bfdff7cb", + "name" : "trigger_calibration_unit_joiner", + "location" : "1143:341", + "zIndex" : "21", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.joiner", + "version" : "3.3", + "name" : "Joiner" + }, + "configuration" : { + "datatype" : "ShortText", + "inputCount" : "2", + "storeComponentHistoryData" : "true" + }, + "dynamicInputs" : [ { + "identifier" : "bb7e5532-5972-41b8-8826-1c076f4a9351", + "name" : "Input 001", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + }, { + "identifier" : "147d7209-609d-40e2-90e6-6b2bea7c4eaa", + "name" : "Input 002", + "epIdentifier" : "toJoin", + "group" : "join", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "e94143c0-9ddf-4011-8875-5fb9273aec88", + "name" : "Joined", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "c9fbb1cb-9fa1-4dba-942c-611ce219bdb6", + "name" : "weight_and_balance_analysis", + "location" : "1517:321", + "zIndex" : "54", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.weight_and_balance_analysis", + "version" : "allTime", + "name" : "weight_and_balance_analysis" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "true" + }, + "staticInputs" : [ { + "identifier" : "6dacab17-aa51-40ca-8870-136f19bec12e", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "02675804-2a3f-4caf-a0e2-d9060fa1ab42", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "541b0cca-7d4e-4368-81b4-bcc09cca893d", + "name" : "weight_and_balance_analysis_calibration", + "location" : "1013:21", + "zIndex" : "42", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.weight_and_balance_analysis", + "version" : "allTime", + "name" : "weight_and_balance_analysis" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "4bc7d2ac-44e1-4da7-bf62-a7c4581e6670", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "700e98a4-156a-4884-89b5-4074da93647f", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "ef9fa21e-1350-4956-a82a-304b03e6cdf4", + "name" : "wing_design", + "location" : "921:426", + "zIndex" : "32", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.wing_design", + "version" : "allTime", + "name" : "wing_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "b5b054b6-2989-4959-8029-d9c7fba40bbe", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "e0eeb0a3-a3ce-40b3-be37-94fec6a586c8", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + }, { + "identifier" : "a64107b8-ae3d-4e81-8ed4-01fde3ceae7c", + "name" : "wing_design_calibration", + "location" : "1628:21", + "zIndex" : "33", + "active" : "true", + "component" : { + "identifier" : "de.rcenvironment.integration.common.wing_design", + "version" : "allTime", + "name" : "wing_design" + }, + "configuration" : { + "chosenDeleteTempDirBehavior" : "deleteWorkingDirectoriesAfterWorkflowExecution", + "storeComponentHistoryData" : "false" + }, + "staticInputs" : [ { + "identifier" : "e87f07bb-b75f-4774-880f-ef0b7471aebb", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ], + "staticOutputs" : [ { + "identifier" : "1e3400d0-d3bb-4c2c-b596-98f334276f5a", + "name" : "current_workflow_name", + "datatype" : "ShortText" + } ] + } ], + "connections" : [ { + "source" : "f1d90e37-bf7c-41b6-981a-44c70e8b6f17", + "output" : "1944ec89-950a-4d31-adea-d761e05192c3", + "target" : "e2f129a4-31a4-4401-a018-3bb591d0c7c2", + "input" : "dd053cb7-3f42-4781-beba-47f902d04e64" + }, { + "source" : "8a71c6da-657c-4477-82a0-49891a14be4c", + "output" : "bfb01312-476c-482c-ae4e-3f00a72c279b", + "target" : "46dafcea-298d-47f2-b071-bdb5bb390e9c", + "input" : "a677f3ba-9863-422f-b763-ad146ec882c5" + }, { + "source" : "e349ce89-8a54-4872-991c-4620d62163b8", + "output" : "751e462c-4a7e-4db7-abb6-3c3954aa0b71", + "target" : "e090fc9b-501e-4c4c-9cf1-b2f871649bef", + "input" : "e886940e-cf3a-4177-b0b9-b97040d71952" + }, { + "source" : "e090fc9b-501e-4c4c-9cf1-b2f871649bef", + "output" : "81ac2cf9-fa50-4167-b723-d1c6bacbb006", + "target" : "16d82d24-4bb4-43d0-bc7d-18c8d64907f0", + "input" : "d027ba57-01ea-46f2-b527-34b2ab979283" + }, { + "source" : "e090fc9b-501e-4c4c-9cf1-b2f871649bef", + "output" : "ebd6cb13-4d54-42b4-b39d-055f51c0290f", + "target" : "15d0bff5-e2ad-46e7-875f-f22bdd9e3b51", + "input" : "11cb3355-786a-430f-a928-5e85327ea15d" + }, { + "source" : "e090fc9b-501e-4c4c-9cf1-b2f871649bef", + "output" : "7cbb1605-b099-4bde-b0b2-9c09f1ff20e1", + "target" : "fdff1cbf-fa40-43af-a036-98a49caddde9", + "input" : "25466c68-9528-4068-af97-428f838b6652" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "19e3d4f7-8c0d-4c74-8a44-bbf84eaedd14", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "b5d6199a-2f90-4f19-ad2e-96f02b95d4e1" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "d1e13946-ad12-4c76-a5e2-daada6966719", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "a429c8cb-910c-49b1-90f3-aece25ef185e" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "317c3f50-7aef-478b-8f43-77e755d2699d", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "85a878f7-2e29-4d87-8d3e-8b7e31828cce" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "4ed7c7bd-e6c5-4538-be5e-de177427d12b", + "target" : "4ddb93ef-f271-4b8d-8c34-8ce11a6e6fbb", + "input" : "fb7cdb30-bc05-4bee-b70c-52d45cda667d" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "4ed7c7bd-e6c5-4538-be5e-de177427d12b", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "f76ce939-43dc-4cc9-be5d-add4c560af44" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "9f25b478-7c6d-4c4c-8366-b9ede21dfa21", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "e0ff6dc1-47dc-412a-b3e4-39c08df4b6f3" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "44963723-13ce-4346-b039-520f94913532", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "8d855cd0-f2db-4c5d-93be-f4f4fd517a61" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "67d461cf-3fd4-45fc-a413-cebf477faba1", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "c9ee86d2-25b6-4447-85d6-5fb57cf26531" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "b6800cc0-15b7-4dc7-98b7-3131063a6c80", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "aaa32404-3a24-415d-9bad-7620d8fa4e52" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "916169ee-19eb-43df-a660-bac558030233", + "target" : "e349ce89-8a54-4872-991c-4620d62163b8", + "input" : "766ce404-9e94-4d57-a9f5-d73199786fed" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "949919fb-0ff1-43bb-b64c-734a6a023a78", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "e8698e2e-8f54-48c0-9ace-5e850943fa7a" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "05839f5d-d3be-468a-bfc2-5e5ad87a2fe0", + "target" : "4ddb93ef-f271-4b8d-8c34-8ce11a6e6fbb", + "input" : "5c605d19-5b7b-4940-9d9b-2571d403e3e0" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "05839f5d-d3be-468a-bfc2-5e5ad87a2fe0", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "37b3ad54-2d53-47e3-95fd-52dd95e6a5a6" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "c0c43fac-65b4-4b06-9e1d-ce1d8d335bfb", + "target" : "4ddb93ef-f271-4b8d-8c34-8ce11a6e6fbb", + "input" : "9cce0d22-b8b1-48ac-a518-9ece29c15187" + }, { + "source" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "output" : "c0c43fac-65b4-4b06-9e1d-ce1d8d335bfb", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "caf8ff74-06e1-411f-b777-9ad0623d7d65" + }, { + "source" : "4ddb93ef-f271-4b8d-8c34-8ce11a6e6fbb", + "output" : "eb08140f-80c3-49ad-b4bc-1292074b48ad", + "target" : "30de1370-ff4a-460f-a74c-16c06e9ef2f5", + "input" : "5ab7f7a5-72be-4789-bfc6-42e12f3cca65" + }, { + "source" : "4ddb93ef-f271-4b8d-8c34-8ce11a6e6fbb", + "output" : "41dbb087-9c35-452c-9f8d-2cc65c93b4aa", + "target" : "a8816b37-0dd8-45aa-bb19-4a13fe74ee31", + "input" : "d42c609e-1c3d-4c5d-a3b4-47ebc6fc16ae" + }, { + "source" : "15d0bff5-e2ad-46e7-875f-f22bdd9e3b51", + "output" : "c427327e-2529-411b-8ae4-bddbbd14057a", + "target" : "955adf0b-210c-4210-a984-04d66ab792ec", + "input" : "43c8f405-ef97-4323-8cd0-53d18ece953b" + }, { + "source" : "15d0bff5-e2ad-46e7-875f-f22bdd9e3b51", + "output" : "4981f85e-9022-4a4d-8060-5defab91e9c0", + "target" : "bfa607cd-accb-4d20-bfcc-f3de47a91d59", + "input" : "5d38fdd9-4c8d-4100-a456-384f361135a1" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "fcb361e6-8cf0-4fe9-bcc1-61c83a81c7ac", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "85ca0f75-8b8e-4fc9-b334-f9cb64623f30" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "6363d86a-58c3-4526-b647-653c156fd598", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "69478b7f-df59-4d1c-ad89-47bdfd07c681" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "79d97dba-3f66-4142-9181-241891cb75cd", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "d027b84c-2f0c-42e1-89bf-35b80766c8d5" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "fcc31ce6-0707-4c81-b17c-5eea81d11a54", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "b2265167-a960-4361-a17a-a4cbe5bce403" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "0cb1fc40-4e7c-4076-a59d-cab779e4d370", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "b097dd1a-d97c-42b9-8cfd-bcdfecc37466" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "5c0a8a4f-12b4-4b28-9b8c-63ee03211906", + "target" : "e090fc9b-501e-4c4c-9cf1-b2f871649bef", + "input" : "186abed3-cc90-4c42-8a74-2053591fe983" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "bafc942c-1020-42ac-90f1-4189ceecf968", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "68459e5a-8f12-4fb1-96ea-0e2b806f24cb" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "43cb6c61-cc87-4100-a77c-683f094134e5", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "000b283d-9406-4e4a-b663-524fc8620627" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "492faca2-c689-441f-bcc8-1c2f0755bae1", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "86f860cf-1e94-4cc6-9348-239b5e3def0f" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "7d0db335-571f-44eb-ae1d-139321ee7ab9", + "target" : "e349ce89-8a54-4872-991c-4620d62163b8", + "input" : "e802ff8c-fd84-43c3-a80d-b4376a94ae9a" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "297dc37c-1970-460b-b62c-de3e4007c258", + "target" : "e090fc9b-501e-4c4c-9cf1-b2f871649bef", + "input" : "a8b3f797-9727-4935-a87d-252b02a0d600" + }, { + "source" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "output" : "560ccc89-d0d0-4740-b8ec-3c1eaffc0559", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "92cd1e9c-7aea-4952-a959-f6da2f3c1f59" + }, { + "source" : "fdb39adf-3696-4e67-9e75-b0a79d7b3953", + "output" : "c20cbe58-f83f-41b4-b46a-cc2de8b62f27", + "target" : "c422c632-93db-479b-9185-d494be3b836b", + "input" : "f8f6aa27-41b4-42fa-b3c3-71f14adac325" + }, { + "source" : "fdb39adf-3696-4e67-9e75-b0a79d7b3953", + "output" : "d67fbd36-3587-4129-9099-83063db6ed0f", + "target" : "96f79610-adc4-49a4-8727-9133b99b54bf", + "input" : "d80ece7f-c96e-498f-b29b-8d75ade28a14" + }, { + "source" : "fdb39adf-3696-4e67-9e75-b0a79d7b3953", + "output" : "d67fbd36-3587-4129-9099-83063db6ed0f", + "target" : "96f79610-adc4-49a4-8727-9133b99b54bf", + "input" : "c330c0fa-d9ed-40b4-89ff-4eb4564bb6cb" + }, { + "source" : "fdb39adf-3696-4e67-9e75-b0a79d7b3953", + "output" : "3a9817c4-04d0-4651-bb94-dcae4bded043", + "target" : "c422c632-93db-479b-9185-d494be3b836b", + "input" : "eca720fe-7281-45ca-8808-f0d39b47a79c" + }, { + "source" : "fdb39adf-3696-4e67-9e75-b0a79d7b3953", + "output" : "b69215d8-f495-4b6c-8d44-4727621b5e2d", + "target" : "c422c632-93db-479b-9185-d494be3b836b", + "input" : "9f764eab-16df-41cd-9202-319865728acc" + }, { + "source" : "955adf0b-210c-4210-a984-04d66ab792ec", + "output" : "546f80b7-6aa0-4e74-a787-e6aad690f6de", + "target" : "bfa607cd-accb-4d20-bfcc-f3de47a91d59", + "input" : "8e7a3a22-6235-4baf-a466-decbdd71e660" + }, { + "source" : "785ca8d3-bb68-4f0e-a2ac-0ecf3375037b", + "output" : "8f0c00d3-1072-41b0-afbd-9fbb163a1fdd", + "target" : "e6a4d26e-4d4b-4372-a75d-ebf2506c5fb5", + "input" : "ac0ccefd-f1a5-4733-9d52-3fba7b59d19e" + }, { + "source" : "14d3858b-82ae-47f5-aa33-9501f7341409", + "output" : "eaa67876-34a0-494d-9b89-5ff6f0743393", + "target" : "a8f0662b-83ca-45ed-b29a-2331931148ee", + "input" : "e5f2df51-817f-4394-a96a-e8e04a5abbe1" + }, { + "source" : "30de1370-ff4a-460f-a74c-16c06e9ef2f5", + "output" : "3ec3b035-fa94-4fb4-951c-25bfdfa491fe", + "target" : "8609525a-c3d9-4b70-97cc-e8889652b357", + "input" : "9d2e8fba-6e6b-48f1-ab40-d5742a26b38e" + }, { + "source" : "28defe30-f45f-4a6c-9c4d-117e96fede0b", + "output" : "c078f515-d20e-4c72-b49e-f212365e2cc6", + "target" : "95f86ae1-58f5-4427-94e0-11a7008004a6", + "input" : "ba1837bb-2703-4738-bf93-80fc7a81181d" + }, { + "source" : "947b6847-a819-4c53-b4a2-14189fa2cfac", + "output" : "0e386a25-2cfe-4eee-b337-c64927019041", + "target" : "cf47b93a-2f0e-4004-ae12-31c46217a449", + "input" : "6adb49f9-b280-4dc7-bab1-ca30e8475877" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "682fe369-864a-43c8-803b-28953e3bb98e", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "1d3fb5f4-19bf-42ed-91ef-87851ed86467" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "2c734a35-25bb-49dc-9541-2c204dbfeebd", + "target" : "9e1e145e-2348-49ae-88d5-94ffbf0bbcc4", + "input" : "23ccac1c-147e-4abb-b0a4-f38c58227cfe" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "2c734a35-25bb-49dc-9541-2c204dbfeebd", + "target" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "input" : "8b4c4b74-d5b4-482f-9449-bfcfcddce96b" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "716e6d4c-63ab-4f40-9093-795b415d5c7b", + "target" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "input" : "16409b06-a5c4-463b-b597-8bcc0ca4c35c" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "0e441ba5-d8cf-4b55-b583-14cd42abec47", + "target" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "input" : "abdb0d5a-a1ef-42f7-89a1-bcc7d15f4aa6" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "08c25001-21ee-439f-a18d-897ce2f19dbc", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "26ded494-c001-4295-b255-d06869200f22" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "e257f8d3-28df-4497-89ef-3a93421db21f", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "9bc417c7-8314-4141-b376-326966369e85" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "74e07ce5-9ad7-4d3a-b34f-66715320cd1e", + "target" : "9e1e145e-2348-49ae-88d5-94ffbf0bbcc4", + "input" : "15508c4d-b775-49fd-8a9b-71bd1220aecf" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "74e07ce5-9ad7-4d3a-b34f-66715320cd1e", + "target" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "input" : "e96b6156-6ef7-416b-a707-f1d22898adcb" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "5f51ff00-b28a-4cae-8f04-2cf3277ce44e", + "target" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "input" : "8b28e89d-ed0d-4295-81a5-2c134af5ee83" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "a11c718f-550d-4158-a29f-a2e890003d08", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "1304a325-8475-434f-8877-2789a2b4082d" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "c12adbae-0974-4aa4-89f3-1f11fef1b188", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "ab9a7852-5a75-4842-8a31-199bd751801e" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "09780450-0acc-4e67-8bff-a34c4b98800a", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "68ec6baf-f1d9-48c8-be6d-8b55b03cc16d" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "21870ea7-d446-44ca-a636-7f0b692d5044", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "bf5ec31b-00f5-45bf-9c44-836fe9296a2a" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "e764df4a-192f-40df-9642-a1ab3bd21f36", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "4669cecd-7947-4216-bcde-f92b980325a3" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "74e28b0b-0dbb-4381-a1db-e23ee96f45e5", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "50e60488-5d3b-4307-a76a-d8ef5ca06abe" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "2e7add2a-64ca-4733-b93f-b5ec981d9ab6", + "target" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "input" : "fdc7d4fd-8d9e-410f-a570-22a27d6a023e" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "a6cd3ad4-cd5d-4431-afd6-691e095230f2", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "6b87d29f-ccfb-4f33-b529-f1f8ce28fec4" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "0efa89f1-5a9b-43bb-8c35-45f9093a26b0", + "target" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "input" : "8e467da2-b754-4af1-82f1-95d44c84650d" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "0efa89f1-5a9b-43bb-8c35-45f9093a26b0", + "target" : "edf5cb5c-763e-47b6-8c4e-ed9caad67051", + "input" : "e5ff2ccd-a89f-4220-8116-e43ce9e52ef1" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "0efa89f1-5a9b-43bb-8c35-45f9093a26b0", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "512cdf15-02fe-486b-bdc0-e2d46eea68a6" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "f96c55de-f0b0-4dbd-8921-2743c93174a8", + "target" : "9e1e145e-2348-49ae-88d5-94ffbf0bbcc4", + "input" : "16aa0097-47d2-47a6-9a2b-230a5a321783" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "f96c55de-f0b0-4dbd-8921-2743c93174a8", + "target" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "input" : "54504ea4-9974-47da-b223-770bc1ee3c58" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "1ad2d3ce-d1e9-4c2f-93fa-b7ee8e19b3fd", + "target" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "input" : "38327c32-03e4-4fa3-bc44-cfeb6a31e29b" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "1ad2d3ce-d1e9-4c2f-93fa-b7ee8e19b3fd", + "target" : "edf5cb5c-763e-47b6-8c4e-ed9caad67051", + "input" : "306c62a0-49b3-428c-9ab5-045bd249beec" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "1ad2d3ce-d1e9-4c2f-93fa-b7ee8e19b3fd", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "ba507e5a-9208-410b-be58-aea3a972799b" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "f4e2a88c-1480-4b3d-9c78-05c0c6ddc963", + "target" : "9e1e145e-2348-49ae-88d5-94ffbf0bbcc4", + "input" : "779b50ba-f3e6-4d4e-920d-5f09a3a0d1ad" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "f4e2a88c-1480-4b3d-9c78-05c0c6ddc963", + "target" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "input" : "27344f89-5ec6-44f4-9a6d-42c626ee63e5" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "bd7d2bba-6de5-4ae7-be6e-b7d15b40d3b4", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "05dac670-b81b-4d54-96b8-5b941a680c94" + }, { + "source" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "output" : "cddde916-3761-450e-96e5-a1b9f1b68279", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "fcd82abc-4b65-4168-ae57-91289b416523" + }, { + "source" : "edf5cb5c-763e-47b6-8c4e-ed9caad67051", + "output" : "8419db9e-bd31-4300-90a5-cb74c8151bc3", + "target" : "14d3858b-82ae-47f5-aa33-9501f7341409", + "input" : "63e8b1e3-4d79-4473-9370-6e8de7f0c34f" + }, { + "source" : "edf5cb5c-763e-47b6-8c4e-ed9caad67051", + "output" : "8792830c-790d-4731-89be-cc8ba7babc4c", + "target" : "2fafd9a2-c992-4a1a-84e3-7367bfdff7cb", + "input" : "147d7209-609d-40e2-90e6-6b2bea7c4eaa" + }, { + "source" : "e6a4d26e-4d4b-4372-a75d-ebf2506c5fb5", + "output" : "c8476e8b-c101-4b97-8de1-1cfd877d96a9", + "target" : "8b87e3bc-05e4-4933-998a-60d71cf0c423", + "input" : "65b9cde4-4265-4a1c-9700-6ad821a4caca" + }, { + "source" : "c19fa814-5c75-4125-a806-4f001b7ef00c", + "output" : "127cab9e-75e6-47d7-8744-b13a001a5f97", + "target" : "85c7f63c-605a-4091-8924-e1b93b15043b", + "input" : "1a9f3756-c915-4804-94cb-a4d51957bc06" + }, { + "source" : "6c7d11a2-ff6b-411c-a7c4-5853d6471740", + "output" : "17e2ed99-0023-42b9-b4c3-5083dd119805", + "target" : "cd51d621-4989-4ce5-afd9-038c035b64ba", + "input" : "2c15323e-b730-4650-8e77-0718c6ad193d" + }, { + "source" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "output" : "755d4508-8019-44da-87be-7ebe24332fe2", + "target" : "fdb39adf-3696-4e67-9e75-b0a79d7b3953", + "input" : "fe78d694-64e3-4bc9-82d1-ad4e4213bb9d" + }, { + "source" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "output" : "e1888fda-8c50-4a32-a05a-9c97028d6b2b", + "target" : "fdb39adf-3696-4e67-9e75-b0a79d7b3953", + "input" : "6dbac510-6ca9-4393-bf8a-0fea5687aa4e" + }, { + "source" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "output" : "ceb4e534-01ef-4dc2-9c22-46026321a3ec", + "target" : "28defe30-f45f-4a6c-9c4d-117e96fede0b", + "input" : "5afa2be4-e393-4f0e-a845-43e248bb43a3" + }, { + "source" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "output" : "81fdc0a4-19df-4206-b0c7-fd757759d82c", + "target" : "fdb39adf-3696-4e67-9e75-b0a79d7b3953", + "input" : "e6d39819-517c-43dc-8c79-dfea4a97ce67" + }, { + "source" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "output" : "70dfcec6-e41d-4196-845f-c902e42544c3", + "target" : "fdb39adf-3696-4e67-9e75-b0a79d7b3953", + "input" : "ffbf6e03-3c0a-4981-819e-553c53bf9b7f" + }, { + "source" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "output" : "0ad0138a-52de-4868-b98c-aceeb960b1a2", + "target" : "8b87e3bc-05e4-4933-998a-60d71cf0c423", + "input" : "ac31c847-1fe5-43a9-9f86-6db8210637cc" + }, { + "source" : "9e1e145e-2348-49ae-88d5-94ffbf0bbcc4", + "output" : "8ca02537-9b99-4ccc-9ba8-24e053dcf915", + "target" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "input" : "dcf6e010-cf9e-45c8-b065-e1213eb00575" + }, { + "source" : "a8f0662b-83ca-45ed-b29a-2331931148ee", + "output" : "e845278f-088d-454d-9454-de118f4fbc67", + "target" : "ef9fa21e-1350-4956-a82a-304b03e6cdf4", + "input" : "b5b054b6-2989-4959-8029-d9c7fba40bbe" + }, { + "source" : "8609525a-c3d9-4b70-97cc-e8889652b357", + "output" : "32e9f1d0-c0c4-419f-8baf-59cdf23368f9", + "target" : "a64107b8-ae3d-4e81-8ed4-01fde3ceae7c", + "input" : "e87f07bb-b75f-4774-880f-ef0b7471aebb" + }, { + "source" : "df71fc65-60d1-4dcb-9bfc-67424c6db107", + "output" : "058d22a8-e8cf-48c7-8ac3-85d328edf4c1", + "target" : "356159aa-26ed-4fb9-9a4d-07407007a0dc", + "input" : "6916e636-e58e-4fa9-ba6d-478f66e81438" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "ca24ddc6-34a5-439a-9757-90693255d91a", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "1636954f-2bc2-43a9-885e-7fa3f0e10565" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "1808c4c8-286d-4665-ac5a-32c698f285b5", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "dc605c7a-095c-411f-a6f1-74420fe41815" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "9da1a5a7-637f-4bf0-8aad-77b599b1e3b2", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "db8d3c8a-0ffc-43c8-b052-c80f142b7573" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "32520df2-079b-4976-a100-08c0944877cb", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "b68997ec-b2dd-4be5-9f23-5dca89c17dec" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "2c78d2e1-589c-419f-8ad1-8cf60f6c14cc", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "bbd1d9d9-851b-4bf3-9505-7b2a28bc756a" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "40a0386c-a4d1-4435-84c0-3b88030d451a", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "b960a680-9864-41b3-a86a-658df2b4e31d" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "b34da647-0654-4218-8e0c-49d5128ae7b7", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "c950b61b-9947-4dde-9b8d-61a575fba946" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "ac95f46f-e42e-4049-9514-90f2c9424b3d", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "7ecfd6fa-4ae0-4c4e-9db1-96e69c428514" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "dfb96afb-22d2-46f8-aedd-a9a124d69c99", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "3469cd78-6ab0-40c0-a797-0fe805be23af" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "313efdc9-70e0-4a43-938a-b9a3605be47f", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "d895b097-3528-4831-8f5d-861103ae2ac4" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "a5a5e791-280e-4008-88c0-1ae45c44fd6e", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "8be52fd7-55cc-4187-b0bd-37960f867e9f" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "fa0bd568-e34b-4212-a4c2-2ae2ff553df5", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "fbf1a57f-913a-4a36-8f5a-86b847b98c90" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "763ac133-1b9d-4014-8ef3-a5b985d7ab59", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "a46ef22d-48af-42e6-8477-633e04722b6e" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "21003046-697c-42e6-95d4-cd5704721fc1", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "edd8e1ff-a43e-426a-93ad-4def45ac5928" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "5d6a4e15-5230-43df-95c0-691592bec82b", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "0e8ca26e-157a-4eaf-9d39-9d8462bb5c32" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "6048ca28-60b2-4b2c-ba76-e8db612dca14", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "e05079fb-af2d-47a3-b58f-61f43209f9ff" + }, { + "source" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "output" : "78a4fc90-03f2-4214-9628-11261c364e31", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "956a3ecc-f505-484e-ac25-e7e388199c04" + }, { + "source" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "output" : "4a3aebf6-4d93-426b-a321-2eab306e03cc", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "b8459983-1bca-4289-b4ab-4f071d2201f5" + }, { + "source" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "output" : "bd9ee66f-7a48-4547-ba42-7e86204c511a", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "fa5d0ad1-dcfa-4172-8406-d12ba4ec274d" + }, { + "source" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "output" : "5b06959c-faff-4d03-a6e7-ac1949ecc35f", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "7bc1ff55-6103-4c4d-b2d8-7cbb2b3f4ab6" + }, { + "source" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "output" : "ce22ba8c-8d85-4a45-9f67-5f9878ac57da", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "6985ecc3-fa99-45df-9f47-24cd146b1179" + }, { + "source" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "output" : "a27abc62-af66-4756-92f3-2fcc12b9836d", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "1291b281-dbdf-40f4-8702-c84f4fcbab87" + }, { + "source" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "output" : "d7152fad-be82-435b-95bd-51bb1157908e", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "0b1957f4-fe2d-43ed-9a1c-63a7dd394f2e" + }, { + "source" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "output" : "de9a7e75-a928-4049-8e81-bf93cb63d27a", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "8b35a366-4b08-4dd5-bd77-be6cf8c2784d" + }, { + "source" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "output" : "7fd4a49c-19a6-4212-956b-9386965dc368", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "a3dfd495-8558-496b-91c8-22cbe9d08e0c" + }, { + "source" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "output" : "72b17cdf-ef01-4d67-b365-bd1f9dfb5605", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "22c49d66-3621-4809-8042-ee14250cacdf" + }, { + "source" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "output" : "cbd1b14f-e34a-48e8-aadd-c01091d66b0d", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "8e23ab3b-e27e-4150-ba34-1d5b8307a94a" + }, { + "source" : "4f49aa16-b47e-4279-8e79-d3d613c398cc", + "output" : "01c7e151-a74e-4ee1-9849-b2888927937f", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "cb4785f2-820f-4d31-902d-94aa3672bbe0" + }, { + "source" : "23f0a309-d793-4b6c-871c-483486428971", + "output" : "e98ca659-d6e6-4588-a48e-baca06fc038f", + "target" : "f1d90e37-bf7c-41b6-981a-44c70e8b6f17", + "input" : "ee2528b1-3e9d-4302-868b-033120790ef6" + }, { + "source" : "993a2aeb-4334-4b80-9ca0-29f1c1d22051", + "output" : "b302a2c7-909c-4a87-9ae3-63657bcf2d7c", + "target" : "8a71c6da-657c-4477-82a0-49891a14be4c", + "input" : "a3cc874b-0c30-4202-840b-2cabea2f6d60" + }, { + "source" : "16d82d24-4bb4-43d0-bc7d-18c8d64907f0", + "output" : "75b47bd7-9c07-4380-9425-b538b322868c", + "target" : "c9fbb1cb-9fa1-4dba-942c-611ce219bdb6", + "input" : "6dacab17-aa51-40ca-8870-136f19bec12e" + }, { + "source" : "be1fbd21-d6c5-4c72-9dc2-8569dd06be27", + "output" : "7cf80042-5928-4e85-8089-a2eb13e2efb7", + "target" : "d1de52bd-1aa4-4f4d-9b77-8286e8fd26fd", + "input" : "7f77f127-73d8-45db-9fc5-03a42b90540f" + }, { + "source" : "1c0c576d-5990-479a-9153-95a741ed9974", + "output" : "23f0992b-0d4e-4051-a869-27a98296f60e", + "target" : "c9104e19-a903-48f7-819a-6268462a5b26", + "input" : "950760b1-4eb4-4be3-8946-4c39b3c83386" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "be11fe82-0d5d-4930-b8db-cb273d8017cb", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "ea1214c5-2e39-4ff9-94f0-ebcdb5a8de0c" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "d227f8e2-e09d-4586-a2fd-6077bc69fef6", + "target" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "input" : "f1962cf4-f57f-495c-a32e-c8354f9a29fb" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "b176fb50-afe8-47a0-9f8a-617e2974818f", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "a570e7b2-4c72-4081-92e3-e8681786e987" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "bcce8b67-d5aa-411c-8878-4baae70bef06", + "target" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "input" : "81c72d11-9eea-41ff-b2db-ced65f32bc34" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "6e9e6d71-b3fb-4def-8be5-3034be6fcbc5", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "342f85af-a6e3-485e-ac6d-ca70e6f3761e" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "caa15f3e-e102-4773-be31-97a1b3abd023", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "900b5112-1386-4e12-a92c-7542e11991d5" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "9feb2dfe-0bb2-442f-b519-f46920e03628", + "target" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "input" : "14a3a9e9-6af2-49c6-afce-d72b2c170670" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "7daa4d82-fb53-43d1-b9e5-6ee49a4734a6", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "b6e1e778-854b-4c33-a354-bb5bd556ca63" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "3b3383f9-58b7-43f7-bc89-d40f9db4aac9", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "e32b5f2d-e71c-4432-814a-1c7557ffb5f6" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "a35a2ffc-55fd-4262-a82f-33b0e4c6f4a5", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "3f02bf11-ca3c-4563-8129-f88f4d4181a3" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "988c519e-6c29-4839-afcf-06e6aa6c8d7d", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "a8e0bfb3-4ccb-4f97-9411-7a428103b523" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "75d9b559-894f-4726-a771-bcd2d70ef697", + "target" : "492e4c3a-c719-44af-b20a-9e1b9ff89bfe", + "input" : "2a2ee247-7f95-4af6-915d-9cc32b948ee5" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "75d9b559-894f-4726-a771-bcd2d70ef697", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "44997c38-7c44-48a9-99ce-531ee4fd4c58" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "9053b71b-c081-469c-bdc6-61ee126209cf", + "target" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "input" : "dcbcae17-9f15-4e2a-9aae-0d6c29c1468f" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "45cfd1f4-eef3-44a6-a38a-8e69895448db", + "target" : "492e4c3a-c719-44af-b20a-9e1b9ff89bfe", + "input" : "7558d879-a8f0-4c56-a1e0-3693baeac211" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "45cfd1f4-eef3-44a6-a38a-8e69895448db", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "d03f24e2-f1ba-4868-8de6-53d3e3c9500f" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "9b2a2be5-d704-4b0b-8292-caf14662ed49", + "target" : "f9af54bb-8bbc-4dfa-8ca6-9b93381c4376", + "input" : "48cf0d95-4fa0-40d0-82cd-d8d4aebe922b" + }, { + "source" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "output" : "211923a4-8df8-4502-a1f2-7f035c9ac79a", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "20ce6a41-f626-477b-99d8-bc0d66e31c31" + }, { + "source" : "c9104e19-a903-48f7-819a-6268462a5b26", + "output" : "25af7c46-672b-4bc1-a34d-4e5972069549", + "target" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "input" : "28880f28-ee94-41ba-b6cc-e57c0f577f56" + }, { + "source" : "492e4c3a-c719-44af-b20a-9e1b9ff89bfe", + "output" : "333b4005-e00e-4bc1-bfe6-f32acf3ce542", + "target" : "947b6847-a819-4c53-b4a2-14189fa2cfac", + "input" : "89ef62b0-4026-4797-896d-18626b7dc471" + }, { + "source" : "492e4c3a-c719-44af-b20a-9e1b9ff89bfe", + "output" : "2bd06159-cb0f-48b4-b73d-6c692467806f", + "target" : "c9104e19-a903-48f7-819a-6268462a5b26", + "input" : "44f3f882-9ab5-4586-869a-9d41816bfce5" + }, { + "source" : "a8816b37-0dd8-45aa-bb19-4a13fe74ee31", + "output" : "e9115015-6833-4ba6-8d30-2d13eca1c6a7", + "target" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "input" : "4bf3391e-fab1-4c0d-8171-fe9ffc9195f3" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "36b96c16-6b90-42e9-98d0-7ee5542950b9", + "target" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "input" : "7b7c3051-b4d7-4145-87b8-a9eb3a9cdefc" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "966bb476-e753-4564-88d1-21ff42092c7b", + "target" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "input" : "2b2a355c-050a-4c16-9ee3-20cf26ecd03d" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "f1817b7c-6edf-4d78-a085-067dd1deaba3", + "target" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "input" : "3deb37ee-aa02-4f86-b8e3-afcb670ebaab" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "1dc950fd-7c78-4a64-86b4-de4f5b3ab580", + "target" : "c422c632-93db-479b-9185-d494be3b836b", + "input" : "4f5f5492-612c-4ce5-8b9d-92ba8e9dcc31" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "a79bf8d3-decc-4ddd-850e-9ba11b22263b", + "target" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "input" : "f3e9289e-d3b1-4fa7-9035-3da5dc3937e5" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "96ee8c0d-7629-42c9-a66e-7e1aea4bdc09", + "target" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "input" : "58d1914c-1a0a-449e-a8bf-aa5f163e914a" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "f3230fa2-8f12-43a8-8742-8e457bcaf0c0", + "target" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "input" : "7aed0ec9-9328-45a1-8431-5626b46e9af2" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "98963b28-462e-4aa2-9784-182c0139fbfc", + "target" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "input" : "7c61708f-dd5d-4836-b955-3d2dc325ab3a" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "29e2c7fc-43ac-4880-ad6b-6bd6e325aa7f", + "target" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "input" : "f22305a9-c47d-400a-a1e4-97765030e65a" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "b18b05e2-5d79-4de4-8343-484ba76588ec", + "target" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "input" : "5b995f5c-cf80-4072-bbee-efabd04e240a" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "63a83bb6-8d80-45d0-9334-87ab856721c3", + "target" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "input" : "cf06059d-449c-4279-9079-2d5f12f80075" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "af3cf777-aeb0-4d80-9051-71fc78393b3f", + "target" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "input" : "cabf72e0-601c-46f7-a388-65e64f95469e" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "844951cf-4b50-49d9-9a4e-e02f6da15c16", + "target" : "8addc91f-83b8-4964-b588-72d53784d5ff", + "input" : "79250d52-28db-4296-89cc-f39f9d5ebc48" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "dc83a264-f1e5-49bc-bd1c-f471165edbe7", + "target" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "input" : "a24bac44-e8c5-43bb-aab8-29c9c0d8b7a6" + }, { + "source" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "output" : "dc83a264-f1e5-49bc-bd1c-f471165edbe7", + "target" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "input" : "e5ca537f-783f-46d3-966f-caaef2ef2c6c" + }, { + "source" : "85d83a8f-a440-45a9-bb41-aa819f6971e5", + "output" : "6f80ad4d-8ecd-4a9b-b170-b86c132806b9", + "target" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "input" : "77675aa6-f349-41bb-86fa-f9e1bae105aa" + }, { + "source" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "output" : "f720d7b0-1138-4128-ad7d-9646441ae362", + "target" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "input" : "74b1a73c-a723-468f-8113-7d7c326ff791" + }, { + "source" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "output" : "9b0f7feb-d595-453b-891b-d8cf44ba44c1", + "target" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "input" : "3d69d4b8-2729-4e4e-8f35-e945f40dba35" + }, { + "source" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "output" : "23502b9d-a83c-4748-bda2-c527e24c74cc", + "target" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "input" : "a33bcfc2-92a4-47aa-8214-c36d3ddffe82" + }, { + "source" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "output" : "4b25f2d1-2c2c-4106-b646-702ed9d3b3dd", + "target" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "input" : "cef6af4f-e718-4ea9-8323-098e6372519b" + }, { + "source" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "output" : "7af74b17-d21c-46c6-aa25-75e4d303d80a", + "target" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "input" : "df6e35c6-aa83-4fbb-840c-17440539ffad" + }, { + "source" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "output" : "01ce0bfa-1b5a-4993-bbb1-0e720dd1cec1", + "target" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "input" : "26bd5353-8194-4ab0-9963-35e32f0412c9" + }, { + "source" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "output" : "9c73eb58-8157-4e2e-9ef9-9002f8610c1b", + "target" : "4e0887ce-8b93-4de5-b4af-5aa3ad095d6c", + "input" : "549e15de-5e5b-4a59-864d-0bed12687070" + }, { + "source" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "output" : "4dac1c16-7baa-4d3c-b9df-23d2378e45d9", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "bad0087e-cd88-4857-9f50-ad3e5ddfa83d" + }, { + "source" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "output" : "a2753cec-901b-4248-9456-4ebc1334df12", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "21a3ffb1-e742-44e2-a6a2-fe7f8009d289" + }, { + "source" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "output" : "f7c60626-1541-47b6-ae3a-3c449570f0d0", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "8b73bc0d-408e-4b00-94ac-954ee883e6e4" + }, { + "source" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "output" : "2213355d-582b-45bc-9e0d-9feb4f1bd0d6", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "68b5b61c-2843-4115-9d48-204b81e4d808" + }, { + "source" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "output" : "fc80dd02-4a9f-4621-9cc0-a4eabbc11bab", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "222bc266-e497-4c14-9148-1d0075e598c3" + }, { + "source" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "output" : "aea980e1-e4f2-4c30-832a-d9346b354b35", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "e7780bc4-2879-4324-b36f-06ba971ae8ea" + }, { + "source" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "output" : "bb931d85-55ae-4ab3-ae27-7e30f56b7fd0", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "1b6369d1-3e84-497f-b9f5-2288e88dcf08" + }, { + "source" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "output" : "ed680b37-42e1-4908-91ae-7ece97aa467c", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "3cd16a12-115c-4bcb-a4c2-44d585584954" + }, { + "source" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "output" : "0b89e6ec-2820-42c8-8178-aa0540afde78", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "4e2e94ad-d761-4c2f-b5c5-ff364e8a8bdd" + }, { + "source" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "output" : "b48956bf-87fa-4f0f-b239-abb7eff2a7ba", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "3091b26e-fb72-4c7f-8dfe-7e4760dfdceb" + }, { + "source" : "f136e7ab-3ee3-4b26-b33b-457148d678d4", + "output" : "98db32a2-b885-46c7-a62e-e476a346e81d", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "1860f6e0-1f17-4719-995b-57474ac99506" + }, { + "source" : "d1de52bd-1aa4-4f4d-9b77-8286e8fd26fd", + "output" : "c69a2d04-3e76-401f-a0b5-622a2dcfa304", + "target" : "785ca8d3-bb68-4f0e-a2ac-0ecf3375037b", + "input" : "3dcd1902-d6c3-4bd5-a55c-4cf81bc5b59e" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "032691f2-c91a-4802-8570-3ceb51c67551", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "6583c056-dcb9-41e7-8865-bb8f54d67b2a" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "be463602-1e0c-47c3-a801-db062fbbc3bf", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "33877e48-87d5-4549-982c-9d0de1e8b82b" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "d02022f7-3cda-4994-9644-80ae59aa8fc2", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "d9e1391b-38db-463a-82cb-9428d929e36b" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "d1b18faf-61f9-4b88-9cba-d67cee47b152", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "35716001-de65-49f4-ad8d-06f113af2ff3" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "b7c93131-7ffb-4742-a2b2-843c220d03c0", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "ccc74d90-a965-4367-b2a7-868e991cd280" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "2eced146-dcb9-4dda-a6a3-9d2e7b847032", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "640949f1-7633-4785-939e-39b6e5fbe676" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "59e4483e-fce8-41b1-adfd-8918666178a0", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "ea776d0a-efa8-43c8-ab6f-67fecad1deb3" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "9ef1cf52-20c0-44cf-ab98-59324d791e69", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "d5c3aa8b-c6d2-4cd7-825a-d58b2dbbc633" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "43319d92-d5b7-4b44-a14f-260bdbcd6fc5", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "150a469e-2f3d-4c6b-8026-91ebd14a2cda" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "a9512f69-22e1-4feb-98ff-80f6d8c8929a", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "302d0238-826f-4a23-9266-1c7e53af3919" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "f5f87451-abbb-42ff-a827-9b453748c11f", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "e0a44e95-1a7b-4c2f-8dd1-44c62a15a571" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "80de462a-f1a7-4053-8072-199127cda91d", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "4654849e-20b1-4355-8275-bb4c3e0b78b9" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "3c027a9c-97c4-4cd1-9ea3-e89bcd66d54e", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "f364243b-e947-41bf-a3dc-69c59d520780" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "4d328456-8b5f-4aa8-a60b-4a9b0dbe3387", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "37a5f9ce-3fb5-4ec1-a69c-1b645698cf21" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "3f4ea7d6-91ed-43d2-b48f-8236ddf5b447", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "dca29a23-e52f-43ba-8ef2-cb5d9597bfc8" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "29ed4976-3c0e-49f0-9df9-94b96afd2742", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "6d1c8342-d5cd-4444-9d48-686d7abafdf9" + }, { + "source" : "59b94c21-6c41-4ead-996d-b63a98137535", + "output" : "fb016221-45f6-4057-8ba2-30b78bb4d51b", + "target" : "a5286554-f730-4229-aa5f-62b1b51537a8", + "input" : "154e4935-f6cb-4c0b-bbf4-6914de746e5d" + }, { + "source" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "output" : "024cb0f0-46d9-4d47-8eff-2149047b037f", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "242fac67-7f81-4f4c-b95a-39f6dfbfd645" + }, { + "source" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "output" : "e56f7fa6-cdad-495d-96d8-723ef13c4a3b", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "791c2a6a-aa7f-4fb8-bf16-71776ebe9752" + }, { + "source" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "output" : "992ffa3d-301d-4682-8d2e-5810d40cf5ad", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "eb8849b3-6930-4552-93cc-89a9a23c7a17" + }, { + "source" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "output" : "c27146e1-a29a-47bf-ba33-6fee7cf4c811", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "a84331da-9be9-41d1-9946-2df6f617528e" + }, { + "source" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "output" : "0ce8f9b1-11bd-4a70-b871-21a97a97c193", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "f4e56642-289e-4733-b647-b944caf25307" + }, { + "source" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "output" : "14578be4-e463-4da4-9aa9-62e3fc8ebf7d", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "3bbb41a9-42bb-4393-869a-58b995e0ef30" + }, { + "source" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "output" : "9750ec36-c262-4691-ad51-e8b1b51f6cf7", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "2bc5348d-9f21-4ecf-aa31-a08b6194ef31" + }, { + "source" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "output" : "7baa6e61-4b83-456d-b26e-448aff2449b1", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "338d261f-e913-4897-9b50-2896fcfe34c5" + }, { + "source" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "output" : "d2ade8b0-87fa-4fa5-aa1c-6410403010a8", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "afb1f9eb-4034-4893-8d5d-0f8030d66a3d" + }, { + "source" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "output" : "a1f5c584-4374-4b5d-9aa3-4b6edc504b86", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "341d1d71-802f-4e4e-980c-648758531829" + }, { + "source" : "ec469b30-8b67-4d57-a378-eda0e631d664", + "output" : "acf23b58-2215-4552-b315-e518a5cfc560", + "target" : "b78ceae1-2502-497f-a30c-70034cdce85c", + "input" : "bd009583-baf5-4dee-8b9b-94e056818f0b" + }, { + "source" : "8b87e3bc-05e4-4933-998a-60d71cf0c423", + "output" : "abc69e40-ce73-4d38-93ff-61c5dfc86526", + "target" : "fdb39adf-3696-4e67-9e75-b0a79d7b3953", + "input" : "d78b0adb-311f-4d13-ad62-fbd8dd8df448" + }, { + "source" : "c422c632-93db-479b-9185-d494be3b836b", + "output" : "1cd77081-e882-417e-92d2-cef4b2784f2f", + "target" : "85d83a8f-a440-45a9-bb41-aa819f6971e5", + "input" : "9a800c80-ada8-4f24-853c-86257dbb01f7" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "1b852eb3-6555-4c38-8226-955231802adc", + "target" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "input" : "7990a966-1476-40e1-bcbb-81bdd7f49380" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "91ee93a9-618f-4f27-948e-b6627cfb7238", + "target" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "input" : "6c580b92-0035-42e9-85b9-7abc17ef738e" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "03040c5a-50ec-442e-8e1a-982bdd438f35", + "target" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "input" : "727b53e3-5430-4328-ad44-b639878fc14f" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "adb29e96-d044-4a42-8210-5e02f3476f78", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "c4a7d10d-7312-49ce-98ff-1e71cf02b5b3" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "be6cddd4-4425-4139-a984-914856714e4f", + "target" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "input" : "a0c66ab2-8251-4efc-8ff4-146060523828" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "00e10e8c-31e3-4b9b-a888-02763f08d9d4", + "target" : "df71fc65-60d1-4dcb-9bfc-67424c6db107", + "input" : "cc578fb7-01fc-441a-9e7c-6d8a6cf03ac8" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "23c00739-352b-4a53-8425-5d5eca96de22", + "target" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "input" : "379aa1c7-3afe-4381-a199-9e46a762afd4" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "f039192c-5eea-4cfa-a82b-65758566fdfd", + "target" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "input" : "eea0fca0-3bbd-43da-bbe5-e9d1c9f0cc8b" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "ef1c8021-ea53-4f27-9035-7be65f93cdb1", + "target" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "input" : "96e44b99-4408-4d9f-a5c1-a114b1f75147" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "c1319f18-7fc4-4586-bd45-1de9e31adfc9", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "725a7752-9fb9-4da3-8315-07ef8b95c1e0" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "81aac912-1551-4192-8082-2133b09cafae", + "target" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "input" : "fb8d926e-91e3-4e22-a9c6-4c2c1e8521b7" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "326dfd2b-264d-4a47-9619-54d6e4300ed3", + "target" : "994fa6fe-5dc2-4b48-8503-019e8a4c4879", + "input" : "d9ff462e-00ac-4bcf-a803-ef6320f3573d" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "32198062-4c91-44a0-9bf8-b3f41c658c7c", + "target" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "input" : "dc9f124c-35db-4e94-9eab-cf0a537821de" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "19e73c98-bda5-443f-8d84-b01b5fa153b0", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "89074ab3-c473-49ea-9151-1f7d411a1fa3" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "2cd5373c-8f3d-46be-9a51-b1ef9c41e62c", + "target" : "356159aa-26ed-4fb9-9a4d-07407007a0dc", + "input" : "3bfa0676-38ed-4e63-b1f3-15a1d25d769b" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "27160aa5-22d5-40eb-881c-f778ca89189e", + "target" : "6237972b-190b-45bb-8ac5-6cbb95317045", + "input" : "16d88892-c896-4288-964a-9894d547ea27" + }, { + "source" : "0e93320e-eef1-4d31-84fb-2515e7f6fda9", + "output" : "1fc5c384-9224-4806-af93-40ea2f444f9b", + "target" : "85d83a8f-a440-45a9-bb41-aa819f6971e5", + "input" : "3e154e0d-1b8d-42ec-93fa-1f3df7dc1317" + }, { + "source" : "783b395e-13db-40b9-b3df-47bc933a3aa1", + "output" : "ed81a8d8-42af-4d1c-ba4a-d59a7563b0f3", + "target" : "23f0a309-d793-4b6c-871c-483486428971", + "input" : "59410051-cf52-4d79-8ce4-5c6a6de4bbb1" + }, { + "source" : "cd51d621-4989-4ce5-afd9-038c035b64ba", + "output" : "b938f4e6-d3d0-49a2-a808-3935e5cf0e70", + "target" : "993a2aeb-4334-4b80-9ca0-29f1c1d22051", + "input" : "b29edafa-8aba-4815-b671-57983057d591" + }, { + "source" : "96f79610-adc4-49a4-8727-9133b99b54bf", + "output" : "23738ccf-101e-4ca4-b6f3-5ae8f800d00f", + "target" : "c422c632-93db-479b-9185-d494be3b836b", + "input" : "d4d98ea4-d68c-484a-adee-be71a49282d7" + }, { + "source" : "bfa607cd-accb-4d20-bfcc-f3de47a91d59", + "output" : "a4f0041a-9672-44c2-b5e1-7f3f5d5ac013", + "target" : "fdff1cbf-fa40-43af-a036-98a49caddde9", + "input" : "8888652c-cdef-46b5-b2c0-0e1cf06ec950" + }, { + "source" : "fdff1cbf-fa40-43af-a036-98a49caddde9", + "output" : "c2c2a8a0-81d5-431d-aea7-3c4105c2a03d", + "target" : "59b94c21-6c41-4ead-996d-b63a98137535", + "input" : "300150d0-1d28-464e-b6e2-5a94e2b4a11c" + }, { + "source" : "356159aa-26ed-4fb9-9a4d-07407007a0dc", + "output" : "eb6814e5-b299-40f4-b0bd-7f3e9868964d", + "target" : "6ab23909-9b8f-46f9-8fff-4d7c7923c0f6", + "input" : "0fc7f8f7-2f8e-4017-8941-e971cbbb1681" + }, { + "source" : "e2f129a4-31a4-4401-a018-3bb591d0c7c2", + "output" : "60b44531-2059-4a7b-ac7d-8343a1cc8aa4", + "target" : "2fafd9a2-c992-4a1a-84e3-7367bfdff7cb", + "input" : "bb7e5532-5972-41b8-8826-1c076f4a9351" + }, { + "source" : "46dafcea-298d-47f2-b071-bdb5bb390e9c", + "output" : "8840cdb6-a1cb-4197-a7dc-3767a3715730", + "target" : "541b0cca-7d4e-4368-81b4-bcc09cca893d", + "input" : "4bc7d2ac-44e1-4da7-bf62-a7c4581e6670" + }, { + "source" : "95f86ae1-58f5-4427-94e0-11a7008004a6", + "output" : "b3ee6691-1180-4c57-89aa-ee9cb770fd06", + "target" : "be1fbd21-d6c5-4c72-9dc2-8569dd06be27", + "input" : "e8035ea0-32fb-4bc9-abfe-1a01a5907268" + }, { + "source" : "cf47b93a-2f0e-4004-ae12-31c46217a449", + "output" : "0f34af58-3bf0-482c-96c0-311b38eff259", + "target" : "1c0c576d-5990-479a-9153-95a741ed9974", + "input" : "f69149ea-2f1d-4155-b2f3-6ddc62688a60" + }, { + "source" : "85c7f63c-605a-4091-8924-e1b93b15043b", + "output" : "b6b70c4e-8787-4e5b-be03-5ee401b01a19", + "target" : "783b395e-13db-40b9-b3df-47bc933a3aa1", + "input" : "eaffcf73-2392-47a7-a240-890c55c91473" + }, { + "source" : "2fafd9a2-c992-4a1a-84e3-7367bfdff7cb", + "output" : "e94143c0-9ddf-4011-8875-5fb9273aec88", + "target" : "59cff53d-a2f4-467f-bf6b-0ff3afe0518b", + "input" : "cfaf2a25-dd31-4d1b-ad67-37a819079e6d" + }, { + "source" : "c9fbb1cb-9fa1-4dba-942c-611ce219bdb6", + "output" : "02675804-2a3f-4caf-a0e2-d9060fa1ab42", + "target" : "15d0bff5-e2ad-46e7-875f-f22bdd9e3b51", + "input" : "7a9f9695-54e8-41cb-9f27-cb5b9c984c75" + }, { + "source" : "541b0cca-7d4e-4368-81b4-bcc09cca893d", + "output" : "700e98a4-156a-4884-89b5-4074da93647f", + "target" : "a8816b37-0dd8-45aa-bb19-4a13fe74ee31", + "input" : "46974d86-e51e-406a-bcde-3c5dd45b9df4" + }, { + "source" : "ef9fa21e-1350-4956-a82a-304b03e6cdf4", + "output" : "e0eeb0a3-a3ce-40b3-be37-94fec6a586c8", + "target" : "c19fa814-5c75-4125-a806-4f001b7ef00c", + "input" : "fce55bb5-eef6-4063-a880-95e76d04fba0" + }, { + "source" : "a64107b8-ae3d-4e81-8ed4-01fde3ceae7c", + "output" : "1e3400d0-d3bb-4c2c-b596-98f334276f5a", + "target" : "6c7d11a2-ff6b-411c-a7c4-5853d6471740", + "input" : "91c34b43-f459-4147-950e-c806bb4fc012" + } ], + "bendpoints" : "[{\"source\":\"a5286554-f730-4229-aa5f-62b1b51537a8\",\"target\":\"edf5cb5c-763e-47b6-8c4e-ed9caad67051\",\"coordinates\":\"480:404,540:404\"},{\"source\":\"f9af54bb-8bbc-4dfa-8ca6-9b93381c4376\",\"target\":\"fdb39adf-3696-4e67-9e75-b0a79d7b3953\",\"coordinates\":\"472:840,680:840,680:780,1361:780\"},{\"source\":\"85c7f63c-605a-4091-8924-e1b93b15043b\",\"target\":\"783b395e-13db-40b9-b3df-47bc933a3aa1\",\"coordinates\":\"1215:465,1215:413,725:413,725:360\"},{\"source\":\"0e93320e-eef1-4d31-84fb-2515e7f6fda9\",\"target\":\"6237972b-190b-45bb-8ac5-6cbb95317045\",\"coordinates\":\"360:58,973:58,973:249,1241:249\"},{\"source\":\"15d0bff5-e2ad-46e7-875f-f22bdd9e3b51\",\"target\":\"955adf0b-210c-4210-a984-04d66ab792ec\",\"coordinates\":\"1613:479,1613:360\"},{\"source\":\"59cff53d-a2f4-467f-bf6b-0ff3afe0518b\",\"target\":\"59b94c21-6c41-4ead-996d-b63a98137535\",\"coordinates\":\"1242:421,1498:421,1498:552,1745:552,1745:249,1745:-32,1649:-32,960:-32,960:248,722:248,705:221,655:221,640:248,600:248\"},{\"source\":\"6237972b-190b-45bb-8ac5-6cbb95317045\",\"target\":\"e349ce89-8a54-4872-991c-4620d62163b8\",\"coordinates\":\"1297:180\"},{\"source\":\"8609525a-c3d9-4b70-97cc-e8889652b357\",\"target\":\"a64107b8-ae3d-4e81-8ed4-01fde3ceae7c\",\"coordinates\":\"1668:180\"},{\"source\":\"4e0887ce-8b93-4de5-b4af-5aa3ad095d6c\",\"target\":\"c422c632-93db-479b-9185-d494be3b836b\",\"coordinates\":\"280:340,280:660\"},{\"source\":\"f9af54bb-8bbc-4dfa-8ca6-9b93381c4376\",\"target\":\"8b87e3bc-05e4-4933-998a-60d71cf0c423\",\"coordinates\":\"472:840,680:840,680:780,1340:780\"},{\"source\":\"bfa607cd-accb-4d20-bfcc-f3de47a91d59\",\"target\":\"fdff1cbf-fa40-43af-a036-98a49caddde9\",\"coordinates\":\"1745:479,1745:249,1745:-32,1649:-32,960:-32,960:248\"},{\"source\":\"492e4c3a-c719-44af-b20a-9e1b9ff89bfe\",\"target\":\"c9104e19-a903-48f7-819a-6268462a5b26\",\"coordinates\":\"680:769\"},{\"source\":\"a5286554-f730-4229-aa5f-62b1b51537a8\",\"target\":\"9e1e145e-2348-49ae-88d5-94ffbf0bbcc4\",\"coordinates\":\"480:404,419:404\"},{\"source\":\"edf5cb5c-763e-47b6-8c4e-ed9caad67051\",\"target\":\"2fafd9a2-c992-4a1a-84e3-7367bfdff7cb\",\"coordinates\":\"680:466,680:303,1163:303\"},{\"source\":\"59cff53d-a2f4-467f-bf6b-0ff3afe0518b\",\"target\":\"e349ce89-8a54-4872-991c-4620d62163b8\",\"coordinates\":\"1297:361\"},{\"source\":\"4e0887ce-8b93-4de5-b4af-5aa3ad095d6c\",\"target\":\"8addc91f-83b8-4964-b588-72d53784d5ff\",\"coordinates\":\"280:340,280:185\"},{\"source\":\"e349ce89-8a54-4872-991c-4620d62163b8\",\"target\":\"e090fc9b-501e-4c4c-9cf1-b2f871649bef\",\"coordinates\":\"1354:249\"},{\"source\":\"0e93320e-eef1-4d31-84fb-2515e7f6fda9\",\"target\":\"356159aa-26ed-4fb9-9a4d-07407007a0dc\",\"coordinates\":\"440:152\"},{\"source\":\"4e0887ce-8b93-4de5-b4af-5aa3ad095d6c\",\"target\":\"0e93320e-eef1-4d31-84fb-2515e7f6fda9\",\"coordinates\":\"280:340,280:151\"},{\"source\":\"4ddb93ef-f271-4b8d-8c34-8ce11a6e6fbb\",\"target\":\"a8816b37-0dd8-45aa-bb19-4a13fe74ee31\",\"coordinates\":\"1410:180,1410:121,1053:121\"},{\"source\":\"f9af54bb-8bbc-4dfa-8ca6-9b93381c4376\",\"target\":\"28defe30-f45f-4a6c-9c4d-117e96fede0b\",\"coordinates\":\"472:840\"},{\"source\":\"1c0c576d-5990-479a-9153-95a741ed9974\",\"target\":\"c9104e19-a903-48f7-819a-6268462a5b26\",\"coordinates\":\"1031:662,1031:560\"},{\"source\":\"0e93320e-eef1-4d31-84fb-2515e7f6fda9\",\"target\":\"994fa6fe-5dc2-4b48-8503-019e8a4c4879\",\"coordinates\":\"360:58,277:58,277:86,120:86,120:440\"},{\"source\":\"a5286554-f730-4229-aa5f-62b1b51537a8\",\"target\":\"59cff53d-a2f4-467f-bf6b-0ff3afe0518b\",\"coordinates\":\"480:404,680:404,680:303,1187:303\"},{\"source\":\"e090fc9b-501e-4c4c-9cf1-b2f871649bef\",\"target\":\"15d0bff5-e2ad-46e7-875f-f22bdd9e3b51\",\"coordinates\":\"1355:421,1557:421\"},{\"source\":\"fdff1cbf-fa40-43af-a036-98a49caddde9\",\"target\":\"59b94c21-6c41-4ead-996d-b63a98137535\",\"coordinates\":\"649:248,600:248\"},{\"source\":\"96f79610-adc4-49a4-8727-9133b99b54bf\",\"target\":\"c422c632-93db-479b-9185-d494be3b836b\",\"coordinates\":\"1521:915,688:915,688:874,280:874,280:660\"},{\"source\":\"492e4c3a-c719-44af-b20a-9e1b9ff89bfe\",\"target\":\"947b6847-a819-4c53-b4a2-14189fa2cfac\",\"coordinates\":\"680:769,680:660\"},{\"source\":\"fdb39adf-3696-4e67-9e75-b0a79d7b3953\",\"target\":\"c422c632-93db-479b-9185-d494be3b836b\",\"coordinates\":\"1420:915,688:915,688:874,280:874,280:660\"},{\"source\":\"9e1e145e-2348-49ae-88d5-94ffbf0bbcc4\",\"target\":\"4f49aa16-b47e-4279-8e79-d3d613c398cc\",\"coordinates\":\"360:466,360:560\"},{\"source\":\"356159aa-26ed-4fb9-9a4d-07407007a0dc\",\"target\":\"6ab23909-9b8f-46f9-8fff-4d7c7923c0f6\",\"coordinates\":\"360:232\"},{\"source\":\"a5286554-f730-4229-aa5f-62b1b51537a8\",\"target\":\"4f49aa16-b47e-4279-8e79-d3d613c398cc\",\"coordinates\":\"480:404,360:404,360:560\"},{\"source\":\"c9104e19-a903-48f7-819a-6268462a5b26\",\"target\":\"ec469b30-8b67-4d57-a378-eda0e631d664\",\"coordinates\":\"600:560\"},{\"source\":\"0e93320e-eef1-4d31-84fb-2515e7f6fda9\",\"target\":\"85d83a8f-a440-45a9-bb41-aa819f6971e5\",\"coordinates\":\"360:58,277:58,277:86,120:86,120:540\"},{\"source\":\"e090fc9b-501e-4c4c-9cf1-b2f871649bef\",\"target\":\"fdff1cbf-fa40-43af-a036-98a49caddde9\",\"coordinates\":\"1355:421,1498:421,1498:552,1745:552,1745:249,1745:-32,1649:-32,960:-32,960:248,719:248\"},{\"source\":\"df71fc65-60d1-4dcb-9bfc-67424c6db107\",\"target\":\"356159aa-26ed-4fb9-9a4d-07407007a0dc\",\"coordinates\":\"519:232\"}]", + "labels" : "[{\"identifier\":\"01988357-448b-4bff-9401-a71729a6fdb0\",\"headerText\":\"optimization\",\"text\":\"\",\"location\":\"141:106\",\"size\":\"121:134\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"LEFT\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"11\"},{\"identifier\":\"19687a62-da2e-491f-99f7-1b662b984f81\",\"headerText\":\"tool execution for design sizing\",\"text\":\"\",\"location\":\"701:260\",\"size\":\"1032:279\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"LEFT\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"2\"},{\"identifier\":\"35384d42-095c-408c-9fdb-ade3fe904bb6\",\"headerText\":\"clean up\",\"text\":\"\",\"location\":\"141:581\",\"size\":\"121:144\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"LEFT\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"8\"},{\"identifier\":\"38f6e4ce-9ea0-4401-82c3-dc4725ca2a76\",\"headerText\":\"vizualization and cpacs\",\"text\":\"\",\"location\":\"624:73\",\"size\":\"323:135\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"LEFT\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"7\"},{\"identifier\":\"6cfe17e1-fd4d-4290-8c36-8ae72bcabbe4\",\"headerText\":\"post operations\",\"text\":\"\",\"location\":\"701:742\",\"size\":\"883:159\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"CENTER\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"5\"},{\"identifier\":\"7a4094ae-38b5-44b8-b126-fcaf4158324a\",\"headerText\":\"moe calibration\",\"text\":\"\",\"location\":\"987:-19\",\"size\":\"746:260\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"CENTER\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"9\"},{\"identifier\":\"7f8b053d-b859-427f-9e4c-5a24f06ee342\",\"headerText\":\"pre-condition\",\"text\":\"\",\"location\":\"300:74\",\"size\":\"121:134\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"LEFT\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"3\"},{\"identifier\":\"94670bfc-02d5-419c-9840-2b9402e805ec\",\"headerText\":\"tool execution for mission study analysis\",\"text\":\"\",\"location\":\"701:581\",\"size\":\"318:140\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"CENTER\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"6\"},{\"identifier\":\"9634075c-8015-4264-afe8-e88965dbeef2\",\"headerText\":\"pre-sizing\",\"text\":\"\",\"location\":\"460:73\",\"size\":\"122:135\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"LEFT\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"0\"},{\"identifier\":\"bdf074ec-a314-47fc-885c-f85b35e92951\",\"headerText\":\"mission study loop\",\"text\":\"\",\"location\":\"300:581\",\"size\":\"361:280\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"LEFT\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"4\"},{\"identifier\":\"e3b9cd44-4f34-45e5-bdee-ef1901fd76bb\",\"headerText\":\"design sizing loop\",\"text\":\"\",\"location\":\"298:261\",\"size\":\"361:278\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"LEFT\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"1\"},{\"identifier\":\"ec6cab4d-84d7-45d8-9fe7-eb8b55b12984\",\"headerText\":\"parameter study\",\"text\":\"\",\"location\":\"140:261\",\"size\":\"122:246\",\"alpha\":\"151\",\"colorHeader\":\"0:0:0\",\"colorText\":\"0:0:0\",\"colorBackground\":\"192:192:192\",\"labelPosition\":\"TOPLEFT\",\"textAlignmentType\":\"LEFT\",\"headerAlignmentType\":\"LEFT\",\"border\":\"false\",\"headerSize\":\"10\",\"textSize\":\"9\",\"zIndex\":\"10\"}]" +} \ No newline at end of file diff --git a/UNICADOworkflow/optimization_conf.xml b/UNICADOworkflow/optimization_conf.xml new file mode 100644 index 0000000000000000000000000000000000000000..6efd8d188af05df303ac9bba83bf2cd82ec31aae --- /dev/null +++ b/UNICADOworkflow/optimization_conf.xml @@ -0,0 +1,69 @@ +<ConfigFile Name="optimization_conf.xml"> + <ProgramSpecific Desc="programmspezifische Steuereinstellungen"> + <StartEveryRunWithRefFile Desc="0: execution with files from last loop; 1: Reset project files to pre-execution status - Design mode will be selected from workflow configuration file" Default="1">1</StartEveryRunWithRefFile> + <ResetVariablesAfterRun Desc="1: Nach Studie/Optimierung werden Parameter in Dateien auf Anfangswerte gesetzt" Default="1">1</ResetVariablesAfterRun> + </ProgramSpecific> + <ProgramSettings Desc="Programmeinstellungen"> + <SensitivityStudySettings Desc="Einstellungen fuer Sensitivitaetsstudien"> + <SaveResults OnlyAiXFile="0" Desc="1: Projektordner fuer jeden Run abspeichern, 0: nur Endresultate" Default="1">1</SaveResults> + <PathToCurrentWorkingDir Desc="Attention: Do not enter here, the path is set automatically!" Default="">../</PathToCurrentWorkingDir> + </SensitivityStudySettings> + <OptimizationSettings Desc="Input parameter ton configure the optimization framework"> + <numberOfInitialSamples Desc="Number of initial optimization runs" Default="30">30</numberOfInitialSamples> + <numberOfImposedSamples Desc="Additional sample size searched in the process of Bayesian optimization" Default="10">0</numberOfImposedSamples> + <numberOfProcessors Desc="Number of processors allocated for one simulation when run in parallel" Default="1">1</numberOfProcessors> + <regularization Desc="0: The surrogate model passes through all the sample points. 1: No guarantee that the surrogate model passes through all the sample points." Default="0">0</regularization> + <doeMethod Desc="LHS or Halton or Sobol" Default="Sobol">Sobol</doeMethod> + <method Desc="EI or EIPI or some others" Default="EI">EI</method> + <multiStart Desc="between 1 and 10 -> greater: higher accuracy but lower efficiency" Default="1">5</multiStart> + <gradientOptSurrogate Desc="method to optimize the likelihood function in constructing surrogate models, 1: BFGS" Default="0">0</gradientOptSurrogate> + </OptimizationSettings> + <designParameter> + <designVariables Desc="Number of design variables to be optimised.">2</designVariables> + <designVariable ID="0"> + <ParameterName Desc="Name of design Parameter">WingLoading</ParameterName> + <PathToFile Desc="Input Directory, Attention: Do not enter here, the path is set automatically!">../</PathToFile> + <FileName Desc="Input Filename">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/sizing_point/wing_loading/value</PathInXmlFile> + <lowerBoundary Desc="lower boundary of input parameter" Unit="kg/m^2">600.0</lowerBoundary> + <upperBoundary Desc="upper boundary of input parameter" Unit="kg/m^2">660.0</upperBoundary> + </designVariable> + <designVariable ID="1"> + <ParameterName Desc="Name des Parameters">ThrustToWeight</ParameterName> + <PathToFile Desc="Input Directory, Attention: Do not enter here, the path is set automatically!">../</PathToFile> + <FileName Desc="Input Filename">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/sizing_point/thrust_to_weight/value</PathInXmlFile> + <lowerBoundary Desc="lower boundary of input parameter" Unit="-">0.28</lowerBoundary> + <upperBoundary Desc="upper boundary of input parameter" Unit="-">0.35</upperBoundary> + </designVariable> + </designParameter> + <costFunctions> + <costFunctionsParameters Desc="Anzahl der Input-/freien Parameter">1</costFunctionsParameters> + <costFunctionsParameter ID="0"> + <ParameterName Desc="Name des Parameters">Consumed Mission Energy</ParameterName> + <PathToFile Desc="Input Directory, Attention: Do not enter here, the path is set automatically!">../</PathToFile> + <FileName Desc="Input Filename">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/analysis/mission/design_mission/loaded_mission_energy/mission_energy/consumed_energy/value</PathInXmlFile> + </costFunctionsParameter> + </costFunctions> + <designRequirementParameter> + <designRequirements Desc="Anzahl der Outputparameter, die mitgetrackt werden">2</designRequirements> + <designRequirement ID="0"> + <ParameterName Desc="Name des Parameters">TOFL_Design</ParameterName> + <PathToFile Desc="Input Directory, Attention: Do not enter here, the path is set automatically!">../</PathToFile> + <FileName Desc="Input Filename">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/assessment/performance/takeoff/takeoff_distance_normal_safety/value</PathInXmlFile> + <lowerBoundary Desc="lower boundary of input parameter" Unit="m">0</lowerBoundary> + <upperBoundary Desc="upper boundary of input parameter" Unit="m">2200.0</upperBoundary> + </designRequirement> + <designRequirement ID="1"> + <ParameterName Desc="Name des Parameters">LDN_Design</ParameterName> + <PathToFile Desc="Input Directory, Attention: Do not enter here, the path is set automatically!">../</PathToFile> + <FileName Desc="Input Filename">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/assessment/performance/landing/needed_runway_length/value</PathInXmlFile> + <lowerBoundary Desc="lower boundary of input parameter" Unit="m">0</lowerBoundary> + <upperBoundary Desc="upper boundary of input parameter" Unit="m">1850.0</upperBoundary> + </designRequirement> + </designRequirementParameter> + </ProgramSettings> +</ConfigFile> \ No newline at end of file diff --git a/UNICADOworkflow/parameter_study_conf.xml b/UNICADOworkflow/parameter_study_conf.xml new file mode 100644 index 0000000000000000000000000000000000000000..cd6e843234205c43878444a2c951acff96e6ea61 --- /dev/null +++ b/UNICADOworkflow/parameter_study_conf.xml @@ -0,0 +1,136 @@ +<ConfigFile Name="parameter_study_conf.xml"> + <ProgramSpecific Desc="programmspezifische Steuereinstellungen"> + <ExitIfSubProgramExits Desc="1: bricht ab, wenn Unterprogramm abbricht, 0: schreibt ungültigen Run in Output und fährt fort" Default="0">0</ExitIfSubProgramExits> + <StartEveryRunWithRefFile Desc="0: execution with files from last loop; 1: Reset project files to pre-execution status - Design mode will be selected from workflow configuration file" Default="1">1</StartEveryRunWithRefFile> + <ResetVariablesAfterRun Desc="1: Nach Studie/Optimierung werden Parameter in Dateien auf Anfangswerte gesetzt" Default="1">1</ResetVariablesAfterRun> + <WriteFailedReqChecksResults Desc="1: Schreibe Ergebnis, 0: Schreibe NAN (bei Run mit exitValue=666 (Requirements Check Failed)" Default="1">1</WriteFailedReqChecksResults> + </ProgramSpecific> + <ProgramSettings Desc="Programmeinstellungen"> + <Mode Desc="Modi: 1: Parametric Study, 2: Full Parametric Study (Attention: this mode is temporary not implemented)" Default="1">1</Mode> + <SensitivityStudySettings Desc="Einstellungen fuer Sensitivitaetsstudien"> + <PathToInputParameterValuesFile Desc="Datei mit Werten fuer Inputparameter (falls Schalter an)">parameter_study_values.csv</PathToInputParameterValuesFile> + <SaveResults OnlyAiXFile="0" Desc="1: Projektordner fuer jeden Run abspeichern, 0: nur Endresultate" Default="1">1</SaveResults> + <MaxFolderSize Desc="Maximaler Speicherplatz für die Berechnung" Unit="GB" Default="10">10</MaxFolderSize> + <ReproduceOutputFileFromOldStudy Desc="Resume an abborted paramter study" Default="0">0</ReproduceOutputFileFromOldStudy> + <PathToCurrentStudy Desc="Attention: Do not enter here, the path is set automatically!" Default="../">../</PathToCurrentStudy> + <PathToFolderOldStudy Desc="Path to parameter study folder which should be resumed" Default="../">../</PathToFolderOldStudy> + </SensitivityStudySettings> + <ParameterSettings Desc="Eingabe der Parameter (Attribute koennen im PathInXmlFile per basepath/@attributeName angesprochen werden)"> + <InputParameters Desc="Anzahl der Input-/freien Parameter">1</InputParameters> + <InputParameter ID="1"> + <ParameterName Desc="Name des Parameters">fuselage mass factor</ParameterName> + <RelDirectory UseIODir="1" Desc="Input Directory">../fuselage_design/</RelDirectory> + <FileName UseIOFile="1" Desc="Input Filename">fuselage_design_conf.xml</FileName> + <PathInXmlFile>/module_configuration_file/program_settings/configuration/fidelity/fuselage_design_tu_berlin/general/mass_technology_factors/fuselage_structural_mass_technology_factor/value</PathInXmlFile> + <ParametricStudy Desc="Einstellungen fuer Parameterstudie (Mode 1 und 2, s.o.)"> + <step_type description="Selector: mode_0 (Use values as absolute values) / mode_1 (Use values as delta values to reference) / mode_2 (Use values as relative step size (e.g. 0.15 as 15 percent))">mode_0</step_type> + <input_selector description="Selector: mode_0 (Use config settings) / mode_1 (Read values from text file)">mode_0</input_selector> + <input_selector_specific_settings> + <mode_0> + <StepSize description="Step size according to step_type (mode_0 = mode_1 = delta value = reference_value +/- step_size*stepsUp/Down / mode_2 = new_value = reference_value * (1. +/- step_size))">0.05</StepSize> + <NumberOfStepsUp description="Number of steps up" Default="3">3</NumberOfStepsUp> + <NumberOfStepsDown description="Number of steps down" Default="3">3</NumberOfStepsDown> + </mode_0> + </input_selector_specific_settings> + </ParametricStudy> + </InputParameter> + <OutputParameters Desc="Anzahl der Outputparameter, die mitgetrackt werden">16</OutputParameters> + <OutputParameter ID="1"> + <ParameterName Desc="Name des Parameters">wing_loading</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>./sizing_point/wing_loading/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="2"> + <ParameterName Desc="Name des Parameters">thrust_to_weight</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>./sizing_point/thrust_to_weight/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="3"> + <ParameterName Desc="Name des Parameters">mtom</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>./analysis/masses_cg_inertia/maximum_takeoff_mass/mass_properties/mass/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="4"> + <ParameterName Desc="Name des Parameters">ome</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>./analysis/masses_cg_inertia/operating_mass_empty/mass_properties/mass/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="5"> + <ParameterName Desc="Name des Parameters">mfm</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/analysis/masses_cg_inertia/maximum_fuel_mass/mass_properties/mass/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="6"> + <ParameterName Desc="Name des Parameters">design_fuel_mass</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/analysis/masses_cg_inertia/design_fuel_mass/mass_properties/mass/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="7"> + <ParameterName Desc="Name des Parameters">wing mass</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/component_design/wing/mass_properties/mass/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="8"> + <ParameterName Desc="Name des Parameters">fuselage mass</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/component_design/fuselage/mass_properties/mass/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="9"> + <ParameterName Desc="Name des Parameters">empennage mass</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/component_design/empennage/mass_properties/mass/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="10"> + <ParameterName Desc="Name des Parameters">landing gear mass</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/component_design/landing_gear/mass_properties/mass/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="11"> + <ParameterName Desc="Name des Parameters">propulsion mass</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/component_design/propulsion/mass_properties/mass/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="12"> + <ParameterName Desc="Name des Parameters">systems mass</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/component_design/systems/mass_properties/mass/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="13"> + <ParameterName Desc="Name des Parameters">reference area</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/analysis/aerodynamics/reference_values/S_ref/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="14"> + <ParameterName Desc="Name des Parameters">reference span</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/analysis/aerodynamics/reference_values/b/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="15"> + <ParameterName Desc="Name des Parameters">take-off distance</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/assessment/performance/takeoff/takeoff_distance_normal_safety/value</PathInXmlFile> + </OutputParameter> + <OutputParameter ID="16"> + <ParameterName Desc="Name des Parameters">landing distance</ParameterName> + <RelDirectory UseIODir="0" Desc="">../projects/CSMR/CSMR-2020/</RelDirectory> + <FileName UseIOFile="0" Desc="">CSMR-2020.xml</FileName> + <PathInXmlFile>/aircraft_exchange_file/assessment/performance/landing/needed_runway_length/value</PathInXmlFile> + </OutputParameter> + </ParameterSettings> + </ProgramSettings> +</ConfigFile> \ No newline at end of file diff --git a/UNICADOworkflow/parameter_study_values.csv b/UNICADOworkflow/parameter_study_values.csv new file mode 100644 index 0000000000000000000000000000000000000000..eca223e8facd50d0bcb769171da15b6a7777ee08 --- /dev/null +++ b/UNICADOworkflow/parameter_study_values.csv @@ -0,0 +1,3 @@ +wing scaling factor;0.25;0.125;-0.125;-0.25; +fuselage scaling factor;0.25;0.125;-0.125;-0.25; +center wing factor;1.03;0.93;0.73;0.63; diff --git a/UNICADOworkflow/range_type_specific_factors.xml b/UNICADOworkflow/range_type_specific_factors.xml new file mode 100644 index 0000000000000000000000000000000000000000..021f3240154f1c28bff688fcc65b05186293de2b --- /dev/null +++ b/UNICADOworkflow/range_type_specific_factors.xml @@ -0,0 +1,497 @@ +<configuration> + <initial_sizing> + <number_of_factors>9</number_of_factors> + <factor ID="1"> + <path>/module_configuration_file/program_settings/General/Cf</path> + <value> + <short-range>0.002</short-range> + <medium-range>0.0025</medium-range> + <long-range>0.003</long-range> + </value> + </factor> + <factor ID="2"> + <path>/module_configuration_file/program_settings/General/FamilyThrustScaling</path> + <value> + <short-range>1.010</short-range> + <medium-range>1.000</medium-range> + <long-range>1.000</long-range> + </value> + </factor> + <factor ID="3"> + <path>/module_configuration_file/program_settings/Climb/deltaCD0_app_flaps</path> + <value> + <short-range>0.03</short-range> + <medium-range>0.04</medium-range> + <long-range>0.05</long-range> + </value> + </factor> + <factor ID="4"> + <path>/module_configuration_file/program_settings/Climb/MaxcontMaxto</path> + <value> + <short-range>0.8967</short-range> + <medium-range>0.92</medium-range> + <long-range>0.94</long-range> + </value> + </factor> + <factor ID="5"> + <path>/module_configuration_file/program_settings/Cruise/McrMto</path> + <value> + <short-range>0.956</short-range> + <medium-range>0.956</medium-range> + <long-range>0.924</long-range> + </value> + </factor> + <factor ID="6"> + <path>/module_configuration_file/program_settings/Cruise/maxInitialCruiseCL</path> + <value> + <short-range>0.5516</short-range> + <medium-range>0.55</medium-range> + <long-range>0.5</long-range> + </value> + </factor> + <factor ID="7"> + <path>/module_configuration_file/program_settings/Masses/Fractions/mf_to</path> + <value> + <short-range>0.99</short-range> + <medium-range>0.98</medium-range> + <long-range>0.97</long-range> + </value> + </factor> + <factor ID="8"> + <path>/module_configuration_file/program_settings/Masses/Fractions/mf_descent</path> + <value> + <short-range>0.995</short-range> + <medium-range>0.9925</medium-range> + <long-range>0.99</long-range> + </value> + </factor> + <factor ID="9"> + <path>/module_configuration_file/program_settings/Masses/Fractions/mf_land</path> + <value> + <short-range>0.997</short-range> + <medium-range>0.9945</medium-range> + <long-range>0.992</long-range> + </value> + </factor> + </initial_sizing> + <fuselage_design> + <number_of_factors>35</number_of_factors> + <factor ID="1"> + <path>/module_configuration_file/program_settings/PassengerClass/Class@ID=1/aisle/width</path> + <value> + <short-range>0.6858</short-range> + <medium-range>0.97</medium-range> + <long-range>0.97</long-range> + </value> + </factor> + <factor ID="2"> + <path>/module_configuration_file/program_settings/PassengerClass/Class@ID=2/aisle/width</path> + <value> + <short-range>0.635</short-range> + <medium-range>0.635</medium-range> + <long-range>0.7</long-range> + </value> + </factor> + <factor ID="3"> + <path>/module_configuration_file/program_settings/PassengerClass/Class@ID=2/aisle/height</path> + <value> + <short-range>2.13</short-range> + <medium-range>2.11</medium-range> + <long-range>2.13</long-range> + </value> + </factor> + <factor ID="4"> + <path>/module_configuration_file/program_settings/PassengerClass/Class@ID=3/aisle/width</path> + <value> + <short-range>0.4826</short-range> + <medium-range>0.5334</medium-range> + <long-range>0.5334</long-range> + </value> + </factor> + <factor ID="5"> + <path>/module_configuration_file/program_settings/PassengerClass/Class@ID=3/aisle/height</path> + <value> + <short-range>2.13</short-range> + <medium-range>2.1</medium-range> + <long-range>2.13</long-range> + </value> + </factor> + <factor ID="6"> + <path>/module_configuration_file/program_settings/PassengerClass/Class@ID=3/PAXperSteward</path> + <value> + <short-range>50</short-range> + <medium-range>50</medium-range> + <long-range>40</long-range> + </value> + </factor> + <factor ID="7"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=1/pitch</path> + <value> + <short-range>0.8128</short-range> + <medium-range>0.86</medium-range> + <long-range>0.8128</long-range> + </value> + </factor> + <factor ID="8"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=1/depth</path> + <value> + <short-range>0.75</short-range> + <medium-range>0.6731</medium-range> + <long-range>0.6731</long-range> + </value> + </factor> + <factor ID="9"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=1/width</path> + <value> + <short-range>0.499533</short-range> + <medium-range>0.508</medium-range> + <long-range>0.527</long-range> + </value> + </factor> + <factor ID="10"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=1/heightSeat</path> + <value> + <short-range>0.95</short-range> + <medium-range>0.94</medium-range> + <long-range>0.94</long-range> + </value> + </factor> + <factor ID="11"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=1/heightHead</path> + <value> + <short-range>1.1481</short-range> + <medium-range>1.6</medium-range> + <long-range>1.45</long-range> + </value> + </factor> + <factor ID="12"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=2/pitch</path> + <value> + <short-range>0.915</short-range> + <medium-range>0.97</medium-range> + <long-range>1.524</long-range> + </value> + </factor> + <factor ID="13"> + <path>/module_configuration_file/program_settings/Seats/seat/depth</path> + <value> + <short-range>0.84</short-range> + <medium-range>0.84</medium-range> + <long-range>0.84</long-range> + </value> + </factor> + <factor ID="14"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=2/width</path> + <value> + <short-range>0.7239</short-range> + <medium-range>0.7239</medium-range> + <long-range>0.7239</long-range> + </value> + </factor> + <factor ID="15"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=2/heightSeat</path> + <value> + <short-range>0.94</short-range> + <medium-range>0.94</medium-range> + <long-range>0.94</long-range> + </value> + </factor> + <factor ID="16"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=2/heightHead</path> + <value> + <short-range>1.1481</short-range> + <medium-range>1.1481</medium-range> + <long-range>1.1481</long-range> + </value> + </factor> + <factor ID="17"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=3/pitch</path> + <value> + <short-range>2.</short-range> + <medium-range>2.</medium-range> + <long-range>1.5</long-range> + </value> + </factor> + <factor ID="18"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=3/depth</path> + <value> + <short-range>0.7747</short-range> + <medium-range>0.7747</medium-range> + <long-range>0.7747</long-range> + </value> + </factor> + <factor ID="19"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=3/width</path> + <value> + <short-range>0.7239</short-range> + <medium-range>0.7239</medium-range> + <long-range>0.67</long-range> + </value> + </factor> + <factor ID="20"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=3/heightSeat</path> + <value> + <short-range>0.94</short-range> + <medium-range>0.94</medium-range> + <long-range>0.94</long-range> + </value> + </factor> + <factor ID="21"> + <path>/module_configuration_file/program_settings/Seats/seat@ID=3/heightHead</path> + <value> + <short-range>1.1481</short-range> + <medium-range>1.1481</medium-range> + <long-range>1.1481</long-range> + </value> + </factor> + <factor ID="22"> + <path>/module_configuration_file/program_settings/Exits/NumberOfExitTypes</path> + <value> + <short-range>7</short-range> + <medium-range>2</medium-range> + <long-range>5</long-range> + </value> + </factor> + <factor ID="23"> + <path>/module_configuration_file/program_settings/Exits/ExitType@ID=2</path> + <value> + <short-range>Type B</short-range> + <medium-range>Type III</medium-range> + <long-range>Type I</long-range> + </value> + </factor> + <factor ID="24"> + <path>/module_configuration_file/program_settings/Exits/ExitType@ID=3</path> + <value> + <short-range>Type C</short-range> + <medium-range>0</medium-range> + <long-range>Type II</long-range> + </value> + </factor> + <factor ID="25"> + <path>/module_configuration_file/program_settings/Exits/ExitType@ID=4</path> + <value> + <short-range>Type I</short-range> + <medium-range>0</medium-range> + <long-range>Type III</long-range> + </value> + </factor> + <factor ID="26"> + <path>/module_configuration_file/program_settings/Exits/ExitType@ID=5</path> + <value> + <short-range>Type II</short-range> + <medium-range>0</medium-range> + <long-range>Type IV</long-range> + </value> + </factor> + <factor ID="27"> + <path>/module_configuration_file/program_settings/Exits/ExitType@ID=6</path> + <value> + <short-range>Type III</short-range> + <medium-range>0</medium-range> + <long-range>0</long-range> + </value> + </factor> + <factor ID="28"> + <path>/module_configuration_file/program_settings/Exits/ExitType@ID=7</path> + <value> + <short-range>Type IV</short-range> + <medium-range>0</medium-range> + <long-range>0</long-range> + </value> + </factor> + <factor ID="29"> + <path>/module_configuration_file/program_settings/Exits/Exit@ID=Type A/Height</path> + <value> + <short-range>1.83</short-range> + <medium-range>1.83</medium-range> + <long-range>1.93</long-range> + </value> + </factor> + <factor ID="30"> + <path>/module_configuration_file/program_settings/Miscellaneous/systemHeight</path> + <value> + <short-range>0.125</short-range> + <medium-range>0.3</medium-range> + <long-range>0.3</long-range> + </value> + </factor> + <factor ID="31"> + <path>/module_configuration_file/program_settings/Miscellaneous/wallThickness</path> + <value> + <short-range>0.1575</short-range> + <medium-range>0.155</medium-range> + <long-range>0.1575</long-range> + </value> + </factor> + <factor ID="32"> + <path>/module_configuration_file/program_settings/Miscellaneous/artificialZOffset</path> + <value> + <short-range>0.</short-range> + <medium-range>0.2</medium-range> + <long-range>0.</long-range> + </value> + </factor> + <factor ID="33"> + <path>/module_configuration_file/program_settings/Miscellaneous/Wingbox/relStartPoint</path> + <value> + <short-range>0.25</short-range> + <medium-range>0.34</medium-range> + <long-range>0.36</long-range> + </value> + </factor> + <factor ID="34"> + <path>/module_configuration_file/program_settings/Miscellaneous/dividerThickness</path> + <value> + <short-range>0.25</short-range> + <medium-range>0.1</medium-range> + <long-range>0.1</long-range> + </value> + </factor> + <factor ID="35"> + <path>/module_configuration_file/program_settings/Miscellaneous/lengthFlightDeck</path> + <value> + <short-range>3.75</short-range> + <medium-range>3.26</medium-range> + <long-range>4.5</long-range> + </value> + </factor> + </fuselage_design> + <propulsion_design> + <number_of_factors>1</number_of_factors> + <factor ID="1"> + <path>/module_configuration_file/program_settings/ScalefactorFuelFlow</path> + <value> + <short-range>0.998</short-range> + <medium-range>1.</medium-range> + <long-range>1.</long-range> + </value> + </factor> + </propulsion_design> + <aerodynamic_assessment> + <number_of_factors>1</number_of_factors> + <factor ID="1"> + <path>/module_configuration_file/program_settings/DragModification/DragCtCorrectionCleanPolar/deltaViscDragWing</path> + <value> + <short-range>-4.</short-range> + <medium-range>0.</medium-range> + <long-range>0.</long-range> + </value> + </factor> + </aerodynamic_assessment> + <systems_design> + <number_of_factors>14</number_of_factors> + <factor ID="1"> + <path>/module_configuration_file/program_settings/Scalingfactors/Systems</path> + <value> + <short-range>0.95</short-range> + <medium-range>0.95</medium-range> + <long-range>1.</long-range> + </value> + </factor> + <factor ID="2"> + <path>/module_configuration_file/program_settings/Scalingfactors/Furnishings</path> + <value> + <short-range>1.</short-range> + <medium-range>0.735</medium-range> + <long-range>1.</long-range> + </value> + </factor> + <factor ID="3"> + <path>/module_configuration_file/program_settings/Scalingfactors/OperatorItems</path> + <value> + <short-range>1.4</short-range> + <medium-range>1.5</medium-range> + <long-range>1.</long-range> + </value> + </factor> + <factor ID="4"> + <path>/module_configuration_file/program_settings/SystemsConstants/IceRainProtection/percentageOfOME</path> + <value> + <short-range>0.001</short-range> + <medium-range>0.0009</medium-range> + <long-range>0.001</long-range> + </value> + </factor> + <factor ID="5"> + <path>/module_configuration_file/program_settings/SystemsConstants/FlightControls/CommonInstWfactor</path> + <value> + <short-range>0.25</short-range> + <medium-range>0.5</medium-range> + <long-range>0.25</long-range> + </value> + </factor> + <factor ID="6"> + <path>/module_configuration_file/program_settings/SystemsConstants/HydraulicSystem/specificDuctingMass</path> + <value> + <short-range>2.5</short-range> + <medium-range>2.2</medium-range> + <long-range>2.5</long-range> + </value> + </factor> + <factor ID="7"> + <path>/module_configuration_file/program_settings/SystemsConstants/HydraulicSystem/specificPumpMass</path> + <value> + <short-range>1.25</short-range> + <medium-range>1.15</medium-range> + <long-range>1.25</long-range> + </value> + </factor> + <factor ID="8"> + <path>/module_configuration_file/program_settings/SystemsConstants/HydraulicSystem/HydraulicCircuits/HydraulicCircuit/Components/Pumps/Pump@ID=1/Efficiency</path> + <value> + <short-range>0.85</short-range> + <medium-range>0.4</medium-range> + <long-range>0.85</long-range> + </value> + </factor> + <factor ID="9"> + <path>/module_configuration_file/program_settings/SystemsConstants/APU/installationfactor</path> + <value> + <short-range>1.5</short-range> + <medium-range>1.3</medium-range> + <long-range>1.5</long-range> + </value> + </factor> + <factor ID="10"> + <path>/module_configuration_file/program_settings/SystemsConstants/remainingConsumers/mass/scalingfactor</path> + <value> + <short-range>1.</short-range> + <medium-range>0.62</medium-range> + <long-range>1.</long-range> + </value> + </factor> + <factor ID="11"> + <path>/module_configuration_file/program_settings/SystemsConstants/remainingConsumers/mass/distribution/percentageInstrumentationOfATAXX</path> + <value> + <short-range>0.08</short-range> + <medium-range>0.129</medium-range> + <long-range>0.08</long-range> + </value> + </factor> + <factor ID="12"> + <path>/module_configuration_file/program_settings/SystemsConstants/remainingConsumers/mass/distribution/percentageAutoFlightOfATAXX</path> + <value> + <short-range>0.13</short-range> + <medium-range>0.091</medium-range> + <long-range>0.13</long-range> + </value> + </factor> + <factor ID="13"> + <path>/module_configuration_file/program_settings/SystemsConstants/remainingConsumers/mass/distribution/percentageNavigationOfATAXX</path> + <value> + <short-range>0.53</short-range> + <medium-range>0.47</medium-range> + <long-range>0.53</long-range> + </value> + </factor> + <factor ID="14"> + <path>/module_configuration_file/program_settings/SystemsConstants/remainingConsumers/mass/distribution/percentageCommunicationOfATAXX</path> + <value> + <short-range>0.26</short-range> + <medium-range>0.31</medium-range> + <long-range>0.26</long-range> + </value> + </factor> + </systems_design> +</configuration> \ No newline at end of file diff --git a/UNICADOworkflow/src/calibration/aux_interpolation_handling.py b/UNICADOworkflow/src/calibration/aux_interpolation_handling.py new file mode 100644 index 0000000000000000000000000000000000000000..b3d5c104a8c1a0654d5a46fcc97b091369ae123d --- /dev/null +++ b/UNICADOworkflow/src/calibration/aux_interpolation_handling.py @@ -0,0 +1,189 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def aux_interpolation_handling(calibration_settings, calibration_loop_vector, type_of_calibration, + path_of_working_directory_rce, current_workflow_name='UNICADOworkflow'): + """ aux_interpol_handling handles the auxiliary interpolation from previous run. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input list "calibration_loop_vector" contains all estimated ome or mtom values. + + The input string "type_of_calibration" contains the name of calibration type. + + The input string "path_of_working_directory_rce" contains the system path to rce working directory. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + :param: calibration_settings: input list of lists + :param: calibration_loop_vector: input list + :param: type_of_calibration: input string + :param: path_of_working_directory_rce: input string + :param: current_workflow_name: input string + :return: calibration_settings: output list of lists + """ + + ''' imports for python ''' + from datetime import datetime + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + target_value = ([item for item in calibration_settings if 'calibration_target_OME' in item])[-1][-1] + aux_interpolation_flag = ([item for item in calibration_settings if 'aux_interpolation_flag' in item])[-1][-1] + calibration_value_high = ([item for item in calibration_settings if 'calibration_value_high' in item])[-1][-1] + calibration_factor_high = ([item for item in calibration_settings if 'calibration_factor_high' in item])[-1][-1] + calibration_value_low = ([item for item in calibration_settings if 'calibration_value_low' in item])[-1][-1] + calibration_factor_low = ([item for item in calibration_settings if 'calibration_factor_low' in item])[-1][-1] + calibration_value_flag = ([item for item in calibration_settings if 'calibration_value_flag' in item])[-1][-1] + calibration_factor_flag = ([item for item in calibration_settings if 'calibration_factor_flag' in item])[-1][-1] + + ''' initialize local parameter ''' + log_file_list = [] + + if aux_interpolation_flag == 1: + print(' Update due to auxiliary interpolation in previous run:') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Update due to auxiliary interpolation in previous run:') + + if calibration_loop_vector[-1] < target_value: + calibration_value_flag = calibration_value_high + calibration_factor_flag = calibration_factor_high + output_string = 'high' + else: + calibration_value_flag = calibration_value_low + calibration_factor_flag = calibration_factor_low + output_string = 'low' + + if type_of_calibration == 'OME': + print(' OME (last) = OME(' + output_string + ') = ' + + str(calibration_value_flag) + ' | CalibFactor (last) = CalibFactor(' + output_string + ') = ' + + str(calibration_factor_flag)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'OME (last) = OME(' + output_string + ') = ' + str(calibration_value_flag) + + ' | CalibFactor (last) = CalibFactor(' + output_string + ') = ' + + str(calibration_factor_flag)) + + if type_of_calibration == 'MTOM': + print(' MTOM (last) = MTOM(' + output_string + ') = ' + + str(calibration_value_flag) + ' | CalibFactor (last) = CalibFactor(' + output_string + ') = ' + + str(calibration_factor_flag)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': MTOM (last) = MTOM(' + + output_string + ') = ' + str(calibration_value_flag) + + ' | CalibFactor (last) = CalibFactor(' + output_string + ') = ' + + str(calibration_factor_flag)) + + aux_interpolation_flag = 0 + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + ''' set output parameter for next iteration step ''' + ([item for item in calibration_settings if 'aux_interpolation_flag' in item])[-1][-1] = int(aux_interpolation_flag) + ([item for item in calibration_settings if 'calibration_value_flag' in item])[-1][-1] = calibration_value_flag + ([item for item in calibration_settings if 'calibration_factor_flag' in item])[-1][-1] = calibration_factor_flag + + return calibration_settings diff --git a/UNICADOworkflow/src/calibration/check_calibration_value_deviation.py b/UNICADOworkflow/src/calibration/check_calibration_value_deviation.py new file mode 100644 index 0000000000000000000000000000000000000000..991e8de3ee55d6430193dd1833e2cab7db8df118 --- /dev/null +++ b/UNICADOworkflow/src/calibration/check_calibration_value_deviation.py @@ -0,0 +1,136 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def check_calibration_value_deviation(calibration_loop_vector, target_value, type_of_calibration, + free_variable_calibration, path_of_working_directory_rce, + current_workflow_name='UNICADOworkflow'): + """ check_calibration_value_deviation checks the difference between current calibration value with given target value. + + The input list "calibration_loop_vector" contains all estimated ome or mtom values. + + The input value "target_value" contains the target value of current calibration type. + * Contains a specified MTOM or OME target value to be hit + + The input string "type_of_calibration" contains the name of calibration type. + * Contains the name OME or MTOM to check which outputs should be generated. + + The input int "free_variable_calibration" contains the status of free variable calibration. + * If input integer is equal to 1 -> engine calibration is selected and is being performed + + The input string "path_of_working_directory_rce" contains the system path to rce working directory. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + :param: calibration_loop_vector: input list + :param: target_value: input value + :param: type_of_calibration: input string + :param: free_variable_calibration: input int + :param: path_of_working_directory_rce: input string + :param: current_workflow_name: input string + :return: none + """ + + ''' imports for python ''' + import sys + from datetime import datetime + from sub_function.write_to_log_file import write_to_log_file + + ''' initialize local parameter ''' + log_file_list = [] + abort_flag = False + max_deviation_calibration_value_to_target = 0.2 + + # check if the current type of calibration is equal to 'OME' + # -> if true: -> check difference of ome calibration values + if type_of_calibration == 'OME': + if (abs(1 - calibration_loop_vector[-1]/target_value)) > max_deviation_calibration_value_to_target: + print(' Target-OME: ' + str(target_value)) + print(' Current-OME: ' + str(calibration_loop_vector[-1])) + print(' Deviation greater ' + str(max_deviation_calibration_value_to_target * 100) + ' percent!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Target-OME: ' + str(target_value)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current-OME: ' + str(calibration_loop_vector[-1])) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Deviation greater ' + str(max_deviation_calibration_value_to_target * 100) + + ' percent!') + + # check if the last element of calibration value list is greater than given target value to hit + if calibration_loop_vector[-1] > target_value: + print(' Fuselage mass factor significantly too high!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Fuselage mass factor significantly too high!') + # else condition: -> the last element of calibration value list is lower or equal to the given target value + else: + print(' Fuselage mass factor significantly too low!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Fuselage mass factor significantly too low!') + + print(' Select an appropriate start value! Program aborted') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Select an appropriate start value! Program aborted') + abort_flag = True + + if type_of_calibration == 'MTOM': + if (abs(1 - calibration_loop_vector[-1]/target_value)) > max_deviation_calibration_value_to_target: + print(' Target-MTOM: ' + str(target_value)) + print(' Current-MTOM: ' + str(calibration_loop_vector[-1])) + print(' Deviation greater ' + str(max_deviation_calibration_value_to_target * 100) + ' percent!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Target-MTOM: ' + str(target_value)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current-MTOM: ' + str(calibration_loop_vector[-1])) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Deviation greater ' + str(max_deviation_calibration_value_to_target * 100) + + ' percent!') + + # check if the last element of calibration value list is greater than given target value to hit + if calibration_loop_vector[-1] > target_value: + if free_variable_calibration == 1: + print(' Engine efficiency factor significantly too high!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Engine efficiency factor significantly too high!') + else: + print(' Drag reduction significantly too low!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Drag reduction significantly too low!') + # else condition: -> the last element of calibration value list is lower or equal to the given target value + else: + if free_variable_calibration == 1: + print(' Engine efficiency factor significantly too low!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Engine efficiency factor significantly too low!') + else: + print(' Drag reduction significantly too high!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Drag reduction significantly too high!') + + print(' Select an appropriate start value! Program aborted') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Select an appropriate start value! Program aborted') + abort_flag = True + + # check if abort flag is equal to 'True' -> if true: -> write error messages to workflow log file + if abort_flag: + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + sys.exit(1) + + return diff --git a/UNICADOworkflow/src/calibration/check_calibration_value_target.py b/UNICADOworkflow/src/calibration/check_calibration_value_target.py new file mode 100644 index 0000000000000000000000000000000000000000..a74a4166e7db37f3f0b2c0e7fd44fb150a08f690 --- /dev/null +++ b/UNICADOworkflow/src/calibration/check_calibration_value_target.py @@ -0,0 +1,269 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def check_calibration_value_target(calibration_settings, calibration_factors, type_of_calibration, automatic_trim, + flag_trim_successful, path_of_working_directory_rce, + current_workflow_name='UNICADOworkflow'): + """ check_calibration_value_target checks the the actual calibration value against the target calibration value. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input list "calibration_factors" contains all estimated calibration factors. + + The input value "type_of_calibration" contains the string of name of current calibration mode. + + The input integer "automatic_trim" contains the current status of automatic trimming is selected or not. + + The input integer "flag_trim_successful" contains the current status of automatic trimming is successful or not. + + The input string "path_of_working_directory_rce" contains the system path to rce working directory. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The output list "calibration_factors" contains all estimated calibration factors. + + :param: calibration_settings: input list of lists + :param: calibration_factors: input list + :param: type_of_calibration: input value + :param: automatic_trim: input integer + :param: flag_trim_successful: input integer + :param: path_of_working_directory_rce: input int + :param: current_workflow_name: input string + :return: calibration_settings: output list of lists, calibration_factors: output list + """ + + ''' imports for python ''' + from datetime import datetime + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + calibration_target_ome = ([item for item in calibration_settings if 'calibration_target_OME' in item])[-1][-1] + calibration_target_mtom = ([item for item in calibration_settings if 'calibration_target_mtom' in item])[-1][-1] + calibration_value_act = ([item for item in calibration_settings if 'calibration_value_act' in item])[-1][-1] + calibration_factor_act = ([item for item in calibration_settings if 'calibration_factor_act' in item])[-1][-1] + calibration_value_high = ([item for item in calibration_settings if 'calibration_value_high' in item])[-1][-1] + calibration_factor_high = ([item for item in calibration_settings if 'calibration_factor_high' in item])[-1][-1] + calibration_value_low = ([item for item in calibration_settings if 'calibration_value_low' in item])[-1][-1] + calibration_factor_low = ([item for item in calibration_settings if 'calibration_factor_low' in item])[-1][-1] + free_variable_mtom_calibration = \ + int(([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1]) + calibration_value_over_target_exist = \ + int(([item for item in calibration_settings if 'calibration_value_over_target_exist' in item])[-1][-1]) + calibration_value_under_target_exist = \ + int(([item for item in calibration_settings if 'calibration_value_under_target_exist' in item])[-1][-1]) + calibration_value_over_target_update_exist = \ + int(([item for item in calibration_settings if 'calibration_value_over_target_update_exist' in item])[-1][-1]) + calibration_value_under_target_update_exist = \ + int(([item for item in calibration_settings if 'calibration_value_under_target_update_exist' in item])[-1][-1]) + + ''' initialize local parameter ''' + log_file_list = [] + + if type_of_calibration == 'MTOM': + calibration_value = calibration_target_mtom + else: + calibration_value = calibration_target_ome + + if calibration_value_act > calibration_value: + if calibration_value_over_target_exist == 0: + print(' Save ' + type_of_calibration + ' (high) = ' + str(calibration_value_act) + ' > ' + + type_of_calibration + ' (target)') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Save ' + type_of_calibration + ' (high) = ' + str(calibration_value_act) + ' > ' + + type_of_calibration + ' (target)') + + calibration_value_high = calibration_value_act + calibration_factor_high = calibration_factor_act + calibration_value_over_target_exist = int(1) + + else: + if calibration_value_act < calibration_value_high: + print(' Overwrite old ' + type_of_calibration + ' (high) = ' + str(calibration_value_high) + ' by ' + + str(calibration_value_act) + ' > ' + type_of_calibration + ' (target)') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Overwrite old ' + type_of_calibration + ' (high) = ' + + str(calibration_value_high) + ' by ' + str(calibration_value_act) + ' > ' + + type_of_calibration + ' (target)') + + calibration_value_high = calibration_value_act + calibration_factor_high = calibration_factor_act + calibration_value_over_target_update_exist = int(1) + + # check if the current calibration mode is equal to MTOM and + # the free variable mtom calibration is not equal to engine calibration + if type_of_calibration == 'MTOM' and not free_variable_mtom_calibration == 1: + calibration_factor_high = calibration_factors[-1] + + # Check if the auto trim option is disabled + # or if the auto trim option is selected and completed successfully. + if not automatic_trim == 1 or flag_trim_successful == 1: + print(' (upper limit for possible new auxiliary interpolation)') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ' ' + '(upper limit for possible new auxiliary interpolation)') + else: + calibration_value_over_target_update_exist = int(0) + + else: + if calibration_value_under_target_exist == 0: + print(' Save ' + type_of_calibration + ' (low) = ' + str(calibration_value_act) + ' < ' + + type_of_calibration + ' (target)') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Save ' + type_of_calibration + ' (low) = ' + str(calibration_value_act) + ' < ' + + type_of_calibration + ' (target)') + + calibration_value_low = calibration_value_act + calibration_factor_low = calibration_factor_act + calibration_value_under_target_exist = int(1) + + else: + if calibration_value_act > calibration_value_low: + print(' Overwrite old ' + type_of_calibration + ' (low) = ' + str(calibration_value_low) + ' by ' + + str(calibration_value_act) + ' < ' + type_of_calibration + ' (target)') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Overwrite old ' + + type_of_calibration + ' (low) = ' + str(calibration_value_low) + ' by ' + + str(calibration_value_act) + ' < ' + type_of_calibration + ' (target)') + + calibration_value_low = calibration_value_act + calibration_factor_low = calibration_factor_act + calibration_value_under_target_update_exist = int(1) + + # check if the current calibration mode is equal to MTOM and + # the free variable mtom calibration is not equal to engine calibration + if type_of_calibration == 'MTOM' and not free_variable_mtom_calibration == 1: + calibration_factor_low = calibration_factors[-1] + + # Check if the auto trim option is disabled + # or if the auto trim option is selected and completed successfully. + if not automatic_trim == 1 or flag_trim_successful == 1: + print(' (lower limit for possible new auxiliary interpolation)') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ' ' + '(lower limit for possible new auxiliary interpolation)') + else: + calibration_value_over_target_update_exist = int(0) + + # write output strings to workflow log-file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + ''' set output parameter for next iteration step ''' + ([item for item in calibration_settings if 'calibration_target_OME' in item])[-1][-1] = calibration_target_ome + ([item for item in calibration_settings if 'calibration_target_mtom' in item])[-1][-1] = calibration_target_mtom + ([item for item in calibration_settings if 'calibration_value_act' in item])[-1][-1] = calibration_value_act + ([item for item in calibration_settings if 'calibration_factor_act' in item])[-1][-1] = calibration_factor_act + ([item for item in calibration_settings if 'calibration_value_high' in item])[-1][-1] = calibration_value_high + ([item for item in calibration_settings if 'calibration_factor_high' in item])[-1][-1] = calibration_factor_high + ([item for item in calibration_settings if 'calibration_value_low' in item])[-1][-1] = calibration_value_low + ([item for item in calibration_settings if 'calibration_factor_low' in item])[-1][-1] = calibration_factor_low + ([item for item in calibration_settings if 'calibration_value_over_target_exist' in item])[-1][-1] =\ + calibration_value_over_target_exist + ([item for item in calibration_settings if 'calibration_value_under_target_exist' in item])[-1][-1] =\ + calibration_value_under_target_exist + ([item for item in calibration_settings if 'calibration_value_over_target_update_exist' in item])[-1][-1] =\ + calibration_value_over_target_update_exist + ([item for item in calibration_settings if 'calibration_value_under_target_update_exist' in item])[-1][-1] =\ + calibration_value_under_target_update_exist + + return calibration_settings, calibration_factors diff --git a/UNICADOworkflow/src/calibration/check_number_of_iterations.py b/UNICADOworkflow/src/calibration/check_number_of_iterations.py new file mode 100644 index 0000000000000000000000000000000000000000..8d53f79dec4a6c8d7b091dde96dd8fec73dda57d --- /dev/null +++ b/UNICADOworkflow/src/calibration/check_number_of_iterations.py @@ -0,0 +1,217 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def check_number_of_iterations(calibration_settings, residual_mission_energy, convergence_criteria, type_of_calibration, + path_of_working_directory_rce, current_workflow_name='UNICADOworkflow'): + """ check_calibration_value_target checks the the actual calibration value against the target calibration value. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input float "residual_mission_energy" contains the residual of mission energy of current iteration loop. + + The input float "convergence_criteria" contains the given convergence criteria for calibration iteration. + + The input value "type_of_calibration" contains the string of name of current calibration mode. + + The input string "path_of_working_directory_rce" contains the system path to rce working directory. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + :param: calibration_settings: input list of lists + :param: residual_mission_energy: input float + :param: convergence_criteria: input float + :param: type_of_calibration: input value + :param: path_of_working_directory_rce: input int + :param: current_workflow_name: input string + :return: calibration_settings: output list of lists + """ + + ''' imports for python ''' + import sys + from datetime import datetime + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + residual_value = ([item for item in calibration_settings if 'residual_iteration_value' in item])[-1][-1] + calibration_factor_act = ([item for item in calibration_settings if 'calibration_factor_act' in item])[-1][-1] + calibration_factor_last = ([item for item in calibration_settings if 'calibration_factor_last' in item])[-1][-1] + calibration_value_act = ([item for item in calibration_settings if 'calibration_value_act' in item])[-1][-1] + calibration_value_last = ([item for item in calibration_settings if 'calibration_value_last' in item])[-1][-1] + number_reverse_effects = ([item for item in calibration_settings if 'number_reverse_effects' in item])[-1][-1] + free_variable_mtom_calibration = \ + int(([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1]) + + ''' initialize local parameter ''' + log_file_list = [] + abort_flag = False + print_flag = False + + ''' check condition for calibration number check ''' + # check if the current running calibration in an infinite loop + # -> if true: -> print a warning and perform specific exception handling + if (((type_of_calibration == 'MTOM' and free_variable_mtom_calibration == 2 + or type_of_calibration == 'OME') + and (((calibration_factor_act > calibration_factor_last) + and (calibration_value_act < calibration_value_last)) + or ((calibration_factor_act < calibration_factor_last) + and (calibration_value_act > calibration_value_last)))) + or ((type_of_calibration == 'MTOM' and free_variable_mtom_calibration == 1) + and (((calibration_factor_act > calibration_factor_last) + and (calibration_value_act > calibration_value_last)) + or ((calibration_factor_act < calibration_factor_last) + and (calibration_value_act < calibration_value_last))))): + # multiply the given convergence criteria by 3 + # to allow exceeding convergence and prepare for leaving the infinity loop + temporary_limit = 3 * convergence_criteria + print(' Warning! Reverse effect occurred!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning! Reverse effect occurred!') + + if residual_value < temporary_limit and type_of_calibration == 'OME': + print_flag = True + + elif residual_value < temporary_limit and residual_mission_energy < temporary_limit\ + and type_of_calibration == 'MTOM': + print_flag = True + + else: + print(' Number of iterations after which Interpol/Extrapolation is performed, possibly too low!') + print(' Increase NumberOfIterations in config file!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Number of iterations after which Interpol/Extrapolation is performed, ' + 'possibly too low!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Increase NumberOfIterations in config file!') + abort_flag = True + + if print_flag: + print(' Deviations in ' + type_of_calibration + ' (' + str(residual_value) + ') but small.') + log_file_list.append( + str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Deviations in ' + type_of_calibration + ' (' + + str(residual_value) + ') but small.') + number_reverse_effects += 1 + ([item for item in calibration_settings if 'number_reverse_effects' in item])[-1][-1] = \ + number_reverse_effects + + if number_reverse_effects > 3: + print(' Reverse Effect nevertheless occurred for the third time. Abort!') + log_file_list.append(str(datetime.now().strftime( + '%Y-%m-%d %H:%M:%S')) + ': Reverse Effect nevertheless occurred for the third time. Abort!') + abort_flag = True + + else: + print(' No abort! Attempts solution by further handling!') + log_file_list.append(str(datetime.now().strftime( + '%Y-%m-%d %H:%M:%S')) + ': No abort! Attempts solution by further handling!') + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + if abort_flag: + sys.exit(1) + + return calibration_settings diff --git a/UNICADOworkflow/src/calibration/check_tools_for_ome_calibration.py b/UNICADOworkflow/src/calibration/check_tools_for_ome_calibration.py new file mode 100644 index 0000000000000000000000000000000000000000..6ff3facbc3e19e5272c9d3df0d5f3412dfbbb484 --- /dev/null +++ b/UNICADOworkflow/src/calibration/check_tools_for_ome_calibration.py @@ -0,0 +1,84 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def check_tools_for_ome_calibration(paths_and_names, log_file_list): + """ check_tools_for_ome_calibration checks if necessary switches in module configuration files are set to perform OME calibration. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list "log_file_list" contains all system prints of function: set_configuration_parameter.py. + + The output list "log_file_list" contains all system prints of functions: set_configuration_parameter.py and select_engine_from_existing_project.py. + + :param: paths_and_names: input list of lists + :param: log_file_list: input list + :return: log_file_list: output list of lists + """ + + ''' imports for python ''' + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + ''' initialize local parameter ''' + calibrate_ome_flag = 1 + function_name = getframeinfo(currentframe()).function + + # try to open weight_and_balance_analysis module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/fuselage_design_conf.xml' + root_of_mass_estimation_tree, _ = read_xml_file(path, path_of_working_directory_rce, 'fuselage_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # read fuselage mass flag from weight_and_balance_analysis configuration file + fuselage_mass_flag = root_of_mass_estimation_tree.find( + './program_settings/configuration/fidelity/fuselage_design_tu_berlin/general/mass_technology_factors/' + 'fuselage_structural_mass_technology_factor/value') + + # check if fuselage mass flag from weight_and_balance_analysis configuration file is equal to zero + # -> if true: -> OME calibration is not possible -> raise an error and exit calibration mode. + if fuselage_mass_flag is None: + print('In fuselage_design configuration file, the fuselage mass technology factor node is missing. \n' + 'OME calibration is not possible. Exit calibration mode. ') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'In fuselage_design configuration file, the fuselage mass technology factor node is missing. \n' + ' OME calibration is not possible. Exit calibration mode.') + calibrate_ome_flag = 0 + + return calibrate_ome_flag, log_file_list diff --git a/UNICADOworkflow/src/calibration/damp_iteration.py b/UNICADOworkflow/src/calibration/damp_iteration.py new file mode 100644 index 0000000000000000000000000000000000000000..d31d00e0678dc13a703d7f14cf7736a31c90dd9b --- /dev/null +++ b/UNICADOworkflow/src/calibration/damp_iteration.py @@ -0,0 +1,105 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def damp_iteration(paths_and_names, mass_loop_vector, type_of_calibration): + """ check_calibration_value_deviation checks the difference between current calibration value with given target value. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list "mass_loop_vector" contains all estimated mass values of current iteration loop. + + The input string "type_of_calibration" contains the name of calibration type. + + The input float "damped_value" contains the estimated damped iteration value. + + :param: paths_and_names: input list of lists + :param: mass_loop_vector: input list + :param: type_of_calibration: input string + :return: damped_value: output float + """ + + ''' imports for python ''' + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + ''' initialize local parameter ''' + log_file_list = [] + output_string = str() + function_name = getframeinfo(currentframe()).function + + ''' estimate damped iteration value ''' + # the damped value is the average of the last two OME or MTOM values + damped_value = 0.5 * (mass_loop_vector[-1] + mass_loop_vector[-2]) + + ''' read data from aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + aircraft_exchange_file + root_of_aircraft_exchange_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + if type_of_calibration == 'OME': + output_string = ' Use damped OME = ' + str(damped_value) + # save damped ome to aircraft exchange file + root_of_aircraft_exchange_tree.find( + './analysis/masses_cg_inertia/operating_mass_empty/mass_properties/mass/value').text = str(damped_value) + root_of_aircraft_exchange_tree.find('./analysis/masses_cg_inertia').set('tool_level', '1') + + if type_of_calibration == 'MTOM': + output_string = ' Use damped MTOM = ' + str(damped_value) + # save damped ome to aircraft exchange file + root_of_aircraft_exchange_tree.find( + './analysis/masses_cg_inertia/maximum_takeoff_mass/mass_properties/mass/value').text = str(damped_value) + root_of_aircraft_exchange_tree.find('./analysis/masses_cg_inertia').set('tool_level', '1') + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + print(str(output_string) + ' kg for next iteration!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + output_string + + ' kg for next iteration!') + log_file_list.append('') + + ''' write log-file to system ''' + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + return damped_value diff --git a/UNICADOworkflow/src/calibration/extrapolation_failed.py b/UNICADOworkflow/src/calibration/extrapolation_failed.py new file mode 100644 index 0000000000000000000000000000000000000000..fc3e5241ad93c06ef1886cfa4b422f4d80783f42 --- /dev/null +++ b/UNICADOworkflow/src/calibration/extrapolation_failed.py @@ -0,0 +1,163 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def extrapolation_failed(calibration_settings, calibration_target_value, path_of_working_directory_rce, + current_workflow_name='UNICADOworkflow'): + """ perform_ome_calibration performs the ome calibration. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input string "path_of_working_directory_rce" contains the system path to rce working directory. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + :param: calibration_settings: input list of lists + :param: calibration_target_value: input float + :param: path_of_working_directory_rce: input string + :param: current_workflow_name: input string + :return: calibration_settings: output list of lists + """ + + ''' imports for python ''' + from datetime import datetime + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + calibration_factor_high = ([item for item in calibration_settings if 'calibration_factor_high' in item])[-1][-1] + calibration_value_high = ([item for item in calibration_settings if 'calibration_value_high' in item])[-1][-1] + calibration_factor_low = ([item for item in calibration_settings if 'calibration_factor_low' in item])[-1][-1] + calibration_value_low = ([item for item in calibration_settings if 'calibration_value_low' in item])[-1][-1] + + ''' initialize local parameter ''' + log_file_list = [] + + print(' Extrapolation failed. Use auxiliary interpolation:') + print(' low[' + str(calibration_factor_low) + '; ' + str(calibration_value_low) + '] | high[' + + str(calibration_factor_high) + '; ' + str(calibration_value_high) + ']') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Extrapolation failed. Use auxiliary interpolation:') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'low[' + str(calibration_factor_low) + '; ' + + str(calibration_value_low) + '] | high[' + str(calibration_factor_high) + '; ' + + str(calibration_value_high) + ']') + + calibration_factor_temp = (calibration_factor_high - calibration_factor_low) / \ + (calibration_value_high - calibration_value_low) * \ + (calibration_target_value - calibration_value_low) + calibration_factor_low + + print(' Corrected calibration factor (new): ' + str(calibration_factor_temp)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Corrected calibration factor (new): ' + + str(calibration_factor_temp)) + + ''' set output parameter for next iteration step ''' + ([item for item in calibration_settings if 'aux_interpolation_flag' in item])[-1][-1] = int(1) + ([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1] = calibration_factor_temp + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + return calibration_settings diff --git a/UNICADOworkflow/src/calibration/final_ome_calibration_steps.py b/UNICADOworkflow/src/calibration/final_ome_calibration_steps.py new file mode 100644 index 0000000000000000000000000000000000000000..111642be0d5c16e794675ac4248f198bc99937b2 --- /dev/null +++ b/UNICADOworkflow/src/calibration/final_ome_calibration_steps.py @@ -0,0 +1,105 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def final_ome_calibration_steps(paths_and_names): + """ final_ome_calibration_steps stores the final ome calibration results to csv-file and saves th current aircraft exchange file. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + :param: paths_and_names: input list of lists + :return: none + """ + + ''' imports for python ''' + import os + import shutil + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from calibration.save_calibration_results_to_file import save_calibration_results_to_file + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + ''' initialize local parameter ''' + log_file_list = [] + function_name = getframeinfo(currentframe()).function + + ''' save aircraft exchange file of final ome calibration loop to temporary results directory ''' + aircraft_exchange_files_of_ome_calibration = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/OMEcalibration/' + if not os.path.isdir(aircraft_exchange_files_of_ome_calibration): + os.makedirs(aircraft_exchange_files_of_ome_calibration) + + list_of_exchange_elements = os.listdir(aircraft_exchange_files_of_ome_calibration) + count_of_calibration = len(list_of_exchange_elements) + 1 + + # save aircraft exchange file of final ome calibration loop + project_file_name = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project \ + + '/' + aircraft_exchange_file + shutil.copy(project_file_name, aircraft_exchange_files_of_ome_calibration + aircraft_exchange_file[:-4] + + '_it' + str(count_of_calibration) + '.xml') + + ''' estimate ome residual from pre last to final ome value ''' + # read final ome value from aircraft exchange file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project \ + + '/' + aircraft_exchange_file + root_of_aircraft_exchange_tree, _ = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + final_ome = float(root_of_aircraft_exchange_tree.find( + './analysis/masses_cg_inertia/operating_mass_empty/mass_properties/mass/value').text) + + # read pre-final ome value from aircraft exchange file + frame_info = getframeinfo(currentframe()) + aircraft_exchange_file = aircraft_exchange_file[:-4] + '_it' + str(count_of_calibration-1) + '.xml' + path = aircraft_exchange_files_of_ome_calibration + aircraft_exchange_file + root_of_aircraft_exchange_tree, _ = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, + frame_info.lineno, log_file_list) + + pre_final_ome = float(root_of_aircraft_exchange_tree.find( + './analysis/masses_cg_inertia/operating_mass_empty/mass_properties/mass/value').text) + + # estimate final ome residual + residual_ome = abs(1 - pre_final_ome/final_ome) + + ''' save calibration results to csv file ''' + save_calibration_results_to_file(paths_and_names, count_of_calibration, residual_ome, 'OME') + + return diff --git a/UNICADOworkflow/src/calibration/initialize_parameter_for_calibration.py b/UNICADOworkflow/src/calibration/initialize_parameter_for_calibration.py new file mode 100644 index 0000000000000000000000000000000000000000..3dfb5a4c08d8c67bd51efa005021ffda4588a04f --- /dev/null +++ b/UNICADOworkflow/src/calibration/initialize_parameter_for_calibration.py @@ -0,0 +1,175 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def initialize_parameter_for_calibration(paths_and_names, calibration_settings, log_file_list): + """ set_settings_for_ome_calibration initialized calibration variables for OME calibration. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + + The input list "log_file_list" contains all system prints of function: set_configuration_parameter.py. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + + The output list "log_file_list" contains all system prints of functions: set_configuration_parameter.py and select_engine_from_existing_project.py. + + :param: paths_and_names: input list of lists + :param: calibration_settings: input list of lists + :param: log_file_list: input list + :return: calibration_settings: output list of lists + """ + ''' imports for python ''' + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + calibration_target_mtom = ([item for item in calibration_settings if 'calibration_target_mtom' in item])[-1][-1] + + ''' initialize local parameter ''' + function_name = getframeinfo(currentframe()).function + + ''' open and read aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + aircraft_exchange_file + root_of_aircraft_exchange_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, + frame_info.lineno, log_file_list, current_workflow_name) + + root_of_aircraft_exchange_tree.find( + './analysis/masses_cg_inertia/maximum_takeoff_mass/mass_properties/mass/value').text =\ + str(calibration_target_mtom) + root_of_aircraft_exchange_tree.find('./analysis/masses_cg_inertia').set('tool_level', '1') + + # write calibration MTOM and tool level to aircraft exchange file + xml_tree.write(path, encoding='utf-8') + + ''' initialize global global calibration parameter ''' + residual_ome = float(0.0) + residual_ome_to_target = float(0.0) + + # try to open weight_and_balance_analysis module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/fuselage_design_conf.xml' + root_of_mass_estimation_tree, _ = read_xml_file(path, path_of_working_directory_rce, 'fuselage_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # read fuselage scaling factor from fuselage configuration file + calibration_factor_temp = float(root_of_mass_estimation_tree.find( + './program_settings/configuration/fidelity/fuselage_design_tu_berlin/' + 'general/mass_technology_factors/fuselage_structural_mass_technology_factor/value').text) + + calibration_factor_flag = calibration_factor_temp + + calibration_settings.append(['residual_iteration_value', residual_ome]) + calibration_settings.append(['residual_iteration_value_to_target', residual_ome_to_target]) + calibration_settings.append(['calibration_factor_temp', calibration_factor_temp]) + calibration_settings.append(['calibration_factor_flag', calibration_factor_flag]) + calibration_settings.append(['calibration_factor_low', float(0.0)]) + calibration_settings.append(['calibration_factor_high', float(0.0)]) + calibration_settings.append(['calibration_factor_act', calibration_factor_temp]) + calibration_settings.append(['calibration_factor_last', calibration_factor_temp]) + calibration_settings.append(['calibration_value_flag', float(0.0)]) + calibration_settings.append(['calibration_value_low', float(0.0)]) + calibration_settings.append(['calibration_value_high', float(0.0)]) + calibration_settings.append(['calibration_value_act', float(0.0)]) + calibration_settings.append(['calibration_value_last', float(0.0)]) + calibration_settings.append(['aux_interpolation_flag', int(0)]) + calibration_settings.append(['calibration_value_over_target_exist', float(0.0)]) + calibration_settings.append(['calibration_value_under_target_exist', float(0.0)]) + calibration_settings.append(['calibration_value_over_target_update_exist', float(0.0)]) + calibration_settings.append(['calibration_value_under_target_update_exist', float(0.0)]) + calibration_settings.append(['number_reverse_effects', int(0)]) + calibration_settings.append(['number_of_final_runs', int(1)]) + calibration_settings.append(['x_relative', float(0.0)]) + calibration_settings.append(['max_delta_calibration_factor', float(0.0)]) + + return calibration_settings diff --git a/UNICADOworkflow/src/calibration/perform_mtom_calibration.py b/UNICADOworkflow/src/calibration/perform_mtom_calibration.py new file mode 100644 index 0000000000000000000000000000000000000000..3e3ae32b3ae456c95ee7548aa6d9f856baf0bbfc --- /dev/null +++ b/UNICADOworkflow/src/calibration/perform_mtom_calibration.py @@ -0,0 +1,426 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def perform_mtom_calibration(calibration_settings, parameter_for_design_case, design_variables, mtom_loop_vector, + calibration_factors, count_of_calibration, automatic_trim, flag_trim_successful, + path_of_working_directory_rce, current_workflow_name='UNICADOworkflow'): + """ perform_mtom_calibration performs the mtom calibration. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The input list of lists "design_variables" contains the following values: + * [0][0] string: 'm_take_off_max_last', [0][1] float: 'value of maximum take off mass of last iteration step' + * [1][0] string: 'm_operating_empty_last', [1][1] float: 'value of operating empty mass of last iteration step' + * [2][0] string: 'mission_energy_last', [2][1] float: 'value of mission energy of last iteration step' + * [3][0] string: 'x_center_of_gravity_last', [3][1] float: 'value of x position of center of gravity of last iteration step' + * [4][0] string: 'cm_cruise', [4][1] float: 'value of the current moment coefficient' + * [5][0] string: 'i_stab', [5][1] float: 'value of the current trimming angle of horizontal stabiliser' + * [6][0] string: 'm_take_off_max', [6][1] float: 'value of maximum take off mass of current iteration step' + * [7][0] string: 'm_operating_empty', [7][1] float: 'value of operating empty mass of current iteration step' + * [8][0] string: 'mission_energy', [8][1] float: 'value of mission energy of current iteration step' + * [9][0] string: 'x_center_of_gravity', [9][1] float: 'value of x position of center of gravity of current iteration step' + * [10][0] string: 'residual_m_take_off_max', [10][1] float: 'value of residual of maximum take off mass of current iteration step' + * [11][0] string: 'residual_m_operating_empty', [11][1] float: 'value of residual of operating empty mass of current iteration step' + * [12][0] string: 'residual_mission_energy', [12][1] float: 'value of residual of mission energy of current iteration step' + * [13][0] string: 'residual_x_center_of_gravity', [13][1] float: 'value of residual of x position of center of gravity of current iteration step' + * [14][0] string: 'status_residual_m_take_off_max', [14][1] bool: 'status of convergence for maximum take of mass' + * [15][0] string: 'status_residual_m_operating_empty', [15][1] bool: 'status of convergence for mass operating empty' + * [16][0] string: 'status_residual_mission_energy', [16][1] bool: 'status of convergence for mission energy' + * [17][0] string: 'status_residual_x_center_of_gravity', [17][1] bool: 'status of convergence for the aft x-position of the center of gravity' + + The input list "mtom_loop_vector" contains all estimated mtom values. + + The input list "calibration_factors" contains all estimated calibration factors. + + The input integer "count_of_calibration" contains the current number of iteration loop. + + The input integer "automatic_trim" contains the current status of automatic trimming is selected or not. + + The input integer "flag_trim_successful" contains the current status of automatic trimming is successful or not. + + The input string "path_of_working_directory" contains the system path to UNICADO installation directory. + + The input string "path_of_working_directory_rce" contains the system path to rce working directory. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The output list "mtom_loop_vector" contains all estimated mtom values. + + The output list "calibration_factors" contains all estimated calibration factors. + + The output bool "iteration_flag" contains the status of calibration. + + :param: calibration_settings: input list of lists + :param: parameter_for_design_case: input list of lists + :param: design_variables: input list of lists + :param: mtom_loop_vector: input list + :param: calibration_factors: input list + :param: count_of_calibration: input integer + :param: automatic_trim: input integer + :param: flag_trim_successful: input integer + :param: path_of_working_directory: input string + :param: path_of_working_directory_rce: input string + :param: current_workflow_name: input string + :return: calibration_settings: output list of lists, mtom_loop_vector: output list, calibration_factors: output list + """ + + ''' imports for python ''' + import sys + from inspect import currentframe, getframeinfo + from datetime import datetime + from sub_function.read_xml_file import read_xml_file + from sub_function.write_to_log_file import write_to_log_file + from calibration.extrapolation_failed import extrapolation_failed + from calibration.set_calibration_factor import set_calibration_factor + from calibration.set_calibration_values import set_calibration_values + from calibration.aux_interpolation_handling import aux_interpolation_handling + from calibration.set_new_calibration_factor import set_new_calibration_factor + from calibration.check_calibration_value_target import check_calibration_value_target + from calibration.check_calibration_value_deviation import check_calibration_value_deviation + + ''' read data for script execution ''' + target_value = ([item for item in calibration_settings if 'calibration_target_mtom' in item])[-1][-1] + trunc_error_factor = ([item for item in calibration_settings if 'trunc_Error_factor' in item])[-1][-1] + free_variable_mtom_calibration = \ + int(([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1]) + number_of_iterations_before_mtom_calibration = \ + int(([item for item in calibration_settings if 'number_of_iterations_before_mtom_calibration' in item])[-1][-1]) + + convergence_criteria = ([item for item in parameter_for_design_case if 'convergence_criteria' in item])[-1][-1] + + ''' check if deviation OME to target is too large ''' + check_calibration_value_deviation(mtom_loop_vector, target_value, 'MTOM', free_variable_mtom_calibration, + path_of_working_directory_rce, current_workflow_name) + + ''' handling of auxiliary interpolation from previous run ''' + calibration_settings = aux_interpolation_handling(calibration_settings, mtom_loop_vector, 'MTOM', + path_of_working_directory_rce, current_workflow_name) + + ''' set calibration values from previous run ''' + calibration_settings = set_calibration_values(calibration_settings, mtom_loop_vector, 'MTOM', convergence_criteria, + count_of_calibration, path_of_working_directory_rce, + current_workflow_name) + + ''' set mtom calibration factors ''' + calibration_settings, calibration_factors = set_calibration_factor(calibration_settings, calibration_factors, + count_of_calibration, + number_of_iterations_before_mtom_calibration) + + ''' check, whether current MTOM is above or below MTOM target value ''' + calibration_settings, calibration_factors = \ + check_calibration_value_target(calibration_settings,calibration_factors, 'MTOM', automatic_trim, + flag_trim_successful, path_of_working_directory_rce, current_workflow_name) + + ''' set new mtom calibration factors ''' + residual_mission_energy = ([item for item in design_variables if 'residual_mission_energy' in item])[-1][-1] + calibration_settings, calibration_factors =\ + set_new_calibration_factor(calibration_settings, calibration_factors, residual_mission_energy, + count_of_calibration, convergence_criteria, 'MTOM', path_of_working_directory_rce, + current_workflow_name) + + ''' add current temporary calibration factor to calibration factor array ''' + calibration_factors.append(([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1]) + + ''' initialize local parameter ''' + log_file_list = [] + function_name = getframeinfo(currentframe()).function + + ''' reload calibration variables from calibration_settings list of list ''' + free_variable_mtom_calibration =\ + int(([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1]) + calibration_target_mtom =\ + ([item for item in calibration_settings if 'calibration_target_mtom' in item])[-1][-1] + calibration_value_over_target_update_exist = \ + ([item for item in calibration_settings if 'calibration_value_over_target_update_exist' in item])[-1][-1] + calibration_value_under_target_update_exist =\ + ([item for item in calibration_settings if 'calibration_value_under_target_update_exist' in item])[-1][-1] + damp_mtom_calibration_lever =\ + ([item for item in calibration_settings if 'damp_MTOM_calibration_lever' in item])[-1][-1] + calibration_factor_temp =\ + ([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1] + calibration_factor_low =\ + ([item for item in calibration_settings if 'calibration_factor_low' in item])[-1][-1] + calibration_factor_high = \ + ([item for item in calibration_settings if 'calibration_factor_high' in item])[-1][-1] + calibration_factor_act =\ + ([item for item in calibration_settings if 'calibration_factor_act' in item])[-1][-1] + calibration_value_act =\ + ([item for item in calibration_settings if 'calibration_value_act' in item])[-1][-1] + x_relative = float(([item for item in calibration_settings if 'x_relative' in item])[-1][-1]) + + ''' catch special case, if extrapolation fails ''' + if (calibration_value_over_target_update_exist == 1 and calibration_value_under_target_update_exist == 1 and + (calibration_factor_temp < calibration_factor_low or calibration_factor_temp > calibration_factor_high)): + # call function to prepare outputs if extrapolation fails + calibration_settings = extrapolation_failed(calibration_settings, calibration_target_mtom, + path_of_working_directory_rce, current_workflow_name) + + ''' safety query check for too large change of calibration factors ''' + if (count_of_calibration - 1) == (number_of_iterations_before_mtom_calibration * 2): + if free_variable_mtom_calibration == 1: + # max delta Engine efficiency factor + max_delta_calibration_factor = 0.3 + else: + # max delta aero factor + max_delta_calibration_factor = 10.0 + + else: + if free_variable_mtom_calibration == 1: + # max delta Engine efficiency factor + max_delta_calibration_factor = 0.08 + else: + # max delta aero factor + max_delta_calibration_factor = 5.0 + + ([item for item in calibration_settings if 'max_delta_calibration_factor' in item])[-1][-1] =\ + max_delta_calibration_factor + + # save current Engine efficiency factor + if free_variable_mtom_calibration == 1: + if abs(1 - calibration_factor_temp / calibration_factor_act) > max_delta_calibration_factor: + print(' Change Engine efficiency Factor (= ' + + str(abs(1 - calibration_factor_temp / calibration_factor_act)) + + ') greater than permitted deviation (' + str(max_delta_calibration_factor) + ')!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Change Engine efficiency Factor (= ' + + str(abs(1 - calibration_factor_temp / calibration_factor_act)) + + ') greater than permitted deviation (' + str(max_delta_calibration_factor) + ')!') + + if x_relative > 1 and not damp_mtom_calibration_lever == 1: + print(' x_rel = ' + str(x_relative) + + ' might be too high, try switching Damp_MTOM_Calibration_Lever on!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'x_rel = ' + str(x_relative) + + ' might be too high, try switching Damp_MTOM_Calibration_Lever on!') + + elif damp_mtom_calibration_lever == 1: + print(' Damp_MTOM_Calibration_Lever is on! x_rel is damped to ' + str(x_relative) + + ' but might still be too high. Try adjusting x_rel_max!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Damp_MTOM_Calibration_Lever is on! x_rel is damped to ' + str(x_relative) + + ' but might still be too high. Try adjusting x_rel_max!') + + print(' Check design, set appropriate start value for Engine efficiency Factor in propulsion_design-Config, ' + 'or increase <NumberOfIterations>! Abort program.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Check design, set appropriate start value for Engine efficiency Factor ' + 'in propulsion_design-Config, or increase <NumberOfIterations>! Abort program.') + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + # abort program + sys.exit(1) + + residual_factor = abs(1 - (calibration_factors[-2] / calibration_factors[-1])) + + # save current aero calibration factor + else: + if calibration_factors[-1] == 0: + residual_factor = 1 + + else: + if abs(1 - calibration_factor_temp / calibration_factors[-1]) > max_delta_calibration_factor: + print(' Change AeroFactor (= ' + str(abs(1 - calibration_factor_temp / calibration_factors[-1])) + + ') greater than permitted deviation (' + str(max_delta_calibration_factor) + ')!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Change AeroFactor (= ' + + str(abs(1 - calibration_factor_temp / calibration_factors[-1])) + + ') greater than permitted deviation (' + str(max_delta_calibration_factor) + + ')!') + + if x_relative > 1 and not damp_mtom_calibration_lever == 1: + print(' x_rel = ' + str( + x_relative) + ' might be too high, try switching Damp_MTOM_Calibration_Lever on!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'x_rel = ' + str(x_relative) + + ' might be too high, try switching Damp_MTOM_Calibration_Lever on!') + + elif damp_mtom_calibration_lever == 1: + print(' Damp_MTOM_Calibration_Lever is on! x_rel is damped to ' + str(x_relative) + + ' but might still be too high. Try adjusting x_rel_max!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Damp_MTOM_Calibration_Lever is on! x_rel is damped to ' + str(x_relative) + + ' but might still be too high. Try adjusting x_rel_max!') + + print(' Check design or set better start value for Aero Factor in aerodynamic_assessment-Config! ' + 'Abort program.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Check design or set better start value for Aero Factor in aerodynamic_assessment-Config! ' + 'Abort program.') + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + # abort program + sys.exit(1) + + residual_factor = abs(1 - (calibration_factors[-2] / calibration_factors[-1])) + + print(' Res. DragReduction: ' + str(residual_factor)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Res. DragReduction: ' + str(residual_factor)) + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + ''' check if convergence criteria reached -> if true: -> prepare final steps ''' + residual_mtom_to_target = abs(1 - calibration_value_act / calibration_target_mtom) + if ((residual_mtom_to_target < convergence_criteria * trunc_error_factor) and + (residual_factor < convergence_criteria * trunc_error_factor)): + ([item for item in calibration_settings if 'calibrate_mtom_flag' in item])[-1][-1] = int(0) + ([item for item in calibration_settings if 'iteration_flag' in item])[-1][-1] = int(1) + ([item for item in calibration_settings if 'final_fuselage_mass_factor' in item])[-1][-1] = \ + calibration_factors[-1] + + print(' !!!Calibration successful!!!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': !!!Calibration successful!!!') + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + ''' write temporary mtom calibration factor to configuration file of performing modules ''' + if free_variable_mtom_calibration == 1: + # try to open propulsion_design module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/propulsion_design_conf.xml' + root_of_mass_estimation_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'propulsion_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # reset Engine efficiency scaling factor in propulsion_design configuration file to 1 + root_of_mass_estimation_tree.find( + './program_settings/technology_factors/engine_efficiency/value').text = str(calibration_factor_temp) + + else: + # try to open aerodynamic_assessment module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/aerodynamic_analysis_conf.xml' + root_of_calculate_polar_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + 'aerodynamic_analysis', function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + # reset drag factor in aerodynamic_assessment configuration file to 1 + root_of_calculate_polar_tree.find( + './program_settings/ViscDragRaymer/DeltaViscousDragWing/value').text = str(calibration_factor_temp) + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + return calibration_settings, mtom_loop_vector, calibration_factors diff --git a/UNICADOworkflow/src/calibration/perform_ome_calibration.py b/UNICADOworkflow/src/calibration/perform_ome_calibration.py new file mode 100644 index 0000000000000000000000000000000000000000..a00aaa8e9d9776dc4f39e41933c3523be4f7c130 --- /dev/null +++ b/UNICADOworkflow/src/calibration/perform_ome_calibration.py @@ -0,0 +1,316 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def perform_ome_calibration(calibration_settings, parameter_for_design_case, ome_loop_vector, calibration_factors, + count_of_calibration, path_of_working_directory_rce, + current_workflow_name='UNIACDOworkflow'): + """ perform_ome_calibration performs the ome target value calibration. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The input list "ome_loop_vector" contains all estimated ome values. + + The input list "calibration_factors" contains all estimated calibration factors. + + The input value "count_of_calibration" contains the current number of calibration loop. + + The input string "path_of_working_directory" contains the system path to UNICADO installation directory. + + The input string "path_of_working_directory_rce" contains the system path to rce working directory. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The output list "ome_loop_vector" contains all estimated ome values. + + The output list "calibration_factors" contains all estimated calibration factors. + + The output bool "iteration_flag" contains the status of calibration. + + :param: calibration_settings: input list of lists + :param: parameter_for_design_case: input list of lists + :param: ome_loop_vector: input list + :param: calibration_factors: input list + :param: count_of_calibration: input value + :param: path_of_working_directory: input string + :param: path_of_working_directory_rce: input string + :param: current_workflow_name: input string + :return: calibration_settings: output list of lists, ome_loop_vector: output list, calibration_factors: output list, iteration_flag: output bool + """ + + ''' imports for python ''' + import sys + from inspect import currentframe, getframeinfo + from datetime import datetime + from sub_function.read_xml_file import read_xml_file + from sub_function.write_to_log_file import write_to_log_file + from calibration.extrapolation_failed import extrapolation_failed + from calibration.set_calibration_factor import set_calibration_factor + from calibration.set_calibration_values import set_calibration_values + from calibration.aux_interpolation_handling import aux_interpolation_handling + from calibration.set_new_calibration_factor import set_new_calibration_factor + from calibration.check_calibration_value_target import check_calibration_value_target + from calibration.check_calibration_value_deviation import check_calibration_value_deviation + + ''' read data for script execution ''' + target_value = ([item for item in calibration_settings if 'calibration_target_OME' in item])[-1][-1] + trunc_error_factor = ([item for item in calibration_settings if 'trunc_Error_factor' in item])[-1][-1] + free_variable_ome_calibration =\ + int(([item for item in calibration_settings if 'free_variable_OME_calibration' in item])[-1][-1]) + + convergence_criteria = ([item for item in parameter_for_design_case if 'convergence_criteria' in item])[-1][-1] + + ''' initialize local parameter ''' + log_file_list = [] + function_name = getframeinfo(currentframe()).function + + ''' check if deviation OME to target is too large ''' + check_calibration_value_deviation(ome_loop_vector, target_value, 'OME', free_variable_ome_calibration, + path_of_working_directory_rce, current_workflow_name) + + ''' handling of auxiliary interpolation from previous run ''' + calibration_settings = aux_interpolation_handling(calibration_settings, ome_loop_vector, 'OME', + path_of_working_directory_rce, current_workflow_name) + + ''' set calibration values from previous run ''' + calibration_settings = set_calibration_values(calibration_settings, ome_loop_vector, 'OME', convergence_criteria, + count_of_calibration, path_of_working_directory_rce, + current_workflow_name) + + ''' set fuselage mass factors ''' + calibration_settings, calibration_factors = set_calibration_factor(calibration_settings, calibration_factors, + count_of_calibration, 3) + + ''' check, whether OME is above or below OME_target ''' + calibration_settings, calibration_factors = check_calibration_value_target(calibration_settings, + calibration_factors, 'OME', 0, 0, + path_of_working_directory_rce, + current_workflow_name) + + ''' set new fuselage mass factor ''' + calibration_settings, calibration_factors = set_new_calibration_factor(calibration_settings, calibration_factors, + 0.00, count_of_calibration, + convergence_criteria, 'OME', + path_of_working_directory_rce, + current_workflow_name) + + ''' add current temporary calibration factor to calibration factor array ''' + calibration_factors.append(([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1]) + + ''' reload calibration variables from calibration_settings list of list ''' + calibration_value_over_target_update_exist = \ + ([item for item in calibration_settings if 'calibration_value_over_target_update_exist' in item])[-1][-1] + calibration_value_under_target_update_exist = \ + ([item for item in calibration_settings if 'calibration_value_under_target_update_exist' in item])[-1][-1] + damp_ome_calibration_lever = \ + ([item for item in calibration_settings if 'damp_OME_calibration_lever' in item])[-1][-1] + calibration_factor_temp = \ + ([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1] + calibration_factor_low = \ + ([item for item in calibration_settings if 'calibration_factor_low' in item])[-1][-1] + calibration_factor_high = \ + ([item for item in calibration_settings if 'calibration_factor_high' in item])[-1][-1] + calibration_factor_act = \ + ([item for item in calibration_settings if 'calibration_factor_act' in item])[-1][-1] + x_relative = float(([item for item in calibration_settings if 'x_relative' in item])[-1][-1]) + + ''' catch special case, if extrapolation fails ''' + if (calibration_value_over_target_update_exist == 1 and calibration_value_under_target_update_exist == 1 and + (calibration_factor_temp < calibration_factor_low or calibration_factor_temp > calibration_factor_high)): + calibration_target_ome = ([item for item in calibration_settings if 'calibration_target_OME' in item])[-1][-1] + # call function for output preparation if the extrapolation failed + calibration_settings = extrapolation_failed(calibration_settings, calibration_target_ome, + path_of_working_directory_rce, current_workflow_name) + + ''' safety query check for too large change of the fuselage mass factors ''' + if count_of_calibration - 1 == 2: + max_delta_calibration_factor = 0.3 + + else: + max_delta_calibration_factor = 0.08 + + if abs(1 - calibration_factor_temp / calibration_factor_act) > max_delta_calibration_factor: + print(' Change FuselageMassFactor (= ' + str(abs(1 - calibration_factor_temp / calibration_factor_act)) + + ') greater than permitted deviation (' + str(max_delta_calibration_factor) + ')!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Change FuselageMassFactor (= ' + + str(abs(1 - calibration_factor_temp / calibration_factor_act)) + + ') greater than permitted deviation (' + str(max_delta_calibration_factor) + ')!') + + if x_relative > 1 and not damp_ome_calibration_lever == 1: + print(' x_rel = ' + str(x_relative) + ' might be too high, try switching Damp_OME_Calibration_Lever on.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': x_rel = ' + + str(x_relative) + ' might be too high, try switching Damp_OME_Calibration_Lever on.') + + elif damp_ome_calibration_lever == 1: + print(' Damp_OME_Calibration_Lever is on. x_rel is damped to ' + str(x_relative) + + ' but might still be too high. Try adjusting x_rel_max.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Damp_OME_Calibration_Lever is on. x_rel is damped to ' + str(x_relative) + + ' but might still be too high. Try adjusting x_rel_max.') + + print(' Check design, increase <NumberOfIterations>. Abort program.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Check design, increase <NumberOfIterations>. Abort program.') + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + # abort program + sys.exit(1) + + ([item for item in calibration_settings if 'max_delta_calibration_factor' in item])[-1][-1] = \ + max_delta_calibration_factor + + ''' save the current fuselage mass factor ''' + residual_ome_to_target = \ + ([item for item in calibration_settings if 'residual_iteration_value_to_target' in item])[-1][-1] + residual_fuselage_factor = abs(1 - (calibration_factors[-2]/calibration_factors[-1])) + + # check if convergence criteria reached -> if true: -> prepare final steps + if ((residual_ome_to_target < convergence_criteria * trunc_error_factor) and + (residual_fuselage_factor < convergence_criteria * trunc_error_factor)): + ([item for item in calibration_settings if 'calibrate_ome_flag' in item])[-1][-1] = int(0) + ([item for item in calibration_settings if 'final_fuselage_mass_factor' in item])[-1][-1] = \ + calibration_factors[-1] + + print(' !!!Calibration successful!!!" ') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': !!!Calibration successful!!!') + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + ''' write temporary fuselage mass factor to configuration file of mass estimation module ''' + # try to open weight_and_balance_analysis module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/fuselage_design_conf.xml' + root_of_mass_estimation_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'fuselage_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # reset fuselage scaling factor in weight_and_balance_analysis configuration file to 1 + root_of_mass_estimation_tree.find( + './program_settings/configuration/fidelity/fuselage_design_tu_berlin/general/mass_technology_factors/' + 'fuselage_structural_mass_technology_factor/value').text = str(calibration_factor_temp) + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + return calibration_settings, ome_loop_vector, calibration_factors diff --git a/UNICADOworkflow/src/calibration/perform_ome_iteration.py b/UNICADOworkflow/src/calibration/perform_ome_iteration.py new file mode 100644 index 0000000000000000000000000000000000000000..6158e77144b12904b0b8dcaec22d3a7f0b00b4aa --- /dev/null +++ b/UNICADOworkflow/src/calibration/perform_ome_iteration.py @@ -0,0 +1,280 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def perform_ome_iteration(paths_and_names, calibration_settings, ome_loop_vector, parameter_for_design_case, + calibration_factors, count_of_calibration): + """ set_settings_for_ome_calibration initialized calibration variables for OME calibration. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The input list "ome_loop_vector" contains all estimated ome values. + + The input list "calibration_factors" contains all estimated calibration factors. + + The input value "count_of_calibration" contains the number of current calibration step. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The output list "ome_loop_vector" contains all estimated ome values. + + The output list "calibration_factors" contains all estimated calibration factors. + + :param: paths_and_names: input list of lists + :param: calibration_settings: input list of lists + :param: ome_loop_vector: input list + :param: parameter_for_design_case: input list of lists + :param: calibration_factors: input list + :param: count_of_calibration: input value + :return: calibration_settings: output list of lists, ome_loop_vector: output list, calibration_factors: output list + """ + + ''' imports for python ''' + import os + import sys + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.write_to_log_file import write_to_log_file + from calibration.perform_ome_calibration import perform_ome_calibration + from calibration.save_calibration_results_to_file import save_calibration_results_to_file + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + calibrate_ome_flag = bool(([item for item in calibration_settings if 'calibrate_ome_flag' in item])[-1][-1]) + calibration_target_ome = ([item for item in calibration_settings if 'calibration_target_OME' in item])[-1][-1] + last_ome = ([item for item in calibration_settings if 'current_value' in item])[-1][-1] + + ''' initialize local parameter ''' + log_file_list = [] + function_name = getframeinfo(currentframe()).function + + ''' open and read aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + aircraft_exchange_file + root_of_aircraft_exchange_tree, _ = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, + frame_info.lineno, log_file_list, current_workflow_name) + + current_ome = float(root_of_aircraft_exchange_tree.find( + './analysis/masses_cg_inertia/operating_mass_empty/mass_properties/mass/value').text) + ome_loop_vector.append(current_ome) + + # write results of current calibration loop to workflow log-file + print("* results: ") + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': * results:') + + if last_ome > 0: + residual_ome = abs(1 - last_ome/current_ome) + residual_to_target = abs(1 - current_ome / calibration_target_ome) + print(" (current) OME = " + str(current_ome) + " kg | Res. OME: " + str(residual_ome) + " | Res. to target = " + + str(residual_to_target)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': (current) OME = ' + + str(current_ome) + ' kg | Res. OME: ' + str(residual_ome) + " | Res. to target = " + + str(residual_to_target)) + + else: + residual_ome = abs(1 - last_ome / current_ome) + residual_to_target = abs(1 - current_ome / calibration_target_ome) + print(" (current) OME = " + str(current_ome) + " kg | Res. OME: " + str(residual_ome) + " | Res. to target = " + + str(residual_to_target)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': (current) OME = ' + + str(current_ome) + ' kg | Res. OME: ' + str(residual_ome) + " | Res. to target = " + + str(residual_to_target)) + print(' After ' + str(count_of_calibration) + '. Iteration Value for OME = ' + str(current_ome) + + '. Program aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': After ' + + str(count_of_calibration) + '. Iteration Value for OME = ' + str(current_ome) + + '. Program aborted!') + + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + ([item for item in calibration_settings if 'residual_iteration_value' in item])[-1][-1] = residual_ome + ([item for item in calibration_settings if 'residual_iteration_value_to_target' in item])[-1][-1] = \ + residual_to_target + + # check if current count of calibration is greater than 2 and the calibration flag is equal to 'True' + # -> if true: -> perform ome calibration + if count_of_calibration > 2 and calibrate_ome_flag == 1: + # call function to perform ome calibration + calibration_settings, ome_loop_vector, calibration_factors = \ + perform_ome_calibration(calibration_settings, parameter_for_design_case, ome_loop_vector, + calibration_factors, count_of_calibration, path_of_working_directory_rce, + current_workflow_name) + + ''' set output parameter for next iteration step ''' + ([item for item in calibration_settings if 'last_value' in item])[-1][-1] = last_ome + ([item for item in calibration_settings if 'current_value' in item])[-1][-1] = current_ome + + ''' check if calibration not successful ''' + if calibrate_ome_flag == 1: + ''' save aircraft exchange file of calibration loop to temporary results directory ''' + aircraft_exchange_files_of_ome_calibration = \ + path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/OMEcalibration/' + if not os.path.isdir(aircraft_exchange_files_of_ome_calibration): + os.makedirs(aircraft_exchange_files_of_ome_calibration) + + # save aircraft exchange file of current loop + project_file_name = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_exchange_file + shutil.copy(project_file_name, aircraft_exchange_files_of_ome_calibration + aircraft_exchange_file[:-4] + + '_it' + str(count_of_calibration) + '.xml') + + ''' save calibration results to csv file ''' + if calibrate_ome_flag == 1: + save_calibration_results_to_file(paths_and_names, count_of_calibration, residual_ome, 'OME') + + ''' check if maximum number of iteration is reached ''' + max_iterations_before_exit_ome_calibration =\ + ([item for item in calibration_settings if 'max_iterations_before_exit_OME_calibration' in item])[-1][-1] + if count_of_calibration >= max_iterations_before_exit_ome_calibration: + print(' Maximum number of ' + str(max_iterations_before_exit_ome_calibration) + + ' Iterations reached during OME calibration. No convergence! Abort program!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Maximum number of ' + str(max_iterations_before_exit_ome_calibration) + + ' Iterations reached during OME calibration. No convergence! Abort program!') + + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + # abort program + sys.exit(1) + + return calibration_settings, ome_loop_vector, calibration_factors diff --git a/UNICADOworkflow/src/calibration/read_calibration_parameter.py b/UNICADOworkflow/src/calibration/read_calibration_parameter.py new file mode 100644 index 0000000000000000000000000000000000000000..8b2737bc8742a8387c08ba5d7eb272a0cef80f8e --- /dev/null +++ b/UNICADOworkflow/src/calibration/read_calibration_parameter.py @@ -0,0 +1,113 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def read_calibration_parameter(root_of_workflow_tree): + """ read_calibration_parameter read the calibration settings from workflow configuration file. + Set values to output lists for following workflow components. + + The input element "root_of_workflow_tree" contains the xml-tree of workflow configuration file. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + + :param: root_of_workflow_tree: input element-tree + :return: calibration_settings: output list of lists + """ + + convert_mode_to_int_dict = { + 'mode_0' : int(0), + 'mode_1' : int(1), + 'mode_2' : int(2), + 'mode_3' : int(3), + 'mode_4' : int(4), + 'mode_5' : int(5) + } + + ''' read calibration parameters from given elementTree ''' + free_variable_ome_calibration = convert_mode_to_int_dict[root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/ome_calibration_mode/value").text] + free_variable_mtom_calibration = convert_mode_to_int_dict[root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/mtom_calibration_mode/value").text] + calibration_target_ome = float(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/target_values/ome/value").text) + calibration_target_mtom = float(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/target_values/mtom/value").text) + reset_fuselage_mass_at_start = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/" + "reset_calibration_factors_at_start/reset_fuselage_mass/value").text.lower() in ['true', 'True', '1', 't']) + reset_viscous_drag_counts_at_start = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/" + "reset_calibration_factors_at_start/reset_viscous_drag_counts/value").text.lower() in ['true', 'True', '1', 't']) + reset_engine_fuel_flow_factor_at_start = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/" + "reset_calibration_factors_at_start/reset_engine_fuel_flow_factor/value").text.lower() in ['true', 'True', '1', 't']) + number_of_iterations_before_mtom_calibration = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/iteration_settings/" + "number_of_before_new_mtom_calibration_step/value").text) + max_iterations_before_exit_ome_calibration = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/iteration_settings/" + "max_number_of_iterations_before_ome_calibration_exit/value").text) + trunc_error_factor = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/iteration_settings/" + "factor_for_convergence_criteria/value").text) + damp_mtom_calibration_lever = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/iteration_settings/" + "damp_MTOM_calibration/enable/value").text.lower() in ['true', 'True', '1', 't']) + x_rel_max_for_mtom_damp = float(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/iteration_settings/" + "damp_MTOM_calibration/maximum_mtom_extrapolation_lever/value").text) + damp_ome_calibration_lever = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/iteration_settings/" + "damp_OME_calibration/enable/value").text.lower() in ['true', 'True', '1', 't']) + x_rel_max_for_ome_damp = float(root_of_workflow_tree.find( + "./program_settings/design_case_settings/calibration_settings/iteration_settings/" + "damp_OME_calibration/maximum_ome_extrapolation_lever/value").text) + + ''' save input parameters as a list of lists ''' + calibration_settings = [['free_variable_OME_calibration', free_variable_ome_calibration], + ['free_variable_MTOM_calibration', free_variable_mtom_calibration], + ['calibration_target_OME', calibration_target_ome], + ['calibration_target_mtom', calibration_target_mtom], + ['reset_fuselage_mass_at_start', reset_fuselage_mass_at_start], + ['reset_viscous_drag_counts_at_start', reset_viscous_drag_counts_at_start], + ['reset_engine_fuel_flow_factor_at_start', reset_engine_fuel_flow_factor_at_start], + ['number_of_iterations_before_mtom_calibration', + number_of_iterations_before_mtom_calibration], + ['max_iterations_before_exit_OME_calibration', max_iterations_before_exit_ome_calibration], + ['trunc_Error_factor', trunc_error_factor], + ['damp_MTOM_calibration_lever', damp_mtom_calibration_lever], + ['x_rel_max_for_MTOM_damp', x_rel_max_for_mtom_damp], + ['damp_OME_calibration_lever', damp_ome_calibration_lever], + ['x_rel_max_for_OME_damp', x_rel_max_for_ome_damp]] + + return calibration_settings diff --git a/UNICADOworkflow/src/calibration/reset_free_calibration_variables.py b/UNICADOworkflow/src/calibration/reset_free_calibration_variables.py new file mode 100644 index 0000000000000000000000000000000000000000..827617b5d49cd7e3614e9514e3f2e9cf3499e1ad --- /dev/null +++ b/UNICADOworkflow/src/calibration/reset_free_calibration_variables.py @@ -0,0 +1,160 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def reset_free_calibration_variables(paths_and_names, calibration_settings, log_file_list): + """ reset_free_calibration_variables resets free calibration variables in tool configuration files. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + + The input list "log_file_list" contains all system prints of function: set_configuration_parameter.py. + + The output list "log_file_list" contains all system prints of functions: set_configuration_parameter.py and select_engine_from_existing_project.py. + + :param: paths_and_names: input list of lists + :param: calibration_settings: input list of lists + :param: log_file_list: input list + :return: log_file_list: output list of lists + """ + + ''' imports for python ''' + import sys + from inspect import currentframe, getframeinfo + from datetime import datetime + from sub_function.read_xml_file import read_xml_file + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + free_variable_ome_calibration = \ + int(([item for item in calibration_settings if 'free_variable_OME_calibration' in item])[-1][-1]) + free_variable_mtom_calibration = \ + int(([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1]) + reset_fuselage_mass_at_start = \ + int(([item for item in calibration_settings if 'reset_fuselage_mass_at_start' in item])[-1][-1]) + reset_viscous_drag_counts_at_start = \ + int(([item for item in calibration_settings if 'reset_viscous_drag_counts_at_start' in item])[-1][-1]) + reset_engine_fuel_flow_factor_at_start = \ + int(([item for item in calibration_settings if 'reset_engine_fuel_flow_factor_at_start' in item])[-1][-1]) + + function_name = getframeinfo(currentframe()).function + + ''' reset free variables for calibration mode ''' + # reset free OME calibration variables + if not free_variable_ome_calibration == 0 and reset_fuselage_mass_at_start: + # try to open weight_and_balance_analysis module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/fuselage_design_conf.xml' + root_of_mass_estimation_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + 'fuselage_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # reset fuselage scaling factor in weight_and_balance_analysis configuration file to 1 + root_of_mass_estimation_tree.find( + './program_settings/configuration/fidelity/fuselage_design_tu_berlin/' + 'general/mass_technology_factors/fuselage_structural_mass_technology_factor/value').text = str(1.0) + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + print('For OME calibration fuselage scaling factor in fuselage design configuration file reset to 1.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'For OME calibration fuselage scaling factor in fuselage design configuration file ' + 'reset to 1.') + + # reset free MTOM calibration variables if mtom calibration is active + if not free_variable_mtom_calibration == 0: + # case 1 -> Engine efficiency calibration mode + if reset_engine_fuel_flow_factor_at_start: + # try to open propulsion_design module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/propulsion_design_conf.xml' + root_of_engine_sizing_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + 'propulsion_design', function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + # reset Engine efficiency scaling factor in propulsion_design configuration file to 1 + root_of_engine_sizing_tree.find( + './program_settings/technology_factors/engine_efficiency/value').text = str(1.0) + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + print('For MTOM calibration, engine efficiency factor in propulsion_design configuration file reset to 1.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'For MTOM calibration, engine efficiency scaling factor in propulsion_design ' + 'configuration file reset to 1.') + + # case 2 -> drag count reduction or Engine efficiency calibration mode and drag count reduction + if reset_viscous_drag_counts_at_start: + # try to open aerodynamic_assessment module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/aerodynamic_analysis_conf.xml' + root_of_calculate_polar_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + 'aerodynamic_analysis', function_name, + frame_info.lineno, log_file_list, + current_workflow_name) + + # reset calibration drag count reduction value in aerodynamic_assessment configuration file to 0 + root_of_calculate_polar_tree.find( + './program_settings/ViscDragRaymer/DoDragCountCorrection/value').text = str(bool(1)).lower() + root_of_calculate_polar_tree.find( + './program_settings/ViscDragRaymer/DeltaViscousDragWing/value').text = str(0) + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + print('For MTOM calibration, drag count reduction factor in aerodynamic_analysis configuration file ' + 'reset to 0.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'For MTOM calibration, drag count reduction factor in aerodynamic_analysis ' + 'configuration file reset to 0.') + + return log_file_list diff --git a/UNICADOworkflow/src/calibration/reset_of_values_for_mtom_calibration.py b/UNICADOworkflow/src/calibration/reset_of_values_for_mtom_calibration.py new file mode 100644 index 0000000000000000000000000000000000000000..fe904527a8173fc5616134dc2e5da81573603003 --- /dev/null +++ b/UNICADOworkflow/src/calibration/reset_of_values_for_mtom_calibration.py @@ -0,0 +1,152 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def reset_of_values_for_mtom_calibration(calibration_settings): + """ reset_of_values_for_mtom_calibration resets the iteration parameter to default to perform mtom calibration. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + :param: calibration_settings: input list of lists + :return: calibration_settings: output list of lists + """ + + ''' reset data for mtom calibration mode ''' + # reset convergence tracker + ([item for item in calibration_settings if 'number_reverse_effects' in item])[-1][-1] = int(0) + ([item for item in calibration_settings if 'number_of_final_runs' in item])[-1][-1] = int(1) + + # reset iteration boolean + ([item for item in calibration_settings if 'iteration_flag' in item])[-1][-1] = int(0) + ([item for item in calibration_settings if 'calibration_value_over_target_exist' in item])[-1][-1] = int(0) + ([item for item in calibration_settings if 'calibration_value_under_target_exist' in item])[-1][-1] = int(0) + ([item for item in calibration_settings if 'calibration_value_over_target_update_exist' in item])[-1][-1] = int(0) + ([item for item in calibration_settings if 'calibration_value_under_target_update_exist' in item])[-1][-1] = int(0) + ([item for item in calibration_settings if 'aux_interpolation_flag' in item])[-1][-1] = int(0) + + # reset calibration values + ([item for item in calibration_settings if 'calibration_value_flag' in item])[-1][-1] = float(0.0) + ([item for item in calibration_settings if 'calibration_value_low' in item])[-1][-1] = float(0.0) + ([item for item in calibration_settings if 'calibration_value_high' in item])[-1][-1] = float(0.0) + ([item for item in calibration_settings if 'calibration_value_act' in item])[-1][-1] = float(0.0) + ([item for item in calibration_settings if 'calibration_value_last' in item])[-1][-1] = float(0.0) + + # reset calibration factors + ([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1] = float(0.0) + ([item for item in calibration_settings if 'calibration_factor_flag' in item])[-1][-1] = float(0.0) + ([item for item in calibration_settings if 'calibration_factor_low' in item])[-1][-1] = float(0.0) + ([item for item in calibration_settings if 'calibration_factor_high' in item])[-1][-1] = float(0.0) + ([item for item in calibration_settings if 'calibration_factor_act' in item])[-1][-1] = float(0.0) + ([item for item in calibration_settings if 'calibration_factor_last' in item])[-1][-1] = float(0.0) + + # reset calibration residuals + ([item for item in calibration_settings if 'residual_iteration_value' in item])[-1][-1] = float(0.0) + ([item for item in calibration_settings if 'residual_iteration_value_to_target' in item])[-1][-1] = float(0.0) + + # reset dynamic calibration objects + ([item for item in calibration_settings if 'current_value' in item])[-1][-1] = float(0.0) + ([item for item in calibration_settings if 'last_value' in item])[-1][-1] = float(0.0) + + return calibration_settings diff --git a/UNICADOworkflow/src/calibration/save_calibration_results_to_file.py b/UNICADOworkflow/src/calibration/save_calibration_results_to_file.py new file mode 100644 index 0000000000000000000000000000000000000000..bbe2d2ce5ccd297a419e6ce45c6cbf09b60a4a64 --- /dev/null +++ b/UNICADOworkflow/src/calibration/save_calibration_results_to_file.py @@ -0,0 +1,134 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def save_calibration_results_to_file(paths_and_names, count_of_calibration, residual_to_target, type_of_calibration): + """ check_calibration_value_deviation checks the difference between current calibration value with given target value. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input int "count_of_calibration" contains the current number of calibration loop. + + The input float "residual_to_target" contains the current residual to calibration target. + + The input string "type_of_calibration" contains the name of calibration type. + + :param: paths_and_names: input list of lists + :param: count_of_calibration: input int + :param: residual_to_target: input float + :param: type_of_calibration: input string + :return: none + """ + + ''' imports for python ''' + import os + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.get_mission_energy_specific_segment import get_mission_energy_specific_segment + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce =\ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + ''' initialize local parameter ''' + results = [] + log_file_list = [] + function_name = getframeinfo(currentframe()).function + reporting_of_ome_calibration = path_of_working_directory_rce + current_workflow_name\ + + '/temporaryResults/reporting/' + + ''' open and read aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + aircraft_exchange_file + root_of_aircraft_exchange_tree, _ = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + if type_of_calibration == 'OME': + m_take_off_max = root_of_aircraft_exchange_tree.find( + "./analysis/masses_cg_inertia/maximum_takeoff_mass/mass_properties/mass/value") + if m_take_off_max is not None: + m_take_off_max = float(m_take_off_max.text) + else: + m_take_off_max = 0 + + m_operating_empty = root_of_aircraft_exchange_tree.find( + "./analysis/masses_cg_inertia/operating_mass_empty/mass_properties/mass/value") + if m_operating_empty is not None: + m_operating_empty = float(m_operating_empty.text) + else: + m_operating_empty = 0 + + mission_energy = get_mission_energy_specific_segment( + root_of_aircraft_exchange_tree, 'design_mission', 'loaded_mission_energy/mission_energy') + + x_center_of_gravity = root_of_aircraft_exchange_tree.find( + "./analysis/masses_cg_inertia/maximum_takeoff_mass/mass_properties/center_of_gravity/x/value") + if x_center_of_gravity is not None: + x_center_of_gravity = float(x_center_of_gravity.text) + else: + x_center_of_gravity = 0 + + if count_of_calibration == 0: + if not os.path.isdir(reporting_of_ome_calibration): + os.makedirs(reporting_of_ome_calibration) + + results.append('count_of_iteration; ' + 'm_take_off_max in kg; ' + 'residual_m_take_off_max; ' + 'm_operating_empty in kg; ' + 'residual_m_operating_empty; ' + 'mission_energy in J; ' + 'residual_mission_energy; ' + 'x_center_of_gravity in m; ' + 'residual_x_center_of_gravity;') + + results.append(str(count_of_calibration) + ';' + + str(round(m_take_off_max, 2)) + ';' + + 'nan;' + + str(round(m_operating_empty, 2)) + ';' + + str(round(residual_to_target, 6)) + ';' + + str(round(mission_energy, 2)) + ';' + + 'nan;' + + str(round(x_center_of_gravity, 3)) + ';' + + 'nan;') + + results_file = open(reporting_of_ome_calibration + 'OME_calibration_results.csv', 'a') + for row in results: + results_file.write(row + '\n') + results_file.close() + + return diff --git a/UNICADOworkflow/src/calibration/set_calibration_factor.py b/UNICADOworkflow/src/calibration/set_calibration_factor.py new file mode 100644 index 0000000000000000000000000000000000000000..8b3143b59e4205fe1dd29e934a40dd409b72607b --- /dev/null +++ b/UNICADOworkflow/src/calibration/set_calibration_factor.py @@ -0,0 +1,140 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def set_calibration_factor(calibration_settings, calibration_factors, count_of_calibration, execution_number): + """ perform_ome_calibration performs the ome calibration. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input list "calibration_factors" contains all estimated calibration factors. + + The input int "count_of_calibration" contains the current number of calibration loop. + + The input int "execution_number" contains the execution number of current function. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The output list "calibration_factors" contains all estimated calibration factors. + + :param: calibration_settings: input list of lists + :param: calibration_factors: input list + :param: count_of_calibration: input value + :param: execution_number: input int + :return: calibration_settings: output list of lists, calibration_factors: output list + """ + + ''' set calibration factors ''' + # check if the current calibration the first calibration of current loop + calibration_factor_act = calibration_factors[-1] + if count_of_calibration == execution_number: + calibration_factor_last = calibration_factor_act + + else: + calibration_factor_last = calibration_factors[-2] + + ''' set output parameter for next iteration step ''' + ([item for item in calibration_settings if 'calibration_factor_last' in item])[-1][-1] = calibration_factor_last + ([item for item in calibration_settings if 'calibration_factor_act' in item])[-1][-1] = calibration_factor_act + + return calibration_settings, calibration_factors diff --git a/UNICADOworkflow/src/calibration/set_calibration_values.py b/UNICADOworkflow/src/calibration/set_calibration_values.py new file mode 100644 index 0000000000000000000000000000000000000000..a01cdda228fafef31c7f9bffc8333cb59bd0bc90 --- /dev/null +++ b/UNICADOworkflow/src/calibration/set_calibration_values.py @@ -0,0 +1,198 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def set_calibration_values(calibration_settings, value_loop_vector, type_of_calibration, + convergence_criteria, count_of_calibration, path_of_working_directory_rce, + current_workflow_name='UNICADOworkflow'): + """ set_calibration_values sets values and factors for next calibration loop. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input list "value_loop_vector" contains all estimated ome values. + + The input value "type_of_calibration" contains the string of name of current calibration mode. + + The input value "count_of_calibration" contains the current number of calibration loop. + + The input float "convergence_criteria" contains the given convergence criteria for calibration iteration. + + The input string "path_of_working_directory_rce" contains the system path to rce working directory. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + :param: calibration_settings: input list of lists + :param: value_loop_vector: input list + :param: type_of_calibration: input string + :param: count_of_calibration: input value# + :param: convergence_criteria: input value + :param: path_of_working_directory_rce: input string + :param: current_workflow_name: input string + :return: calibration_settings: output list of lists + """ + + ''' imports for python ''' + from datetime import datetime + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + number_of_iterations_before_mtom_calibration = \ + int(([item for item in calibration_settings if 'number_of_iterations_before_mtom_calibration' in item])[-1][-1]) + residual_ome_to_target = \ + ([item for item in calibration_settings if 'residual_iteration_value_to_target' in item])[-1][-1] + calibration_target_mtom = ([item for item in calibration_settings if 'calibration_target_mtom' in item])[-1][-1] + trunc_error_factor = ([item for item in calibration_settings if 'trunc_Error_factor' in item])[-1][-1] + calibration_value_act = float() + calibration_value_last = float() + + ''' initialize local parameter ''' + log_file_list = [] + + if type_of_calibration == 'OME': + print('* OME-calibration: ') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': * OME-calibration: ') + + calibration_value_act = value_loop_vector[-1] + calibration_value_last = value_loop_vector[-2] + print(' OME(' + str(count_of_calibration) + ') = ' + str(calibration_value_act) + 'kg | OME(' + + str(count_of_calibration - 1) + ') = ' + str(calibration_value_last) + 'kg | Res. OME(act)2target = ' + + str(residual_ome_to_target * 100) + ' % (Limit = ' + + str(convergence_criteria * trunc_error_factor * 100) + '%).') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'OME(' + str(count_of_calibration) + ') = ' + str(calibration_value_act) + 'kg | OME(' + + str(count_of_calibration - 1) + ') = ' + str(calibration_value_last) + + 'kg | Res. OME(act)2target = ' + str(residual_ome_to_target * 100) + ' % (Limit = ' + + str(convergence_criteria * trunc_error_factor * 100) + '%).') + + if type_of_calibration == 'MTOM': + print('* MTOM-calibration: ') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': * MTOM-calibration: ') + + last_calibration_id = len(value_loop_vector) - number_of_iterations_before_mtom_calibration + if last_calibration_id > 1: # after first calibration step compare to converged MTOM of previous calibration + last_calibration_id -= 1 + calibration_value_act = value_loop_vector[-1] + calibration_value_last = value_loop_vector[int(last_calibration_id)] + residual_mtom_to_target = abs(1 - calibration_value_act / calibration_target_mtom) + print(' MTOM(' + str(count_of_calibration) + ') = ' + str(calibration_value_act) + 'kg | MTOM(' + + str(last_calibration_id) + ') = ' + + str(calibration_value_last) + 'kg | Res. MTOM(act)2target = ' + str(residual_mtom_to_target * 100) + + ' % (Limit = ' + str(convergence_criteria * trunc_error_factor * 100) + '%).') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': MTOM(' + str(count_of_calibration) + + ') = ' + str(calibration_value_act) + 'kg | MTOM(' + + str(last_calibration_id) + + ') = ' + str(calibration_value_last) + 'kg | Res. MTOM(act)2target = ' + + str(residual_mtom_to_target * 100) + ' % (Limit = ' + + str(convergence_criteria * trunc_error_factor * 100) + '%).') + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + ''' set output parameter for next iteration step ''' + ([item for item in calibration_settings if 'calibration_value_act' in item])[-1][-1] = calibration_value_act + ([item for item in calibration_settings if 'calibration_value_last' in item])[-1][-1] = calibration_value_last + + return calibration_settings diff --git a/UNICADOworkflow/src/calibration/set_lever_arm.py b/UNICADOworkflow/src/calibration/set_lever_arm.py new file mode 100644 index 0000000000000000000000000000000000000000..bffdec53a5daa22eec88a1580a978f565d9ce70f --- /dev/null +++ b/UNICADOworkflow/src/calibration/set_lever_arm.py @@ -0,0 +1,243 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def set_lever_arm(calibration_settings, type_of_calibration, path_of_working_directory_rce, + current_workflow_name='UNICADOworkflow'): + """ check_calibration_value_target checks the the actual calibration value against the target calibration value. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input value "type_of_calibration" contains the string of name of current calibration mode. + + The input string "path_of_working_directory_rce" contains the system path to rce working directory. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + :param: calibration_settings: input list of lists + :param: type_of_calibration: input value + :param: path_of_working_directory_rce: input string + :param: current_workflow_name: input string + :return: calibration_settings: output list of lists, calibration_factors: output list + """ + + ''' imports for python ''' + from datetime import datetime + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + calibration_target_ome = ([item for item in calibration_settings if 'calibration_target_OME' in item])[-1][-1] + calibration_target_mtom = ([item for item in calibration_settings if 'calibration_target_mtom' in item])[-1][-1] + calibration_value_flag = ([item for item in calibration_settings if 'calibration_value_flag' in item])[-1][-1] + calibration_value_act = ([item for item in calibration_settings if 'calibration_value_act' in item])[-1][-1] + x_relative = ([item for item in calibration_settings if 'x_relative' in item])[-1][-1] + x_rel_max_for_ome_damp = ([item for item in calibration_settings if 'x_rel_max_for_OME_damp' in item])[-1][-1] + x_rel_max_for_mtom_damp = ([item for item in calibration_settings if 'x_rel_max_for_MTOM_damp' in item])[-1][-1] + damp_ome_calibration_lever =\ + ([item for item in calibration_settings if 'damp_OME_calibration_lever' in item])[-1][-1] + damp_mtom_calibration_lever =\ + ([item for item in calibration_settings if 'damp_MTOM_calibration_lever' in item])[-1][-1] + + ''' initialize local parameter ''' + log_file_list = [] + + if type_of_calibration == 'MTOM': + x_relative = (calibration_target_mtom - calibration_value_flag) / \ + (calibration_value_act - calibration_value_flag) + + if x_relative > x_rel_max_for_mtom_damp and damp_mtom_calibration_lever == 1: + print(' Warning! The switch Damp_MTOM_Calibration_Lever is on! x_rel = ' + '(MTOM_target-MTOM_flag)/(MTOM_act-MTOM_flag) = ' + str(x_relative) + + ' is higher than the set x_rel_max.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Warning! The switch Damp_MTOM_Calibration_Lever is on! x_rel = ' + '(MTOM_target-MTOM_flag)/(MTOM_act-MTOM_flag) = ' + str(x_relative) + + ' is higher than the set x_rel_max.') + + x_relative = x_rel_max_for_mtom_damp + + if x_relative < 0 or x_relative > 1: + print(' x_rel is now capped at = ' + str(x_relative) + ' -> Extrapolation!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': x_rel is now capped at= ' + str(x_relative) + ' -> Extrapolation!') + else: + print(' x_rel is now capped at = ' + str(x_relative) + '.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': x_rel is now capped at= ' + str(x_relative) + '.') + + elif x_relative <= x_rel_max_for_mtom_damp and damp_mtom_calibration_lever == 1: + print(' Warning! The switch Damp_MTOM_Calibration_Lever is on! x_rel = ' + 'MTOM_target-MTOM_flag)/(MTOM_act-MTOM_flag)= ' + str(x_relative) + + ' is lower than x_rel_max and not damped.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Warning! The switch Damp_MTOM_Calibration_Lever is on! x_rel = ' + '(MTOM_target-MTOM_flag)/(MTOM_act-MTOM_flag)= ' + str(x_relative) + + ' is lower than x_rel_max and not damped.') + + else: + if x_relative < 0 or x_relative > 1: + print(' x_rel = (MTOM_target-MTOM_flag)/(MTOM_act-MTOM_flag) = ' + str(x_relative) + + ' -> Extrapolation!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': x_rel = (MTOM_target-MTOM_flag)/(MTOM_act-OME_flag) = ' + str(x_relative) + + ' -> Extrapolation!') + else: + print(' x_rel = (MTOM_target-MTOM_flag)/(MTOM_act-MTOM_flag) = ' + str(x_relative) + '.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': x_rel = (MTOM_target-MTOM_flag)/(MTOM_act-MTOM_flag) = ' + + str(x_relative) + '.') + + if type_of_calibration == 'OME': + x_relative = (calibration_target_ome - calibration_value_flag) / \ + (calibration_value_act - calibration_value_flag) + + if x_relative > x_rel_max_for_ome_damp and damp_ome_calibration_lever == 1: + print(' Warning! The switch Damp_OME_Calibration_Lever is on! x_rel = ' + '(OME_target-OME_flag)/(OME_act-OME_flag) = ' + str(x_relative) + + ' is higher than the set x_rel_max.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Warning! The switch Damp_OME_Calibration_Lever is on! x_rel = ' + '(OME_target-OME_flag)/(OME_act-OME_flag) = ' + str(x_relative) + + ' is higher than the set x_rel_max.') + + x_relative = x_rel_max_for_ome_damp + + if x_relative < 0 or x_relative > 1: + print(' x_rel is now capped at = ' + str(x_relative) + ' -> Extrapolation!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': x_rel is now capped at= ' + str(x_relative) + ' -> Extrapolation!') + else: + print(' x_rel is now capped at = ' + str(x_relative) + '.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': x_rel is now capped at= ' + str(x_relative) + '.') + + elif x_relative <= x_rel_max_for_ome_damp and damp_ome_calibration_lever == 1: + print(' Warning! The switch Damp_OME_Calibration_Lever is on! x_rel = ' + '(OME_target-OME_flag)/(OME_act-OME_flag)= ' + str(x_relative) + + ' is lower than x_rel_max and not damped.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Warning! The switch Damp_OME_Calibration_Lever is on! x_rel = ' + '(OME_target-OME_flag)/(OME_act-OME_flag)= ' + str(x_relative) + + ' is lower than x_rel_max and not damped.') + + else: + if x_relative < 0 or x_relative > 1: + print(' x_rel = (OME_target-OME_flag)/(OME_act-OME_flag) = ' + str(x_relative) + ' -> Extrapolation!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': x_rel = (OME_target-OME_flag)/(OME_act-OME_flag) = ' + str(x_relative) + + ' -> Extrapolation!') + else: + print(' x_rel = (OME_target-OME_flag)/(OME_act-OME_flag) = ' + str(x_relative) + '.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': x_rel = (OME_target-OME_flag)/(OME_act-OME_flag) = ' + str(x_relative) + '.') + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + ''' set output parameter for next iteration step ''' + ([item for item in calibration_settings if 'x_relative' in item])[-1][-1] = float(x_relative) + + return calibration_settings diff --git a/UNICADOworkflow/src/calibration/set_new_calibration_factor.py b/UNICADOworkflow/src/calibration/set_new_calibration_factor.py new file mode 100644 index 0000000000000000000000000000000000000000..e373fdc7c18087546c15b0851813a30ac556275a --- /dev/null +++ b/UNICADOworkflow/src/calibration/set_new_calibration_factor.py @@ -0,0 +1,343 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def set_new_calibration_factor(calibration_settings, calibration_factors, residual_mission_energy, count_of_calibration, + convergence_criteria, type_of_calibration, path_of_working_directory_rce, + current_workflow_name='UNICADOworkflow'): + """ check_calibration_value_target checks the the actual calibration value against the target calibration value. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input list "calibration_factors" contains all estimated calibration factors. + + The input float "residual_mission_energy" contains the residual of mission energy mass of current iteration loop. + + The input int "count_of_calibration" contains the execution number of current function. + + The input float "convergence_criteria" contains the given convergence criteria for calibration iteration. + + The input value "type_of_calibration" contains the string of name of current calibration mode. + + The input string "path_of_working_directory_rce" contains the system path to rce working directory. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The output list "calibration_factors" contains all estimated calibration factors. + + :param: calibration_settings: input list of lists + :param: calibration_factors: input list + :param: residual_mission_energy: input float + :param: count_of_calibration: input int + :param: convergence_criteria: input float + :param: type_of_calibration: input value + :param: path_of_working_directory_rce: input int + :param: current_workflow_name: input string + :return: calibration_settings: output list of lists, calibration_factors: output list + """ + + ''' imports for python ''' + import sys + from datetime import datetime + from calibration.set_lever_arm import set_lever_arm + from calibration.set_new_calibration_flag import set_new_calibration_flag + from calibration.check_number_of_iterations import check_number_of_iterations + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + calibration_target_ome = ([item for item in calibration_settings if 'calibration_target_OME' in item])[-1][-1] + calibration_target_mtom = ([item for item in calibration_settings if 'calibration_target_mtom' in item])[-1][-1] + calibration_value_act = ([item for item in calibration_settings if 'calibration_value_act' in item])[-1][-1] + calibration_factor_temp = \ + float(([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1]) + calibration_factor_last = ([item for item in calibration_settings if 'calibration_factor_last' in item])[-1][-1] + calibration_factor_act = ([item for item in calibration_settings if 'calibration_factor_act' in item])[-1][-1] + free_variable_mtom_calibration = \ + int(([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1]) + + ''' initialize local parameter ''' + log_file_list = [] + print(' Calibration factor (act) = ' + str(calibration_factor_act) + ' | Calibration factor (last) = ' + + str(calibration_factor_last) + '.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Calibration factor (act) = ' + + str(calibration_factor_act) + ' | Calibration factor (last) = ' + + str(calibration_factor_last) + '.') + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + log_file_list = [] + + ''' set mtom calibration factors ''' + if type_of_calibration == 'MTOM': + number_of_iterations_before_mtom_calibration = \ + int(([item for item in calibration_settings + if 'number_of_iterations_before_mtom_calibration' in item])[-1][-1]) + + # check if the current calibration the first mtom calibration of current project + if count_of_calibration == number_of_iterations_before_mtom_calibration: + calibration_value_flag = calibration_value_act + if calibration_value_act >= calibration_target_mtom: + if free_variable_mtom_calibration == 1: + calibration_factor_temp *= 1.04 + else: + calibration_factor_temp -= 4.0 + else: + if free_variable_mtom_calibration == 1: + calibration_factor_temp *= 0.96 + else: + calibration_factor_temp += 4.0 + + ([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1] = \ + float(calibration_factor_temp) + ([item for item in calibration_settings if 'calibration_value_flag' in item])[-1][-1] = \ + float(calibration_value_flag) + + if free_variable_mtom_calibration == 1: + print(' Engine efficiency fact. (new), after 1. Cal.-Run = ' + str(calibration_factor_temp)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Engine efficiency fact. (new), after 1. Cal.-Run = ' + + str(calibration_factor_temp)) + else: + print(' Aero fact. (new), after 1. Cal.-Run = ' + str(calibration_factor_temp)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Aero fact. (new), after 1. Cal.-Run = ' + str(calibration_factor_temp)) + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + else: + # call function to check which number of mtom calibration iteration is performed + calibration_settings = check_number_of_iterations(calibration_settings, residual_mission_energy, + convergence_criteria, 'MTOM', + path_of_working_directory_rce, current_workflow_name) + + # call function to set the lever arm for ome calibration + calibration_settings = set_lever_arm(calibration_settings, 'MTOM', path_of_working_directory_rce) + + # determine new calibration factor + calibration_value_act = \ + ([item for item in calibration_settings if 'calibration_value_act' in item])[-1][-1] + calibration_value_flag = \ + ([item for item in calibration_settings if 'calibration_value_flag' in item])[-1][-1] + calibration_factor_flag = \ + ([item for item in calibration_settings if 'calibration_factor_flag' in item])[-1][-1] + calibration_factor_act = \ + ([item for item in calibration_settings if 'calibration_factor_act' in item])[-1][-1] + x_relative = ([item for item in calibration_settings if 'x_relative' in item])[-1][-1] + + if free_variable_mtom_calibration == 1: + # check if the current running calibration in an infinite loop + # -> if true: -> print a warning and perform specific exception handling + if ((calibration_factor_act > calibration_factor_flag + and calibration_value_act > calibration_value_flag) + or (calibration_factor_act < calibration_factor_flag + and calibration_value_act < calibration_value_flag)): + print(' Warning! Reverse effect occurred during inter-/extrapolation.') + print(' Warning! Set x_re = -x_rel = -' + str(x_relative) + ' !') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning! Reverse effect occurred during inter-/extrapolation.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning! Set x_re = -x_rel = -' + str(x_relative) + ' !') + + x_relative *= -1 + + calibration_factor_temp = (1 - x_relative) * calibration_factor_flag \ + + x_relative * calibration_factor_act + print(' Engine efficiency fact. (new) = ' + str(calibration_factor_temp)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Engine efficiency fact. (new) = ' + str(calibration_factor_temp)) + + else: + calibration_factor_temp = (1 - x_relative) * calibration_factor_flag \ + + x_relative * calibration_factors[-1] + print(' Aero fact. (new) = ' + str(calibration_factor_temp)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Aero fact. (new) = ' + str(calibration_factor_temp)) + + ([item for item in calibration_settings if 'x_relative' in item])[-1][-1] = x_relative + ([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1] = \ + calibration_factor_temp + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + # call function to set the values for next run flags for next iteration loop + calibration_settings = set_new_calibration_flag(calibration_settings, calibration_factors, 'MTOM', + path_of_working_directory_rce, current_workflow_name) + + ''' set ome calibration factors ''' + if type_of_calibration == 'OME': + # check if the current calibration the first ome calibration of current project + if (count_of_calibration - 1) == 2: + calibration_value_flag = calibration_value_act + if calibration_value_act >= calibration_target_ome: + calibration_factor_temp *= 0.96 + else: + calibration_factor_temp *= 1.04 + + ([item for item in calibration_settings if 'calibration_value_flag' in item])[-1][-1] =\ + calibration_value_flag + ([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1] =\ + calibration_factor_temp + + print(' Fuselage fact. (new), after 1. Cal.-Run = ' + str(calibration_factor_temp)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Fuselage fact. (new), after 1. Cal.-Run = ' + str(calibration_factor_temp)) + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + else: + # call function to check which number of ome calibration iteration is performed + calibration_settings = check_number_of_iterations(calibration_settings, 0.00, convergence_criteria, 'OME', + path_of_working_directory_rce, current_workflow_name) + + # call function to set the lever arm for ome calibration + calibration_settings = set_lever_arm(calibration_settings, 'OME', path_of_working_directory_rce, + current_workflow_name) + + # determine new calibration factor + calibration_value_act =\ + ([item for item in calibration_settings if 'calibration_value_act' in item])[-1][-1] + calibration_value_flag =\ + ([item for item in calibration_settings if 'calibration_value_flag' in item])[-1][-1] + calibration_factor_flag =\ + ([item for item in calibration_settings if 'calibration_factor_flag' in item])[-1][-1] + calibration_factor_act =\ + ([item for item in calibration_settings if 'calibration_factor_act' in item])[-1][-1] + x_relative = ([item for item in calibration_settings if 'x_relative' in item])[-1][-1] + + # check if the current running calibration in an infinite loop + # -> if true: -> print a warning and perform specific exception handling + if ((calibration_factor_act > calibration_factor_flag and calibration_value_act < calibration_value_flag) or + (calibration_factor_act < calibration_factor_flag and calibration_value_act > calibration_value_flag)): + print(' Warning! Reverse effect occurred during inter-/extrapolation.') + print(' Warning! Set x_re = -x_rel = -' + str(x_relative) + ' !') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning! Reverse effect occurred during inter-/extrapolation.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning! Set x_re = -x_rel = -' + str(x_relative) + ' !') + + x_relative *= -1 + + calibration_factor_temp = (1 - x_relative) * calibration_factor_flag + x_relative * calibration_factor_act + ([item for item in calibration_settings if 'x_relative' in item])[-1][-1] = x_relative + ([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1] = \ + calibration_factor_temp + + print(' Fuselage mass fact. (new) = ' + str(calibration_factor_temp)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Fuselage mass fact. (new) = ' + + str(calibration_factor_temp)) + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + # call function to set the values for next run flags for next iteration loop + calibration_settings = set_new_calibration_flag(calibration_settings, calibration_factors, 'OME', + path_of_working_directory_rce, current_workflow_name) + + return calibration_settings, calibration_factors diff --git a/UNICADOworkflow/src/calibration/set_new_calibration_flag.py b/UNICADOworkflow/src/calibration/set_new_calibration_flag.py new file mode 100644 index 0000000000000000000000000000000000000000..a2160c61097ba3003dc72aa2a2ca2b97e7a9fa8c --- /dev/null +++ b/UNICADOworkflow/src/calibration/set_new_calibration_flag.py @@ -0,0 +1,184 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def set_new_calibration_flag(calibration_settings, calibration_factors, type_of_calibration, + path_of_working_directory_rce, current_workflow_name='UNICADOworkflow'): + """ check_calibration_value_target checks the the actual calibration value against the target calibration value. + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input list "calibration_factors" contains all estimated calibration factors. + + The input value "type_of_calibration" contains the string of name of current calibration mode. + + The input string "path_of_working_directory_rce" contains the system path to rce working directory. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + :param: calibration_settings: input list of lists + :param: calibration_factors: input list + :param: type_of_calibration: input value + :param: path_of_working_directory_rce: input int + :param: current_workflow_name: input string + :return: calibration_settings: output list of lists, calibration_factors: output list + """ + + ''' imports for python ''' + from datetime import datetime + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + calibration_target_ome = ([item for item in calibration_settings if 'calibration_target_OME' in item])[-1][-1] + calibration_target_mtom = ([item for item in calibration_settings if 'calibration_target_mtom' in item])[-1][-1] + calibration_value_flag = ([item for item in calibration_settings if 'calibration_value_flag' in item])[-1][-1] + calibration_value_act = ([item for item in calibration_settings if 'calibration_value_act' in item])[-1][-1] + calibration_value_last = ([item for item in calibration_settings if 'calibration_value_last' in item])[-1][-1] + calibration_factor_flag = ([item for item in calibration_settings if 'calibration_factor_flag' in item])[-1][-1] + calibration_factor_last = ([item for item in calibration_settings if 'calibration_factor_last' in item])[-1][-1] + calibration_factor_act = ([item for item in calibration_settings if 'calibration_factor_act' in item])[-1][-1] + free_variable_mtom_calibration = \ + ([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1] + + ''' initialize local parameter ''' + log_file_list = [] + + if type_of_calibration == 'MTOM': + if abs(calibration_value_act - calibration_target_mtom) > abs(calibration_value_last - calibration_target_mtom): + calibration_value_flag = calibration_value_last + if free_variable_mtom_calibration == 1: + calibration_factor_flag = calibration_factor_last + else: + calibration_factor_flag = calibration_factors[-2] + + else: + calibration_value_flag = calibration_value_act + if free_variable_mtom_calibration == 1: + calibration_factor_flag = calibration_factor_act + else: + calibration_factor_flag = calibration_factors[-1] + + if type_of_calibration == 'OME': + if abs(calibration_value_act - calibration_target_ome) > abs(calibration_value_last - calibration_target_ome): + calibration_value_flag = calibration_value_last + calibration_factor_flag = calibration_factor_last + + else: + calibration_value_flag = calibration_value_act + calibration_factor_flag = calibration_factor_act + + print(' Set calibration factor flag: ' + str(calibration_factor_flag)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Set calibration factor flag: ' + str(calibration_factor_flag)) + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + ''' set output parameter for next iteration step ''' + ([item for item in calibration_settings if 'calibration_value_flag' in item])[-1][-1] = calibration_value_flag + ([item for item in calibration_settings if 'calibration_factor_flag' in item])[-1][-1] = calibration_factor_flag + + return calibration_settings diff --git a/UNICADOworkflow/src/calibration/set_settings_for_mtom_calibration.py b/UNICADOworkflow/src/calibration/set_settings_for_mtom_calibration.py new file mode 100644 index 0000000000000000000000000000000000000000..4adba55d3852de46872f8e94c0d066d78052bd8a --- /dev/null +++ b/UNICADOworkflow/src/calibration/set_settings_for_mtom_calibration.py @@ -0,0 +1,227 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def set_settings_for_mtom_calibration(paths_and_names, calibration_settings, calibration_factors): + """ set_settings_for_mtom_calibration initializes the iteration parameter to perform mtom calibration mode. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input list "calibration_factors" contains all estimated calibration factors of mtom calibration. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The output list "calibration_factors" contains all estimated calibration factors of mtom calibration. + + :param: paths_and_names: input list of lists + :param: calibration_settings: input list of lists + :param: calibration_factors: input list + :return: calibration_settings: output list of lists + """ + + ''' imports for python ''' + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.write_to_log_file import write_to_log_file + from calibration.reset_of_values_for_mtom_calibration import reset_of_values_for_mtom_calibration + + ''' read data for script execution ''' + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce =\ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + free_variable_mtom_calibration =\ + int(([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1]) + + ''' initialize local parameter ''' + log_file_list = [] + fuel_flow_factor = float(0.0) + drag_reduction_factor = float(0.0) + function_name = getframeinfo(currentframe()).function + + ''' reset iteration parameter for mtom calibration ''' + calibration_settings = reset_of_values_for_mtom_calibration(calibration_settings) + + ''' initialize iteration parameter to perform mtom calibration ''' + print('Step 2: Calibrate MTOM will be performed during design sizing loop!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Step 2: Calibrate MTOM will be performed during design sizing loop!') + + # set mtom calibration flag to "true" + ([item for item in calibration_settings if 'calibrate_mtom_flag' in item])[-1][-1] = int(1) + + # check if free_variable_MTOM_calibration selector is equal to 1 -> if true: -> perform engine calibration + if free_variable_mtom_calibration == 1: + print(' Engine calibration is selected and will performed!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Engine calibration is selected and will performed!') + + # try to open propulsion_design module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/propulsion_design_conf.xml' + root_of_engine_sizing_tree, _ = read_xml_file(path, path_of_working_directory_rce, 'propulsion_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # read engine efficiency factor from propulsion_design configuration file + fuel_flow_factor = float(root_of_engine_sizing_tree.find( + './program_settings/technology_factors/engine_efficiency/value').text) + + # save initial iteration factor to list of calibration settings + ([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1] = fuel_flow_factor + ([item for item in calibration_settings if 'calibration_factor_flag' in item])[-1][-1] = fuel_flow_factor + calibration_factors[-1] = fuel_flow_factor + + # else if condition: check if free_variable_MTOM_calibration selector is equal to 2 + # -> if true: -> perform aerodynamic calibration + else: + print(' Aerodynamic calibration is selected and will performed!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Aerodynamic calibration is selected and will performed!') + + # try to open aerodynamic_assessment module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/aerodynamic_analysis_conf.xml' + root_of_calculate_polar_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + 'aerodynamic_analysos', function_name, + frame_info.lineno, log_file_list, current_workflow_name) + + # read drag count reduction factor for viscous wing drag from aerodynamic_analysis configuration file + drag_reduction_factor = float(root_of_calculate_polar_tree.find( + './program_settings/ViscDragRaymer/DeltaViscousDragWing/value').text) + # activate drag count reduction in aerodynamic_analysis module + root_of_calculate_polar_tree.find( + './program_settings/ViscDragRaymer/DoDragCountCorrection/value').text = str(bool(1)).lower() + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + # save initial iteration factor to list of calibration settings + ([item for item in calibration_settings if 'calibration_factor_temp' in item])[-1][-1] = drag_reduction_factor + ([item for item in calibration_settings if 'calibration_factor_flag' in item])[-1][-1] = drag_reduction_factor + calibration_factors[-1] = drag_reduction_factor + + ''' append calibration factors to list of calibration settings ''' + calibration_settings.append(['fuel_flow_factor', fuel_flow_factor]) + calibration_settings.append(['drag_reduction_factor', drag_reduction_factor]) + + # write function output to workflow log file + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + return calibration_settings, calibration_factors diff --git a/UNICADOworkflow/src/calibration/set_settings_for_ome_calibration.py b/UNICADOworkflow/src/calibration/set_settings_for_ome_calibration.py new file mode 100644 index 0000000000000000000000000000000000000000..4a0210188bc28450552cb174f4580feb2920fedb --- /dev/null +++ b/UNICADOworkflow/src/calibration/set_settings_for_ome_calibration.py @@ -0,0 +1,195 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def set_settings_for_ome_calibration(paths_and_names, calibration_settings, log_file_list): + """ set_settings_for_ome_calibration initialized calibration variables for OME calibration. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + + The input list "log_file_list" contains all system prints of function: set_configuration_parameter.py. + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The output list "log_file_list" contains all system prints of functions: set_configuration_parameter.py and select_engine_from_existing_project.py. + + :param: paths_and_names: input list of lists + :param: calibration_settings: input list of lists + :param: log_file_list: input list + :return: calibration_settings: output list of lists, log_file_list: output list + """ + + ''' imports for python ''' + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from calibration.check_tools_for_ome_calibration import check_tools_for_ome_calibration + from calibration.initialize_parameter_for_calibration import initialize_parameter_for_calibration + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + free_variable_ome_calibration = \ + int(([item for item in calibration_settings if 'free_variable_OME_calibration' in item])[-1][-1]) + calibration_target_ome = ([item for item in calibration_settings if 'calibration_target_OME' in item])[-1][-1] + + ''' initialize local parameter ''' + current_ome = 0 + final_fuselage_mass_factor = int(1) + function_name = getframeinfo(currentframe()).function + + ''' check if OME calibration is switched off (mode_0: int(0)) -> if true: -> set OME calibration flag to "False" ''' + if free_variable_ome_calibration == 0: + ''' initialize parameter for ome calibration ''' + calibration_settings = initialize_parameter_for_calibration(paths_and_names, calibration_settings, + log_file_list) + + print('OME-Calibration is skipped due to setting in workflow configuration file!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'OME-Calibration is skipped due to setting in workflow configuration file!') + + # try to open weight_and_balance_analysis module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/fuselage_design_conf.xml' + root_of_mass_estimation_tree, _ = read_xml_file(path, path_of_working_directory_rce, 'fuselage_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # read fuselage scaling factor from weight_and_balance_analysis configuration file + final_fuselage_mass_factor = root_of_mass_estimation_tree.find( + './program_settings/configuration/fidelity/fuselage_design_tu_berlin/' + 'general/mass_technology_factors/fuselage_structural_mass_technology_factor/value').text + calibrate_ome_flag = 0 + + else: + calibrate_ome_flag, log_file_list = check_tools_for_ome_calibration(paths_and_names, log_file_list) + + if calibrate_ome_flag == 1: + ''' initialize parameter for ome calibration ''' + calibration_settings = initialize_parameter_for_calibration(paths_and_names, calibration_settings, + log_file_list) + + # output print for first calibration step + print('Step 1: Calibrate OME for target-MTOM! \n ' + ' OME: ' + str(calibration_target_ome) + ' kg \n ' + ' (Calibration OME via fuselage mass in file: weight_and_balance_analysis_conf.xml)') + log_file_list.append('') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Step 1: Calibrate OME for target-MTOM! \n' + ' OME: ' + str(calibration_target_ome) + ' kg \n' + ' (Calibration OME via fuselage mass in file: ' + 'weight_and_balance_analysis_conf.xml) \n') + + # try to open weight_and_balance_analysis module configuration file + ''' open and read aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_exchange_file + root_of_aircraft_exchange_tree, _ = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, + frame_info.lineno, log_file_list) + + current_ome = float(root_of_aircraft_exchange_tree.find( + './analysis/masses_cg_inertia/operating_mass_empty/mass_properties/mass/value').text) + + ''' extend table for calibration settings ''' + calibration_settings.append(['calibrate_ome_flag', int(calibrate_ome_flag)]) + calibration_settings.append(['calibrate_mtom_flag', int(0)]) + calibration_settings.append(['final_fuselage_mass_factor', final_fuselage_mass_factor]) + calibration_settings.append(['current_value', current_ome]) + calibration_settings.append(['last_value', current_ome]) + calibration_settings.append(['iteration_flag', int(0)]) + + return calibration_settings, log_file_list diff --git a/UNICADOworkflow/src/clean_up/clean_up_temporary_results.py b/UNICADOworkflow/src/clean_up/clean_up_temporary_results.py new file mode 100644 index 0000000000000000000000000000000000000000..c807607b94ff775ce64663a827d934969b180ed7 --- /dev/null +++ b/UNICADOworkflow/src/clean_up/clean_up_temporary_results.py @@ -0,0 +1,308 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def clean_up_temporary_results(paths_and_names, parameter_for_design_case, control_settings, identifier, log_file_list): + """ post_operations_of_workflow creates all output files and copies them to the result directory. + Deletes all temporary files. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The input list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'use_range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The input integer "identifier" contains the identifier number of the current workflow execution. + + The input list "log_file_list" contains all system prints of function: post_operations_of_workflow.py. + + :param: paths_and_names: input list of lists + :param: parameter_for_design_case: input list of lists + :param: control_settings: input list of lists + :param: identifier: input integer + :param: log_file_list: input list + :return: none + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + from parameter_study.read_parameter_study_settings import read_parameter_study_settings + from parameter_study.write_parameter_study_csv_output import write_parameter_study_csv_output + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory = \ + ([item for item in paths_and_names if 'path_of_working_directory' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + global_loop_counter = int(([item for item in parameter_for_design_case if 'global_loop_counter' in item])[-1][-1]) + parameter_name = str(([item for item in parameter_for_design_case if 'parameter_name' in item])[-1][-1]) + parameter_study_mode = (([item for item in parameter_for_design_case if 'program_mode' in item])[-1][-1] + == "parameter_study") + optimization_mode = (([item for item in parameter_for_design_case if 'program_mode' in item])[-1][-1] + == "optimization") + study_counter = int(([item for item in parameter_for_design_case if 'study_counter' in item])[-1][-1]) + + ''' initialize local parameters ''' + save_results = int(0) + copy_target_path = str() + skip_saving_flag = False + save_only_aircraft_exchange_file = int(0) + + # Check if any design tool has sent an execution error + # -> if true: -> add "_Failed_execution" string to result directory of current workflow loop + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'): + current_workflow_name_new = current_workflow_name + '_Failed_execution' + else: + current_workflow_name_new = current_workflow_name + + ''' perform copy and clean up ''' + # check if the parameter study should not be performed -> if true: -> set copy target path to workflow results + if parameter_study_mode == 0 and optimization_mode == 0: + copy_target_path = path_of_working_directory + 'workflowResults/' + current_workflow_name_new + '_' \ + + aircraft_project + + # else if condition: parameter study should be performed -> set copy target path to parameter study working dir + elif parameter_study_mode == 1: + # call function to read parameter study settings + parameter_study_list, log_file_list = read_parameter_study_settings(path_of_working_directory, log_file_list, + current_workflow_name) + + path_to_current_study = \ + str(([item for item in parameter_study_list if 'path_to_current_study' in item])[-1][-1]) + reproduce_output_file_from_old_study = \ + int(([item for item in parameter_study_list if 'reproduce_output_file_from_old_study' in item])[-1][-1]) + save_results = \ + int(([item for item in parameter_study_list if 'save_results' in item])[-1][-1]) + save_only_aircraft_exchange_file =\ + int(([item for item in parameter_study_list if 'save_only_aircraft_exchange_file' in item])[-1][-1]) + + # reference case + if global_loop_counter == 1: + # set target path to copy results of reference case + copy_target_path = path_to_current_study + '/reference_aircraft/results' + if reproduce_output_file_from_old_study == 1: + skip_saving_flag = True + + # parameter study iteration + else: + copy_target_path = path_to_current_study + '/' + parameter_name + '/' + 'run_' + str(study_counter) + if study_counter == 0: + if os.path.isdir(path_to_current_study + '/' + parameter_name): + last_number = len(os.listdir(path_to_current_study + '/' + parameter_name)) + else: + last_number = int(0) + copy_target_path = path_to_current_study + '/' + parameter_name + '/' + 'run_' + str(last_number+1) + + # else if condition: optimization should be performed -> set copy target path for results of optimization + elif optimization_mode == 1: + # generate directory for optimization results and save outputs of first workflow loop as reference case + if global_loop_counter == 1: + copy_target_path = path_of_working_directory + 'workflowResults/' + current_workflow_name_new + '_' \ + + aircraft_project + '_optimization/referenceCase' + if not os.path.isdir(path_of_working_directory + 'workflowResults/' + current_workflow_name_new + '_' + + aircraft_project + '_optimization/results'): + os.makedirs(path_of_working_directory + 'workflowResults/' + current_workflow_name_new + '_' + + aircraft_project + '_optimization/results') + with open(path_of_working_directory + 'workflowResults/' + current_workflow_name_new + '_' + + aircraft_project + '_optimization/results/X-values.csv', 'w') as file: + file.close() + with open(path_of_working_directory + 'workflowResults/' + current_workflow_name_new + '_' + + aircraft_project + '_optimization/results/Y-values.csv', 'w') as file: + file.close() + with open(path_of_working_directory + 'workflowResults/' + current_workflow_name_new + '_' + + aircraft_project + '_optimization/results/G-values.csv', 'w') as file: + file.close() + + else: + copy_target_path = path_of_working_directory + 'workflowResults/' + current_workflow_name_new + '_' \ + + aircraft_project + '_optimization/run_' + str(global_loop_counter - 1) + + ''' if existing, copy and then delete temporary results directory ''' + if parameter_study_mode == 0 or (save_results == 1 and save_only_aircraft_exchange_file == 0) \ + and not skip_saving_flag: + # copy temporary results to workflowResults and delete working copy of current workflow + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/temporaryResults'): + # copy temporary workflow results to workflow results directory + shutil.copytree(path_of_working_directory_rce + current_workflow_name + '/temporaryResults', + copy_target_path) + print('Workflow results successfully saved!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Workflow results successfully stored!') + # delete temporary workflow files + shutil.rmtree(path_of_working_directory_rce + current_workflow_name + '/temporaryResults') + print('Directory for temporary results cleared!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Directory for temporary results cleared!') + + ''' copy workflow configuration file to log-file results ''' + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow_conf.xml', + copy_target_path + '/config_files/unicado_workflow_conf.xml') + print('UNICADOworkflow configuration file has been successfully copied to results folder!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'UNICADOworkflow configuration file has been successfully copied to results folder!') + + elif save_results == 1 and save_only_aircraft_exchange_file == 1 and not skip_saving_flag: + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files'): + shutil.copytree(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files', copy_target_path) + print('Only aircraft exchange files of current parameter study input successfully stored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Only aircraft exchange files of current parameter study input successfully stored!') + + if optimization_mode == 1: + ''' copy optimization configuration file to config files ''' + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/optimization_conf.xml', + copy_target_path + '/config_files/optimization_conf.xml') + print('Optimization configuration file has been successfully copied to results folder!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Pptimization configuration file has been successfully copied to results folder!') + + ''' write csv-output file if parameter study is selected ''' + if parameter_study_mode == 1: + ''' copy parameter study configuration file to config files ''' + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/parameter_study_conf.xml', + copy_target_path + '/config_files/parameter_study_conf.xml') + print('Parameter study configuration file has been successfully copied to results folder!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Parameter study configuration file has been successfully copied to results folder!') + + # delete temporary workflow files + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/temporaryResults'): + shutil.rmtree(path_of_working_directory_rce + current_workflow_name + '/temporaryResults') + print('Directory for temporary results cleared!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Directory for temporary results cleared!') + + # call function to write parameter study output data to output csv-file + if not skip_saving_flag: + status_csv_output, log_file_list = write_parameter_study_csv_output(path_of_working_directory_rce, + path_of_working_directory, + copy_target_path, + parameter_for_design_case, + log_file_list, current_workflow_name) + + ''' copy tool error list log-file to log-file results ''' + if not skip_saving_flag: + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/toolErrorList.log'): + if not os.path.isdir(copy_target_path + '/reporting/'): + os.mkdir(copy_target_path + '/reporting/') + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/temp/toolErrorList.log', + copy_target_path + '/reporting/toolErrorList.log') + print('UNICADOworkflow tool error list has been successfully copied to reporting folder of ' + 'workflow results!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'UNICADOworkflow tool error list has been successfully copied to reporting folder of ' + 'workflow results!') + + ''' generate warning if convergence of design sizing loop has not reached ''' + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/convergenceError.dat'): + print('Warning!') + print('Maximum number of iterations of design sizing loop reached, but no convergence achieved!') + print('Please check the maximum number of iterations and the convergence criterion in the ' + 'UNICADOworkflow configuration file!') + log_file_list.append('Warning!') + log_file_list.append('Maximum number of iterations of design sizing loop reached, but no convergence achieved!') + log_file_list.append('Please check the maximum number of iterations and the convergence criterion in the ' + 'UNICADOworkflow configuration file!') + + ''' write log-file to system ''' + log_file_list.append('****************************************** end post operations of workflow ' + '******************************************') + log_file_list.append('') + log_file_list.append('********************************************** END OF UNICADO WORKFLOW ' + '**********************************************') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + ''' copy workflow log-file to log-file results ''' + if not os.path.isdir(copy_target_path + '/reporting/log_files'): + os.makedirs(copy_target_path + '/reporting/log_files') + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', + copy_target_path + '/reporting/log_files/unicado_workflow.log') + + ''' delete identifier file of current workflow execution ''' + # check if the parameter study mode and the optimization mode is not selected + # -> if true: -> delete identifier file of current running workflow execution + if parameter_study_mode == 0 and optimization_mode == 0: + # remove identifier file of current workflow execution to prepare shut down after workflow termination + os.remove(path_of_working_directory_rce + 'identifier/' + str(identifier) + '.dat') + if len(os.listdir(path_of_working_directory_rce + 'identifier/')) == 0: + os.rmdir(path_of_working_directory_rce + 'identifier/') + + # delete temporary workflow directory of current workflow execution + shutil.rmtree(path_of_working_directory_rce + current_workflow_name) + + return diff --git a/UNICADOworkflow/src/clean_up/post_operations_of_workflow.py b/UNICADOworkflow/src/clean_up/post_operations_of_workflow.py new file mode 100644 index 0000000000000000000000000000000000000000..52e67a7e042aaae079ac722ab83d83fc0ae5058b --- /dev/null +++ b/UNICADOworkflow/src/clean_up/post_operations_of_workflow.py @@ -0,0 +1,449 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def post_operations_of_workflow(paths_and_names, control_settings, parameter_for_design_case, identifier): + """ post_operations_of_workflow creates all output files and copies them to the result directory. + Deletes all temporary files. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'use_range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The input integer "identifier" contains the identifier number of the current workflow execution. + + :param: paths_and_names: input list of lists + :param: control_settings: input list of lists + :param: parameter_for_design_case: input list of lists + :param: identifier: input integer + :return: none + """ + + ''' import for python ''' + import os + import json + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from clean_up.clean_up_temporary_results import clean_up_temporary_results + + ''' read data for script execution ''' + aircraft_exchange_directory = ([item for item in paths_and_names if 'aircraft_exchange_directory' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory = ([item for item in paths_and_names if 'path_of_working_directory' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + path_to_json_files = ([item for item in paths_and_names if 'path_to_json_files' in item])[-1][-1] + + save_log_files_to_result_folder = \ + int(([item for item in control_settings if 'save_log_files_to_result_folder' in item])[-1][-1]) + save_acft_xml_to_result_folder = \ + int(([item for item in control_settings if 'save_acft_xml_to_result_folder' in item])[-1][-1]) + save_acft_xml_after_each_iteration = \ + int(([item for item in control_settings if 'save_acft_xml_after_each_iteration' in item])[-1][-1]) + + count_of_iteration = \ + int(([item for item in parameter_for_design_case if 'count_of_iteration' in item])[-1][-1]) + count_of_mission_study_loop = \ + int(([item for item in parameter_for_design_case if 'count_of_mission_study_loop' in item])[-1][-1]) + + ''' initialize local parameter ''' + function_name = getframeinfo(currentframe()).function + + ''' create list of files to copy ''' + files_in_working_directory = os.listdir(path_of_working_directory) + list_of_json_tools = os.listdir(path_to_json_files) + + ''' create list for log-file string ''' + log_file_list = ['', + '******************************************** post operations Of workflow ' + '********************************************'] + + ''' save configuration files after executed post operation modules ''' + path_of_aircraft_exchange_files_after_execution = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/config_files/postProcessing/' + os.makedirs(path_of_aircraft_exchange_files_after_execution) + for file_name in files_in_working_directory: + # check if current list element is a directory + if os.path.isdir(path_of_working_directory_rce + current_workflow_name): + # check whether a configuration xml file exists within the current list element + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + file_name + '_conf.xml'): + source = path_of_working_directory_rce + current_workflow_name + '/' + file_name + '_conf.xml' + # read group name of module from json file + for json_tool in list_of_json_tools: + if json_tool == file_name: + with open(path_to_json_files + file_name + '/configuration.json', 'r') as file: + json_tree = json.loads(file.read()) + group_name = json_tree['groupName'] + if group_name == 'postProcessing': + copy_target_path = path_of_aircraft_exchange_files_after_execution + file_name + '_conf.xml' + shutil.copy(source, copy_target_path) + + # open current configuration file to reset absolut paths to relativ + frame_info = getframeinfo(currentframe()) + root_of_config_tree, xml_tree = read_xml_file(copy_target_path, + path_of_working_directory_rce, + file_name, function_name, + frame_info.lineno, + log_file_list, + current_workflow_name) + + # Check if the IODir entry is in the config file + # -> if true: -> reset to relative path + if root_of_config_tree.find('./control_settings/aircraft_exchange_file_directory/value') is not None: + root_of_config_tree.find('./control_settings/aircraft_exchange_file_directory/value').text = \ + aircraft_exchange_directory + + # Check if the LogFile entry is in the config file + # -> if true: -> reset to name of file + if root_of_config_tree.find('./control_settings/log_file/value') is not None: + root_of_config_tree.find('./control_settings/log_file/value').text = \ + file_name + '.log' + + # Check if the cpacsDir entry is in the config file + # -> if true: -> reset to relative path + if root_of_config_tree.find('./control_settings/program_specific/cpacsDir/value') \ + is not None: + root_of_config_tree.find('./control_settings/program_specific/cpacsDir/value').text = \ + aircraft_exchange_directory + + # write settings to configuration xml file + xml_tree.write(copy_target_path, encoding='utf-8') + + ''' create temporary folder for log-files ''' + path_of_log_file_results = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project \ + + '/reporting/log_files/' + if not os.path.isdir(path_of_log_file_results): + os.makedirs(path_of_log_file_results) + + ''' create list of files in working directory ''' + files_in_working_directory = os.listdir(path_of_working_directory) + + # copy log-files to temporary results directory + if save_log_files_to_result_folder == 1: + # loop for all elements in list of files + for file_name in files_in_working_directory: + if not (file_name == 'workingDirectoryRCE') and not (file_name == 'workflowResults') \ + and not (file_name == 'projects'): + # check if current list element is a directory + if os.path.isdir(path_of_working_directory + file_name): + # save log-file of each module to results directory + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + file_name + '.log'): + # if log file exist, copy log file of list-element to temporary results + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/' + file_name + '.log', + path_of_log_file_results + file_name + '.log') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Log-file of ' + file_name + ' successfully stored!') + + ''' save plots, html and tex folder to workflow results ''' + # output folder + check_flag_project = os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project) + check_flag_reporting = os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/reporting') + + # save reporting folder to workflow results + if check_flag_reporting: + source = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/reporting' + destination = path_of_working_directory_rce + current_workflow_name + '/temporaryResults/reporting' + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/reporting'): + shutil.copytree(source, destination) + else: + list_of_reporting_elements = os.listdir(source) + for element in list_of_reporting_elements: + if os.path.isdir(source + '/' + element): + shutil.copytree(source + '/' + element, destination + '/' + element) + else: + shutil.copy(source + '/' + element, destination + '/' + element) + + print('Reporting files successfully stored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Reporting files successfully stored!') + + ''' save aircraft exchange files to results folder ''' + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files'): + os.makedirs(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files') + + if check_flag_project: + source = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_project + '.xml' + destination = path_of_working_directory_rce + current_workflow_name + '/temporaryResults/' \ + + aircraft_project + '.xml' + shutil.copy(source, destination) + + print('Final aircraft exchange files successfully stored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Final aircraft exchange files successfully stored!') + + # check for existing aircraft exchange files of sizing loop directory + check_flag_aircraft_exchange_files_of_sizing_loop = \ + os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files_of_sizing_loop') + # check for existing aircraft exchange files of study loop directory + check_flag_aircraft_exchange_files_of_study_loop = \ + os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files_of_study_loop') + + if save_acft_xml_to_result_folder == 0: + if check_flag_aircraft_exchange_files_of_sizing_loop: + # delete temporary workflow files + shutil.rmtree(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files_of_sizing_loop') + + if check_flag_aircraft_exchange_files_of_study_loop: + # delete temporary workflow files + shutil.rmtree(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files_of_study_loop') + + print('All aircraft-exchange files successfully deleted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'All aircraft-exchange files successfully deleted!') + + elif save_acft_xml_after_each_iteration == 1: + if check_flag_aircraft_exchange_files_of_sizing_loop: + source = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files_of_sizing_loop/' + aircraft_project + '_it' \ + + str(count_of_iteration) + '.xml' + destination = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/finalaircraft_exchange_files/' + aircraft_project \ + + '_final_design_sizing_file.xml' + shutil.copy(source, destination) + + if check_flag_aircraft_exchange_files_of_study_loop: + source = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files_of_study_loop/' + aircraft_project + '_it' \ + + str(count_of_mission_study_loop) + '.xml' + destination = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files/' + aircraft_project \ + + '_final_mission_study_file.xml' + shutil.copy(source, destination) + + if check_flag_project: + source = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_project + '.xml' + destination = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files/' + aircraft_project \ + + '_final_project_file.xml' + shutil.copy(source, destination) + + print('Aircraft-exchange files of each iteration step successfully stored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Aircraft-exchange files of each iteration step successfully stored!') + + else: + if check_flag_aircraft_exchange_files_of_sizing_loop: + # delete temporary workflow files + source = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files_of_sizing_loop/' + aircraft_project + '_it' \ + + str(count_of_iteration) + '.xml' + destination = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files/' + aircraft_project \ + + '_final_design_sizing_file.xml' + shutil.copy(source, destination) + # delete temporary workflow files + shutil.rmtree(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files_of_sizing_loop') + + if check_flag_aircraft_exchange_files_of_study_loop: + source = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files_of_study_loop/' + aircraft_project + '_it' \ + + str(count_of_iteration) + '.xml' + destination = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files/' + aircraft_project \ + + '_final_mission_study_file.xml' + shutil.copy(source, destination) + # delete temporary workflow files + shutil.rmtree(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files_of_study_loop') + if check_flag_project: + source = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_project + '.xml' + destination = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files/' + aircraft_project \ + + '_final_project_file.xml' + shutil.copy(source, destination) + + print('Only final aircraft-exchange files are stored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Only final aircraft-exchange files are stored!') + + ''' save converged cpacs file to workflow results ''' + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + + aircraft_project + '_CPACS.xml'): + source = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_project + '_CPACS.xml' + destination = path_of_working_directory_rce + current_workflow_name + '/temporaryResults/' \ + + aircraft_project + '_CPACS.xml' + shutil.copy(source, destination) + destination = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files/' + aircraft_project \ + + '_final_CPACS_file.xml' + shutil.copy(source, destination) + + print('CPACS exchange-file successfully stored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': CPACS exchange-file successfully stored!') + + ''' save scenario.xml file to workflow results ''' + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/scenario.xml'): + source = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/scenario.xml' + destination = path_of_working_directory_rce + current_workflow_name + '/temporaryResults/scenario.xml' + shutil.copy(source, destination) + + print('Scenario xml-file successfully stored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Scenario xml-file successfully stored!') + + ''' save operating_company.xml file to workflow results ''' + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/operating_company.xml'): + source = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project \ + + '/operating_company.xml' + destination = path_of_working_directory_rce + current_workflow_name + '/temporaryResults/operating_company.xml' + shutil.copy(source, destination) + + print('Operating_company xml-file successfully stored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': operating_company file successfully stored!') + + ''' save project aero data to workflow results ''' + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/aero_data'): + source = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/aero_data' + destination = path_of_working_directory_rce + current_workflow_name + '/temporaryResults/aero_data' + shutil.copytree(source, destination) + + print('Project polar xml-file successfully stored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Project polar xml-file successfully stored!') + + ''' save geometry data to workflow geometry results ''' + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/geometry_data'): + source = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/geometry_data' + destination = path_of_working_directory_rce + current_workflow_name + '/temporaryResults/geometry_data' + shutil.copytree(source, destination) + + print('Geometry files successfully stored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Geometry files successfully stored!') + + ''' save mission data to workflow mission_data results ''' + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/mission_data'): + source = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/mission_data' + destination = path_of_working_directory_rce + current_workflow_name + '/temporaryResults/mission_data' + shutil.copytree(source, destination) + + print('Mission files successfully stored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Mission files successfully stored!') + + ''' save engine data to results directory ''' + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/engine_data'): + # try to open aircraft exchange file as element tree + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_project + '.xml' + root_of_aircraft_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, aircraft_project, + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + used_engines = root_of_aircraft_tree.findall('./component_design/propulsion/specific/propulsion/engine') + # create list of all elements inside of engine directory + files_in_engine_directory = os.listdir(path_of_working_directory_rce + current_workflow_name + '/' + + aircraft_project + '/engine_data') + for engine in used_engines: + engine_name = engine.find('./model/value').text + for file_name in files_in_engine_directory: + # check if fileName a directory + if file_name == engine_name: + # if true -> delete engine data from project folder + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/engine_data/' + file_name) and not\ + (os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/engine_data/' + file_name)): + source = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project \ + + '/engine_data/' + file_name + destination = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/engine_data/' + file_name + shutil.copytree(source, destination) + + print('Engine ' + file_name + ' has been successfully copied to results folder!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Engine ' + file_name + ' has been successfully copied to results folder!') + + ''' copy results of current workflow loop and clean up temporary directory ''' + # call clean-up function of workflow to copy final results to workflow results directory + clean_up_temporary_results(paths_and_names, parameter_for_design_case, control_settings, identifier, log_file_list) diff --git a/UNICADOworkflow/src/design_sizing_loop/activate_plots_and_reports_for_sizing_loop.py b/UNICADOworkflow/src/design_sizing_loop/activate_plots_and_reports_for_sizing_loop.py new file mode 100644 index 0000000000000000000000000000000000000000..feef527615e250aad2ebda512a7968ef4df124c7 --- /dev/null +++ b/UNICADOworkflow/src/design_sizing_loop/activate_plots_and_reports_for_sizing_loop.py @@ -0,0 +1,284 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def activate_plots_and_reports_for_sizing_loop(paths_and_names, control_settings, parameter_for_design_case, + module_list_of_sizing_loop): + """ activate_plots_and_reports_for_sizing_loop sets switches in configuration files to activate plot- and report generation of design sizing loop. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The input list of lists "module_list_of_sizing_loop" is a dynamic list of used sizing loop modules of current workflow execution: + * [:][0] string: 'sizing_loop_module', [0][:] string: 'name of the used sizing loop module of current workflow execution' + + The output integer "status_flag_to_skip" contains the status to skip or perform the generation of plots and reports of the design sizing loop. + + :param: paths_and_names: input list of lists + :param: control_settings: input list of lists + :param: parameter_for_design_case: input list of lists + :param: module_list_of_sizing_loop: input list of lists + :return: status_flag_to_skip: output integer + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory = ([item for item in paths_and_names if 'path_of_working_directory' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + write_info_files = ([item for item in control_settings if 'write_info_files' in item])[-1][-1] + write_info_files_only_at_last_step_of_iteration = \ + ([item for item in control_settings if 'write_info_files_only_at_last_step_of_iteration' in item])[-1][-1] + plot_output_on = int(([item for item in control_settings if 'plot_output_on' in item])[-1][-1]) + report_output_on = int(([item for item in control_settings if 'report_output_on' in item])[-1][-1]) + tex_report_on = int(([item for item in control_settings if 'tex_report_on' in item])[-1][-1]) + + number_of_max_iteration = \ + ([item for item in parameter_for_design_case if 'number_of_max_iteration' in item])[-1][-1] + count_of_iteration = ([item for item in parameter_for_design_case if 'count_of_iteration' in item])[-1][-1] + + ''' initialize local parameter ''' + # date_time_counter is the number of characters of date and time print of workflow logfile + # -> should not be printed in the workflow console + character_length_of_date_and_time = 21 + status_flag_to_skip = False + function_name = getframeinfo(currentframe()).function + + ''' create list for log-file string ''' + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/convergenceError.dat'): + log_file_list = ['', + '******************* Convergence could not be achieved before number of max iteration ' + 'was reached! ******************', + '', + '******************************************** activate plots and reports ' + '********************************************'] + + elif not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'): + log_file_list = ['**************************** End of Iteration: Convergence reached after ' + + str(count_of_iteration) + ' iterations! *****************************', + '', + '******************************************** activate plots and reports ' + '********************************************'] + else: + log_file_list = ['', + '*************************** Convergence could not be reached due to a design tool error! ' + '***************************', + '', + '******************************************** activate plots and reports ' + '********************************************'] + + ''' restore aircraft-exchange-file of last loop ''' + file_name = aircraft_exchange_file[:len(aircraft_exchange_file) - 4] + if not number_of_max_iteration <= 0: + name_of_current_aircraft_exchange_file = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' + file_name + '_it' \ + + str(count_of_iteration) + '.xml' + shutil.copy(path_of_working_directory_rce + name_of_current_aircraft_exchange_file, + path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' + + file_name + '_finalLoop.xml') + + # Check if the tool execution error flag is not existing and plot or report generation is not disabled + # -> if true: -> prepare module configuration files to generate plots and reports by restoring the + # pre last design sizing aircraft exchange file + if not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat') \ + and (plot_output_on == 1 or report_output_on == 1 or tex_report_on == 1): + if number_of_max_iteration < 0: + file_source = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' + file_name + '_it' \ + + str(count_of_iteration - 2) + '.xml' + if not os.path.isfile(file_source): + if count_of_iteration < 2: + file_source = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' \ + + file_name + '_it0.xml' + else: + file_source = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' \ + + file_name + '_it' + str(count_of_iteration - 1) + '.xml' + destination = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project \ + + '/' + aircraft_exchange_file + shutil.copy(path_of_working_directory_rce + file_source, destination) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Aircraft exchange file for output generation restored!') + else: + file_source = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' + file_name + '_it' \ + + str(count_of_iteration - 1) + '.xml' + destination = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project \ + + '/' + aircraft_exchange_file + shutil.copy(path_of_working_directory_rce + file_source, destination) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Aircraft exchange file for output generation restored!') + + ''' create list of files in working directory ''' + files_in_working_directory = os.listdir(path_of_working_directory) + # loop for all elements in list of files + for file_name in files_in_working_directory: + if not (file_name == 'workingDirectoryRCE') and not (file_name == 'workflowResults') \ + and not (file_name == 'projects'): + # check if current list element is a directory + if os.path.isdir(path_of_working_directory + file_name): + # check whether a configuration xml file exists within the current list element + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + + file_name + '_conf.xml'): + # activate plot and/or report generation for last iteration step + # if selected in workflow configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + file_name + '_conf.xml' + file_name_tree_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, file_name, + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + if plot_output_on == 1: + file_name_tree_root.find('./control_settings/plot_output/enable/value').text = \ + str(bool(1)).lower() + if report_output_on == 1: + file_name_tree_root.find('./control_settings/report_output/value').text = \ + str(bool(1)).lower() + if tex_report_on == 1: + file_name_tree_root.find('./control_settings/tex_report/value').text = str(bool(1)).lower() + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + ''' Write info file after last step of sizing loop iteration ''' + # Check if attribute 'onlyAtLastStepOfIteration' of switch 'WriteInfoFiles' set to 1 + # -> if true: -> activate writeInfoFiles in sizing loop configuration files + if write_info_files_only_at_last_step_of_iteration == 1 and write_info_files == 1: + i = 0 + for _ in module_list_of_sizing_loop: + module_name = module_list_of_sizing_loop[i][-1] + # try to open module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + module_name + '_conf.xml' + file_name_tree_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, module_name, + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + file_name_tree_root.find('./control_settings/write_info_files/value').text = str(bool(1)).lower() + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Switch of WriteInfoFile only for last step of iteration in ' + module_name + + '_conf.xml successfully set to active!') + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + i += 1 + + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'All switches set to generate plots and reports!') + + # Else condition: Error in design tool execution or generate plots is disabled in workflow configuration file + else: + status_flag_to_skip = True + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Plots and reports of design sizing loop were not generated!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error in design tool execution or generate plots or reports is disabled in ' + 'workflow configuration file.') + + ''' write log-file to system ''' + log_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a') + # check if error in tool execution has occurred + # -> if true: initialize loop counter with zero to skip the first four entries of log-file list to print to + # workflow console + if status_flag_to_skip: + i = 0 + # Else condition: no error in tool execution has occurred -> skip only the first three lines of log-file list + else: + i = 1 + + # loop across all elements of log-file list to print to workflow console and write to workflow log-file + for row in log_file_list: + # check if the actual loop counter is greater than 3 + # -> if true: -> print log-file list entry to workflow console + if i > 3: + print(row[character_length_of_date_and_time:]) + + # write current entry of log-file list to workflow log-file + log_file.write(row + '\n') + i += 1 + log_file.close() + + return status_flag_to_skip diff --git a/UNICADOworkflow/src/design_sizing_loop/estimate_design_sizing_residuals.py b/UNICADOworkflow/src/design_sizing_loop/estimate_design_sizing_residuals.py new file mode 100644 index 0000000000000000000000000000000000000000..461f7b8f80379f8181833e3f6c66c2279abae9f5 --- /dev/null +++ b/UNICADOworkflow/src/design_sizing_loop/estimate_design_sizing_residuals.py @@ -0,0 +1,251 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def estimate_design_sizing_residuals(paths_and_names, design_variables, mtom_loop_vector, number_of_max_iteration, + count_of_iteration, convergence_criteria): + """ estimate_mission_study_residuals calculates the residuals of design variables of design sizing loop + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "design_variables" contains the following values: + * [0][0] string: 'm_take_off_max_last', [0][1] float: 'value of maximum take off mass of last iteration step' + * [1][0] string: 'm_operating_empty_last', [1][1] float: 'value of operating empty mass of last iteration step' + * [2][0] string: 'mission_energy_last', [2][1] float: 'value of mission energy of last iteration step' + * [3][0] string: 'x_center_of_gravity_last', [3][1] float: 'value of x position of center of gravity of last iteration step' + * [4][0] string: 'cm_cruise', [4][1] float: 'value of the current moment coefficient' + * [5][0] string: 'i_stab', [5][1] float: 'value of the current trimming angle of horizontal stabiliser' + + The input list "mtom_loop_vector" contains all estimated mtom values. + + The input int "number_of_max_iteration" contains the current maximum number of iteration steps subtracted by the value of performed iterations. + + The input int "count_of_iteration" contains the current number of iteration loop. + + The input float "convergence_criteria" contains the convergence criteria of current iteration process. + + The output list of lists "design_variables" contains the following values: + * [0][0] string: 'm_take_off_max_last', [0][1] float: 'value of maximum take off mass of last iteration step' + * [1][0] string: 'm_operating_empty_last', [1][1] float: 'value of operating empty mass of last iteration step' + * [2][0] string: 'mission_energy_last', [2][1] float: 'value of mission energy of last iteration step' + * [3][0] string: 'x_center_of_gravity_last', [3][1] float: 'value of x position of center of gravity of last iteration step' + * [4][0] string: 'cm_cruise', [4][1] float: 'value of the current moment coefficient' + * [5][0] string: 'i_stab', [5][1] float: 'value of the current trimming angle of horizontal stabiliser' + * [6][0] string: 'm_take_off_max', [6][1] float: 'value of maximum take off mass of current iteration step' + * [7][0] string: 'm_operating_empty', [7][1] float: 'value of operating empty mass of current iteration step' + * [8][0] string: 'mission_energy', [8][1] float: 'value of mission energy of current iteration step' + * [9][0] string: 'x_center_of_gravity', [9][1] float: 'value of x position of center of gravity of current iteration step' + * [10][0] string: 'residual_m_take_off_max', [10][1] float: 'value of residual of maximum take off mass of current iteration step' + * [11][0] string: 'residual_m_operating_empty', [11][1] float: 'value of residual of operating empty mass of current iteration step' + * [12][0] string: 'residual_mission_energy', [12][1] float: 'value of residual of mission energy of current iteration step' + * [13][0] string: 'residual_x_center_of_gravity', [13][1] float: 'value of residual of x position of center of gravity of current iteration step' + * [14][0] string: 'status_residual_m_take_off_max', [14][1] bool: 'status of convergence for maximum take of mass' + * [15][0] string: 'status_residual_m_operating_empty', [15][1] bool: 'status of convergence for mass operating empty' + * [16][0] string: 'status_residual_mission_energy', [16][1] bool: 'status of convergence for mission energy' + * [17][0] string: 'status_residual_x_center_of_gravity', [17][1] bool: 'status of convergence for the aft x-position of the center of gravity' + + The output list "mtom_loop_vector" contains all estimated mtom values. + + :param: paths_and_names: input list of lists + :param: design_variables: input list of lists + :param: mtom_loop_vector: input list + :param: number_of_max_iteration: input int + :param: count_of_iteration: input int + :param: convergence_criteria: input float + :return: design_variables: output list of lists, mtom_loop_vector: output list + """ + + ''' import for python ''' + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.get_mission_energy_specific_segment import get_mission_energy_specific_segment + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + m_take_off_max_last = ([item for item in design_variables if 'm_take_off_max_last' in item])[-1][-1] + m_operating_empty_last = ([item for item in design_variables if 'm_operating_empty_last' in item])[-1][-1] + mission_energy_last = ([item for item in design_variables if 'mission_energy_last' in item])[-1][-1] + x_center_of_gravity_last = ([item for item in design_variables if 'x_center_of_gravity_last' in item])[-1][-1] + + ''' initialize local parameter ''' + # date_time_counter is the number of characters of date and time print of workflow logfile + # -> should not be printed in the workflow console + character_length_of_date_and_time = 21 + valid_data = True + log_file_list = ['', '------------------------------ Current loop of iteration: ' + str(count_of_iteration) + + ' ---------', + '{0}: * results:'.format(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')))] + status_residual_mission_energy = False + status_residual_m_take_off_max = False + status_residual_m_operating_empty = False + status_residual_x_center_of_gravity = False + function_name = getframeinfo(currentframe()).function + + ''' open and read aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + aircraft_exchange_file + root_of_aircraft_exchange_tree, _ = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + # read iteration variables + m_take_off_max = root_of_aircraft_exchange_tree.find( + "./analysis/masses_cg_inertia/maximum_takeoff_mass/mass_properties/mass/value") + if m_take_off_max is not None: + m_take_off_max = float(m_take_off_max.text) + else: + m_take_off_max = 0 + + m_operating_empty = root_of_aircraft_exchange_tree.find( + "./analysis/masses_cg_inertia/operating_mass_empty/mass_properties/mass/value") + if m_operating_empty is not None: + m_operating_empty = float(m_operating_empty.text) + else: + m_operating_empty = 0 + + mission_energy = get_mission_energy_specific_segment( + root_of_aircraft_exchange_tree, 'design_mission', 'loaded_mission_energy/mission_energy') + + x_center_of_gravity = root_of_aircraft_exchange_tree.find( + "./analysis/masses_cg_inertia/maximum_takeoff_mass/mass_properties/center_of_gravity/x/value") + if x_center_of_gravity is not None: + x_center_of_gravity = float(x_center_of_gravity.text) + else: + x_center_of_gravity = 0 + # save current mtom value to mtom loop vector + mtom_loop_vector.append(m_take_off_max) + + # rel. residual m_take_off_max + if m_take_off_max > 0: + residual_m_take_off_max = round(abs(1 - m_take_off_max_last / m_take_off_max), 6) + if residual_m_take_off_max < convergence_criteria: + status_residual_m_take_off_max = True + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Current m_take_off_max: ' + + str(m_take_off_max) + '; Res. m_take_off_max: ' + str(residual_m_take_off_max) + + '; Convergence: ' + str(status_residual_m_take_off_max)) + else: + residual_m_take_off_max = 1 + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Current m_take_off_max: ' + + str(m_take_off_max) + '; Res. m_take_off_max: ' + str(residual_m_take_off_max) + + '; Convergence: ' + str(status_residual_m_take_off_max)) + + # rel. residual m_operating_empty + if m_operating_empty > 0: + residual_m_operating_empty = round(abs(1 - m_operating_empty_last / m_operating_empty), 6) + if residual_m_operating_empty < convergence_criteria: + status_residual_m_operating_empty = True + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current m_operating_empty: ' + str(m_operating_empty) + '; Res. m_operating_empty: ' + + str(residual_m_operating_empty) + '; Convergence: ' + + str(status_residual_m_operating_empty)) + + else: + residual_m_operating_empty = 1 + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current m_operating_empty: ' + str(m_operating_empty) + '; Res. m_operating_empty: ' + + str(residual_m_operating_empty) + '; Convergence: ' + + str(status_residual_m_operating_empty)) + + # rel. residual x_center_of_gravity + if x_center_of_gravity > 0: + residual_x_center_of_gravity = round(abs(1 - x_center_of_gravity_last / x_center_of_gravity), 6) + if residual_x_center_of_gravity < convergence_criteria: + status_residual_x_center_of_gravity = True + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Current x_center_of_gravity: ' + + str(x_center_of_gravity) + '; Res. x_center_of_gravity: ' + + str(residual_x_center_of_gravity) + '; Convergence: ' + + str(status_residual_x_center_of_gravity)) + else: + residual_x_center_of_gravity = 1 + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current xCoG: ' + str(x_center_of_gravity) + '; Res. xCoG: ' + + str(residual_x_center_of_gravity) + '; Convergence: ' + + str(status_residual_x_center_of_gravity)) + + # rel. residual mission_energy + if mission_energy > 0: + residual_mission_energy = round(abs(1 - mission_energy_last / mission_energy), 6) + if residual_mission_energy < convergence_criteria: + status_residual_mission_energy = True + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current mission_energy: ' + str(mission_energy) + '; Res. mission_energy: ' + + str(residual_mission_energy) + '; Convergence: ' + + str(status_residual_mission_energy)) + else: + residual_mission_energy = 1 + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current mission_energy: ' + str(mission_energy) + '; Res. mission_energy: ' + + str(residual_mission_energy) + '; Convergence: ' + str(status_residual_mission_energy)) + + ''' check for maximum iteration reached ''' + if number_of_max_iteration <= 0: + mission_energy = mission_energy_last + m_take_off_max = m_take_off_max_last + m_operating_empty = m_operating_empty_last + x_center_of_gravity = x_center_of_gravity_last + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'WARNING: Number of maximum iteration steps reached!') + valid_data = False + + ''' write log-file to system ''' + log_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a') + # loop across all elements of log-file list to print to workflow console and write to workflow log-file + for row in log_file_list: + # print current log-file list entry to workflow console + print(row[character_length_of_date_and_time:]) + + # write current entry of log-file list to workflow log-file + log_file.write(row + '\n') + log_file.close() + + ''' append calculated design values to list of list "design_variables" ''' + design_variables.append(['m_take_off_max', m_take_off_max]) + design_variables.append(['m_operating_empty', m_operating_empty]) + design_variables.append(['mission_energy', mission_energy]) + design_variables.append(['x_center_of_gravity', x_center_of_gravity]) + design_variables.append(['residual_m_take_off_max', residual_m_take_off_max]) + design_variables.append(['residual_m_operating_empty', residual_m_operating_empty]) + design_variables.append(['residual_mission_energy', residual_mission_energy]) + design_variables.append(['residual_x_center_of_gravity', residual_x_center_of_gravity]) + design_variables.append(['status_residual_m_take_off_max', status_residual_m_take_off_max]) + design_variables.append(['status_residual_m_operating_empty', status_residual_m_operating_empty]) + design_variables.append(['status_residual_mission_energy', status_residual_mission_energy]) + design_variables.append(['status_residual_x_center_of_gravity', status_residual_x_center_of_gravity]) + + return design_variables, mtom_loop_vector, valid_data diff --git a/UNICADOworkflow/src/design_sizing_loop/final_operations_of_sizing_loop.py b/UNICADOworkflow/src/design_sizing_loop/final_operations_of_sizing_loop.py new file mode 100644 index 0000000000000000000000000000000000000000..45b40429949d1d95c32429b7db8ff47ef59a4d63 --- /dev/null +++ b/UNICADOworkflow/src/design_sizing_loop/final_operations_of_sizing_loop.py @@ -0,0 +1,165 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def final_operations_of_sizing_loop(paths_and_names): + """ final_operations_of_sizing_loop combines the results of the design sizing loop to one csv file. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + :param: paths_and_names: input list of lists + :return: none + """ + + ''' import for python ''' + import json + import os + import shutil + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + + ''' read data for script execution ''' + aircraft_exchange_directory = ([item for item in paths_and_names if 'aircraft_exchange_directory' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory = ([item for item in paths_and_names if 'path_of_working_directory' in item])[-1][-1] + path_of_working_directory_rce\ + = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + path_to_json_files = ([item for item in paths_and_names if 'path_to_json_files' in item])[-1][-1] + + ''' initialize local parameter ''' + log_file_list = [] + function_name = getframeinfo(currentframe()).function + + ''' create list of files in working directory ''' + files_in_working_directory = os.listdir(path_of_working_directory) + + ''' save configuration files after performed sizing loop of UNICADO modules ''' + path_of_aircraft_exchange_files_after_execution = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/config_files/' + + # create results folder for configuration files + os.makedirs(path_of_aircraft_exchange_files_after_execution + 'setup/') + os.makedirs(path_of_aircraft_exchange_files_after_execution + 'sizingLoop/') + list_of_json_tools = os.listdir(path_to_json_files) + if not os.path.isdir(path_of_aircraft_exchange_files_after_execution): + os.makedirs(path_of_aircraft_exchange_files_after_execution) + + for file_name in files_in_working_directory: + if not (file_name == 'workingDirectoryRCE') and not (file_name == 'workflowResults') \ + and not (file_name == 'projects'): + # check if current list element is a directory + if os.path.isdir(path_of_working_directory_rce + current_workflow_name): + # check whether a configuration xml file exists within the current list element + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + file_name + '_conf.xml'): + source = path_of_working_directory_rce + current_workflow_name + '/' + file_name + '_conf.xml' + if not file_name == 'parameterStudyMgr': + # read group name of module from json file + for json_tool in list_of_json_tools: + if json_tool == file_name: + with open(path_to_json_files + file_name + '/configuration.json', 'r') as file: + json_tree = json.loads(file.read()) + group_name = json_tree['groupName'] + copy_target_path = str() + # copy current configuration file of list element to temporary working results + if group_name == 'preSizing': + copy_target_path = path_of_aircraft_exchange_files_after_execution + 'setup/' \ + + file_name + '_conf.xml' + shutil.copy(source, copy_target_path) + elif group_name == 'sizingLoop' or group_name == 'visualization': + copy_target_path = path_of_aircraft_exchange_files_after_execution + 'sizingLoop/' \ + + file_name + '_conf.xml' + shutil.copy(source, copy_target_path) + if file_name == 'aerodynamic_assessment': + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/liftingLine_conf.xml'): + copy_target_path = path_of_aircraft_exchange_files_after_execution \ + + 'sizingLoop/' + 'liftingLine_conf.xml' + shutil.copy(path_of_working_directory_rce + current_workflow_name + + '/liftingLine_conf.xml', copy_target_path) + copy_target_path = \ + path_of_aircraft_exchange_files_after_execution + 'sizingLoop/' \ + + file_name + '_conf.xml' + if file_name == 'cpacsInterface': + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/convertUNICADO2CPACS_conf.xml'): + shutil.copy(path_of_working_directory_rce + current_workflow_name + + '/convertUNICADO2CPACS_conf.xml', + path_of_aircraft_exchange_files_after_execution + + 'sizingLoop/' + 'convertUNICADO2CPACS_conf.xml') + + # reset all paths in the configuration files to preview entries + if not group_name == 'postProcessing': + while True: + # open current configuration file to reset absolut paths to relativ + frame_info = getframeinfo(currentframe()) + root_of_config_tree, xml_tree = read_xml_file(copy_target_path, + path_of_working_directory_rce, + file_name, function_name, + frame_info.lineno, + log_file_list, + current_workflow_name) + + # Check if the IODir entry is in the config file + # -> if true: -> reset to relative path + if root_of_config_tree.find( + './control_settings/aircraft_exchange_file_directory/value') is not None: + root_of_config_tree.find( + './control_settings/aircraft_exchange_file_directory/value').text = \ + aircraft_exchange_directory + + # Check if the LogFile entry is in the config file + # -> if true: -> reset to name of file + if root_of_config_tree.find( + './control_settings/log_file/value') is not None: + root_of_config_tree.find('./control_settings/log_file/value').text = \ + file_name + '.log' + + # Check if the cpacsDir entry is in the config file + # -> if true: -> reset to relative path + if root_of_config_tree.find( + './control_settings/program_specific/cpacsDir/value') is not None: + root_of_config_tree.find( + './control_settings/program_specific/cpacsDir/value').text = \ + aircraft_exchange_directory + + # write settings to configuration xml file + xml_tree.write(copy_target_path, encoding='utf-8') + if not file_name == 'cpacsInterface': + break + else: + copy_target_path = path_of_aircraft_exchange_files_after_execution \ + + 'sizingLoop/' + 'convertUNICADO2CPACS_conf.xml' + file_name = 'convertUNICADO2CPACS' + + ''' end of sizing loop ''' + print('Design sizing loop finished!') diff --git a/UNICADOworkflow/src/design_sizing_loop/initialize_calibration.py b/UNICADOworkflow/src/design_sizing_loop/initialize_calibration.py new file mode 100644 index 0000000000000000000000000000000000000000..deda376e7a4f442740554a3edd58d571a19effe9 --- /dev/null +++ b/UNICADOworkflow/src/design_sizing_loop/initialize_calibration.py @@ -0,0 +1,144 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def initialize_calibration(paths_and_names, calibration_settings): + """ initialize_calibration initialize parameter for ome and mtom calibration. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + :param: paths_and_names: input list of lists + :param: calibration_settings: input list of lists + :return: calibration_settings: output list of lists + """ + + ''' imports for python ''' + from calibration.reset_free_calibration_variables import reset_free_calibration_variables + from calibration.set_settings_for_ome_calibration import set_settings_for_ome_calibration + from calibration.save_calibration_results_to_file import save_calibration_results_to_file + from sub_function.write_to_log_file import write_to_log_file + + ''' create list for log-file string ''' + log_file_list = ['********************************************** initialize calibration ' + '**********************************************'] + + ''' read data for script execution ''' + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce\ + = ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + calibration_check_flag = int(([item for item in \ + calibration_settings if 'free_variable_OME_calibration' in item])[-1][-1] > 0 or \ + ([item for item in \ + calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1] > 0) + + # check if calibration mode active -> if true: -> initialize calibration mode operations + if calibration_check_flag: + # reset free variables for OME and MTOM calibration + log_file_list = reset_free_calibration_variables(paths_and_names, calibration_settings, log_file_list) + + # call function to set settings for ome calibration or set final values if OME calibration is skipped + calibration_settings, log_file_list = set_settings_for_ome_calibration(paths_and_names, calibration_settings, + log_file_list) + + # save initial calibration values to csv file + save_calibration_results_to_file(paths_and_names, 0, 0.000000, 'OME') + + ''' write log-file to system ''' + log_file_list.append('******************************************** end initialize calibration ' + '********************************************') + log_file_list.append('') + + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + return calibration_settings diff --git a/UNICADOworkflow/src/design_sizing_loop/initialize_design_sizing_loop.py b/UNICADOworkflow/src/design_sizing_loop/initialize_design_sizing_loop.py new file mode 100644 index 0000000000000000000000000000000000000000..a25f2d79ff7bde76aed143578dbdbf644b765a9d --- /dev/null +++ b/UNICADOworkflow/src/design_sizing_loop/initialize_design_sizing_loop.py @@ -0,0 +1,350 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def initialize_design_sizing_loop(paths_and_names, parameter_for_design_case, control_settings): + """ initialize_design_sizing_loop initialize design sizing loop and auto-trim function. + Set initial values of sizing loop and auto-trim parameter + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The input list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'use_range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The output list of lists "design_variables" contains the following values: + * [0][0] string: 'm_take_off_max', [0][1] float: 'value of initial maximum take off mass' + * [1][0] string: 'm_operating_empty', [1][1] float: 'value of initial operating empty mass' + * [2][0] string: 'mission_energy', [2][1] float: 'value of initial consumed mission energy of design mission' + * [3][0] string: 'x_center_of_gravity', [3][1] float: 'value of initial x-position of center of gravity' + + The output list of lists "trim_parameter_list" contains the following values: + * [0][0] string: 'i_stab', [0][1] array: 'array of values of angle of incidence of horizontal stabilizer' + * [1][0] string: 'i_stab_tmp', [1][1] float: 'value of temporary angle of incidence of horizontal stabilizer' + * [2][0] string: 'i_stab_last', [2][1] float: 'value of last angle of incidence of horizontal stabilizer' + * [3][0] string: 'cm_cruise', [3][1] array: 'array of values of moment coefficient of cruise flight' + * [4][0] string: 'cm_cruise_current', [4][1] float: 'value of temporary moment coefficient of cruise flight' + * [5][0] string: 'cm_cruise_last', [5][1] float: 'value of last moment coefficient of cruise flight' + * [6][0] string: 'flag_trim_successful', [6][1] int: 'value to signalize that trim is successful' + * [7][0] string: 'retries', [7][1] int: 'value to count the retries of trim function' + * [8][0] String: 'trim_accuracy' [8][1] float: 'value of trim accuracy if the ohn convergence criterion should be used' + + The output list "mtom_loop_vector" contains all estimated mtom values. + + :param paths_and_names: input list of lists + :param parameter_for_design_case: input list of lists + :param control_settings: input list of lists + :return design_variables: output list of lists, trim_parameter_list: output list of lists, mtom_loop_vector: output list + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.get_mission_energy_specific_segment import get_mission_energy_specific_segment + from sub_function.write_to_log_file import write_to_log_file + + ''' create list for log-file string ''' + log_file_list = ['', + '****************************************** initialize design sizing loop ' + '******************************************'] + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory = ([item for item in paths_and_names if 'path_of_working_directory' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + automatic_trim = ([item for item in parameter_for_design_case if 'automatic_trim' in item])[-1][-1] + design_mode = int(([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1]) + number_of_max_iteration =\ + ([item for item in parameter_for_design_case if 'number_of_max_iteration' in item])[-1][-1] + + switch_off_plots = ([item for item in control_settings if 'switch_off_plots' in item])[-1][-1] + switch_off_reports = ([item for item in control_settings if 'switch_off_reports' in item])[-1][-1] + switch_off_tex = ([item for item in control_settings if 'switch_off_tex' in item])[-1][-1] + + ''' initialize local parameter ''' + function_name = getframeinfo(currentframe()).function + mtom_loop_vector = [] + + print(os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/temp/workflowExecutionError.dat')) + # check if design_mode not equal to 3 and no error in tool execution before + # -> if true: -> design sizing loop should be executed -> prepare initial parameter for design sizing + if not design_mode == 3 and not os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/temp/workflowExecutionError.dat'): + ''' create list of files in working directory ''' + files_in_working_directory = os.listdir(path_of_working_directory) + if switch_off_plots == 1 or switch_off_reports == 1 or switch_off_tex == 1: + # loop for all elements in list of files + for file_name in files_in_working_directory: + if not (file_name == 'workingDirectoryRCE') and not (file_name == 'workflowResults') \ + and not (file_name == 'projects') and not (file_name == 'cpacs_interface') and not (file_name == 'report_generator'): + # check if current list element is a directory + if os.path.isdir(path_of_working_directory + file_name): + # check whether a configuration xml file exists within the current list element + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + + file_name + '_conf.xml'): + # disable plot and report generation for sizing loop + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + file_name + '_conf.xml' + file_name_tree_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, file_name, + function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + if switch_off_plots == 1: + file_name_tree_root.find('./control_settings/plot_output/enable/value').text = \ + str(bool(0)).lower() + if switch_off_reports == 1: + file_name_tree_root.find('./control_settings/report_output/value').text = \ + str(bool(0)).lower() + if switch_off_tex == 1: + file_name_tree_root.find('./control_settings/tex_report/value').text = \ + str(bool(0)).lower() + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + ''' open and read aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project \ + + '/' + aircraft_exchange_file + root_of_aircraft_exchange_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, + frame_info.lineno, log_file_list, + current_workflow_name) + + # set values to output variables + m_take_off_max = root_of_aircraft_exchange_tree.find( + "./analysis/masses_cg_inertia/maximum_takeoff_mass/mass_properties/mass/value") + if m_take_off_max is not None: + m_take_off_max = float(m_take_off_max.text) + else: + m_take_off_max = 0 + + m_operating_empty = root_of_aircraft_exchange_tree.find( + "./analysis/masses_cg_inertia/operating_mass_empty/mass_properties/mass/value") + if m_operating_empty is not None: + m_operating_empty = float(m_operating_empty.text) + else: + m_operating_empty = 0 + + mission_energy_mission_design = get_mission_energy_specific_segment( + root_of_aircraft_exchange_tree, "design_mission", "loaded_mission_energy/mission_energy") + + x_center_of_gravity = root_of_aircraft_exchange_tree.find( + "./analysis/masses_cg_inertia/most_forward_mass/mass_properties/center_of_gravity/x/value") + if x_center_of_gravity is not None: + x_center_of_gravity = float(x_center_of_gravity.text) + else: + x_center_of_gravity = 0 + + design_variables = [['m_take_off_max', m_take_off_max], + ['m_operating_empty', m_operating_empty], + ['mission_energy', mission_energy_mission_design], + ['x_center_of_gravity', x_center_of_gravity]] + + # set current mtom value tp loop vector + mtom_loop_vector.append(m_take_off_max) + + ''' check if auto-trim is activated ''' + # initialize trim parameter + cm_cruise = [] + cm_cruise_last = float(0.0) + cm_cruise_current = float(0.0) + i_stab = [] + i_stab_tmp = float(0.0) + flag_trim_successful = 0 + retries = int(0) + trim_accuracy = float() + + ''' Check if auto trim is activated ''' + if automatic_trim: + # initialize automated trimming + print('Auto-Trim is activated!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Auto-Trim is activated!') + number_of_lifting_surfaces = len(root_of_aircraft_exchange_tree.findall( + "./component_design/empennage/specific/geometry/aerodynamic_surface")) + name_of_lifting_surfaces = root_of_aircraft_exchange_tree.findall( + './component_design/empennage/specific/geometry/aerodynamic_surface/name/value') + + # open and read workflow configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/unicado_workflow_conf.xml' + root_of_workflow_tree, _ = read_xml_file(path, path_of_working_directory_rce, 'unicado_workflow', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + trim_accuracy = float(1e-5) + + # check if number of lifting surfaces is greater than zero + if number_of_lifting_surfaces > 0: + # read names of lifting surfaces + lifting_surface_list = [] + for liftingSurface in name_of_lifting_surfaces: + lifting_surface_list.append(liftingSurface.text) + # check if only one horizontal stabiliser exists + if (lifting_surface_list.count('horizontal_stabiliser') == 1): + automatic_trim = 1 + else: + print('Unknown designation for wing-tail arrangement \n' '(Name Wing: ' + lifting_surface_list[0] + + ', Name Stabiliser: ' + lifting_surface_list[1] + ').\n' 'Switch automatic trim off!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Unknown designation for wing-tail arrangement \n' '(Name Wing: ' + + lifting_surface_list[0] + ', Name Stabiliser: ' + lifting_surface_list[1] + + ').\n' 'Switch automatic trim off!') + automatic_trim = 0 + + # otherwise: check if module empennage_design is in working directory + elif 'empennage_design' in files_in_working_directory: + automatic_trim = 1 + + # otherwise: check only one lifting surface is available -> auto-trim disabled + else: + print('Only one lifting surface available and empennage_design not activated. ' + 'This is not enough for an automated trimming. Switch off trimming.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Only one lifting surface available and empennage_design not activated. ' + 'This is not enough for an automated trimming. Switch off trimming.') + automatic_trim = 0 + else: + print('Auto-Trim is disabled!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Auto-Trim is disabled!') + + ''' set start values ''' + i_stab.append(i_stab_tmp) + i_stab_last = i_stab_tmp + cm_cruise.append(i_stab_tmp) + + ''' create table for for trim parameter ''' + ([item for item in parameter_for_design_case if 'automatic_trim' in item])[-1][-1] = automatic_trim + trim_parameter_list = [['i_stab', i_stab], + ['i_stab_tmp', float(i_stab_tmp)], + ['i_stab_last', float(i_stab_last)], + ['cm_cruise', cm_cruise], + ['cm_cruise_current', float(cm_cruise_current)], + ['cm_cruise_last', float(cm_cruise_last)], + ['flag_trim_successful', int(flag_trim_successful)], + ['retries', int(retries)], + ['trim_accuracy', trim_accuracy]] + + ''' crate temporary folder for aircraft exchange files of each sizing loop ''' + aircraft_exchange_files_of_sizing_loop = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' + if not os.path.isdir(aircraft_exchange_files_of_sizing_loop): + os.makedirs(aircraft_exchange_files_of_sizing_loop) + + ''' save clean aircraft exchange file ''' + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + + aircraft_exchange_file, + aircraft_exchange_files_of_sizing_loop + aircraft_exchange_file[:-4] + '_it0.xml') + + ''' start of iteration ''' + print('----- Start Iteration: Maximum steps of iteration to perform = ' + + str(number_of_max_iteration) + '! -----') + + ''' write log-file to system ''' + log_file_list.append('**************************************** end initialize design sizing loop ' + '****************************************') + log_file_list.append('') + log_file_list.append('************************** Start Iteration: Maximum steps of iteration to perform = ' + + str(number_of_max_iteration) + '! ***************************') + log_file_list.append('') + + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + # Else condition: design_mode is equal to 3 -> skip design sizing loop and perform mission study loop + # -> initialize design variables and trim parameter with zero + else: + design_variables = [['m_take_off_max', 0], + ['m_operating_empty', 0], + ['mission_energy', 0], + ['x_center_of_gravity', 0]] + + ([item for item in parameter_for_design_case if 'automatic_trim' in item])[-1][-1] = 0 + cm_cruise = [0] + i_stab = [0] + mtom_loop_vector = [0] + trim_parameter_list = [['i_stab', i_stab], + ['i_stab_tmp', 0], + ['i_stab_last', 0], + ['cm_cruise', cm_cruise], + ['cm_cruise_current', 0], + ['cm_cruise_last', 0], + ['flag_trim_successful', 0], + ['retries', 0], + ['trim_accuracy', 0]] + + return design_variables, trim_parameter_list, mtom_loop_vector diff --git a/UNICADOworkflow/src/design_sizing_loop/post_operation_of_design_sizing.py b/UNICADOworkflow/src/design_sizing_loop/post_operation_of_design_sizing.py new file mode 100644 index 0000000000000000000000000000000000000000..1286d92f502a0b48bd1f206a02789252a84ee2ae --- /dev/null +++ b/UNICADOworkflow/src/design_sizing_loop/post_operation_of_design_sizing.py @@ -0,0 +1,630 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def post_operation_of_design_sizing(paths_and_names, parameter_for_design_case, design_variables, control_settings, + module_list_of_sizing_loop, calibration_settings, mtom_loop_vector, + calibration_factors, accuracy_list, trim_parameter_list, i_stab, cm_cruise, + design_sizing_iteration_flag): + """ post_operation_of_design_sizing prepares design variables for converge component of RCE and calculates the residuals of design variables. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The input list of lists "design_variables" contains the following values: + * [0][0] string: 'm_take_off_max_last', [0][1] float: 'value of maximum take off mass of last iteration step' + * [1][0] string: 'm_operating_empty_last', [1][1] float: 'value of operating empty mass of last iteration step' + * [2][0] string: 'mission_energy_last', [2][1] float: 'value of mission fuel mass of last iteration step' + * [3][0] string: 'x_center_of_gravity_last', [3][1] float: 'value of x position of center of gravity of last iteration step' + * [4][0] string: 'cm_cruise', [4][1] float: 'value of the current moment coefficient' + * [5][0] string: 'i_stab', [5][1] float: 'value of the current trimming angle of horizontal stabiliser' + + The input list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The input list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The input list "mtom_loop_vector" contains all estimated mtom values. + + The input list "calibration_factors" contains all estimated calibration factors of mtom calibration. + + The input list of lists "accuracy_list" contains the following values: + * [0][0] string: 'accuracy_low', [0][1] float: 'value of low accuracy condition' + * [1][0] string: 'accuracy_medium', [1][1] float: 'value of medium accuracy condition' + * [2][0] string: 'accuracy_high', [2][1] float: 'value of high accuracy condition' + + The input list of lists "trim_parameter_list" contains the following values: + * [0][0] string: 'i_stab', [0][1] array: 'array of values of angle of incidence of horizontal stabilizer' + * [1][0] string: 'i_stab_tmp', [1][1] float: 'value of temporary angle of incidence of horizontal stabilizer' + * [2][0] string: 'i_stab_last', [2][1] float: 'value of last angle of incidence of horizontal stabilizer' + * [3][0] string: 'cm_cruise', [3][1] array: 'array of values of moment coefficient of cruise flight' + * [4][0] string: 'cm_cruise_current', [4][1] float: 'value of temporary moment coefficient of cruise flight' + * [5][0] string: 'cm_cruise_last', [5][1] float: 'value of last moment coefficient of cruise flight' + * [6][0] string: 'flag_trim_successful', [6][1] int: 'value to signalize that trim is successful' + * [7][0] string: 'retries', [7][1] int: 'value to count the retries of trim function' + * [8][0] String: 'trim_accuracy' [8][1] float: 'value of trim accuracy if the ohn convergence criterion should be used' + + The input list "i_stab" contains the following values: + * [count_of_iteration] float: 'values of angle of incidence of horizontal stabilizer' + + The input list "cm_cruise" contains the following values: + * [count_of_iteration] float: 'values of moment coefficient of cruise flight' + + The input float "design_sizing_iteration_flag" contains the status of the design sizing loop is finished or not. + + The output list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The output list of lists "design_variables" contains the following values: + * [0][0] string: 'm_take_off_max_last', [0][1] float: 'value of maximum take off mass of last iteration step' + * [1][0] string: 'm_operating_empty_last', [1][1] float: 'value of operating empty mass of last iteration step' + * [2][0] string: 'mission_energy_last', [2][1] float: 'value of mission fuel mass of last iteration step' + * [3][0] string: 'x_center_of_gravity_last', [3][1] float: 'value of x position of center of gravity of last iteration step' + * [4][0] string: 'cm_cruise', [4][1] float: 'value of the current moment coefficient' + * [5][0] string: 'i_stab', [5][1] float: 'value of the current trimming angle of horizontal stabiliser' + * [6][0] string: 'm_take_off_max', [6][1] float: 'value of maximum take off mass of current iteration step' + * [7][0] string: 'm_operating_empty', [7][1] float: 'value of operating empty mass of current iteration step' + * [8][0] string: 'mission_energy', [8][1] float: 'value of mission energy of current iteration step' + * [9][0] string: 'x_center_of_gravity', [9][1] float: 'value of x position of center of gravity of current iteration step' + * [10][0] string: 'residual_m_take_off_max', [10][1] float: 'value of residual of maximum take off mass of current iteration step' + * [11][0] string: 'residual_m_operating_empty', [11][1] float: 'value of residual of operating empty mass of current iteration step' + * [12][0] string: 'residual_mission_energy', [12][1] float: 'value of residual of mission energy of current iteration step' + * [13][0] string: 'residual_x_center_of_gravity', [13][1] float: 'value of residual of x position of center of gravity of current iteration step' + * [14][0] string: 'status_residual_m_take_off_max', [14][1] bool: 'status of convergence for maximum take of mass' + * [15][0] string: 'status_residual_m_operating_empty', [15][1] bool: 'status of convergence for mass operating empty' + * [16][0] string: 'status_residual_mission_energy', [16][1] bool: 'status of convergence for mission energy' + * [17][0] string: 'status_residual_x_center_of_gravity', [17][1] bool: 'status of convergence for the aft x-position of the center of gravity' + + The output list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + * [14][0] string: 'residual_iteration_value', [14][1] float: 'initial value of ome calibration residual' + * [15][0] string: 'residual_iteration_value_to_target', [15][1] float: 'initial value of ome calibration residual to target' + * [16][0] string: 'calibration_factor_temp', [16][1] float: 'temporary value of ome calibration factor' + * [17][0] string: 'calibration_factor_flag', [17][1] float: 'current value of ome calibration flag' + * [18][0] string: 'calibration_factor_low' [18][1] float: 'value of lower calibration factor' + * [19][0] string: 'calibration_factor_high' [19][1] float: 'value of higher calibration factor' + * [20][0] string: 'calibration_factor_act', [20][1] float: 'value of actual calibration factor' + * [21][0] string: 'calibration_factor_last', [21][1] float: 'value of last calibration factor' + * [22][0] string: 'calibration_value_flag', [22][1] bool: 'current status of calibration value flag' + * [23][0] string: 'calibration_value_low', [23][1] float: 'lower calibration value' + * [24][0] string: 'calibration_value_high' [24][1] float: 'higher calibration value' + * [25][0] string: 'calibration_value_act' [25][1] float: 'actual calibration value' + * [26][0] string: 'calibration_value_last', [26][1] float: 'last calibration value' + * [27][0] string: 'aux_interpolation_flag', [27][1] bool: 'status of auxiliary interpolation flag' + * [28][0] string: 'calibration_value_over_target_exist', [28][1] bool: 'status of calibration value over target value' + * [29][0] string: 'calibration_value_under_target_exist', [29][1] bool: 'status of calibration value under target value' + * [30][0] string: 'calibration_value_over_target_update_exist', [30][1] bool: 'status of calibration value update over target value' + * [31][0] string: 'calibration_value_under_target_update_exist', [31][1] bool: 'status of calibration value update under target value' + * [32][0] string: 'number_reverse_effects', [32][1] int: 'number of reverse effects which are performed during calibration' + * [33][0] string: 'number_of_final_runs', [33][1] int: 'number of final runs performed during calibration' + * [34][0] string: 'x_relative' [34][1] float: 'value of relative lever arm in x direction' + * [35][0] string: 'max_delta_calibration_factor' [35][1] float: 'value of maximum allowed delta for calibration factor' + * [36][0] string: 'calibrate_ome_flag', [36][1] bool: 'flag for ome calibration' + * [37][0] string: 'calibrate_mtom_flag', [37][1] bool: 'flag for mtom calibration' + * [38][0] string: 'final_fuselage_mass_factor', [38][1] float: 'value of final fuselage mass factor' + * [39][0] string: 'current_value', [39][1] float: 'value of current operating mass empty' + * [40][0] string: 'last_value', [40][1] float: 'value of last operating mass empty' + * [41][0] string: 'iteration_flag' [41][1] int: 'number of the status of calibration successful' + + The output list "mtom_loop_vector" contains all estimated mtom values. + + The output list "calibration_factors" contains all estimated calibration factors of mtom calibration. + + The input list of lists "trim_parameter_list" contains the following values: + * [0][0] string: 'i_stab', [0][1] array: 'array of values of angle of incidence of horizontal stabilizer' + * [1][0] string: 'i_stab_tmp', [1][1] float: 'value of temporary angle of incidence of horizontal stabilizer' + * [2][0] string: 'i_stab_last', [2][1] float: 'value of last angle of incidence of horizontal stabilizer' + * [3][0] string: 'cm_cruise', [3][1] array: 'array of values of moment coefficient of cruise flight' + * [4][0] string: 'cm_cruise_current', [4][1] float: 'value of temporary moment coefficient of cruise flight' + * [5][0] string: 'cm_cruise_last', [5][1] float: 'value of last moment coefficient of cruise flight' + * [6][0] string: 'flag_trim_successful', [6][1] int: 'value to signalize that trim is successful' + * [7][0] string: 'retries', [7][1] int: 'value to count the retries of trim function' + * [8][0] String: 'trim_accuracy' [8][1] float: 'value of trim accuracy if the ohn convergence criterion should be used' + + The input list "i_stab" contains the following values: + * [count_of_iteration] float: 'values of angle of incidence of horizontal stabilizer' + + The input list "cm_cruise" contains the following values: + * [count_of_iteration] float: 'values of moment coefficient of cruise flight' + + The output float "design_sizing_iteration_flag" contains the status of the design sizing loop is finished or not. + + :param: paths_and_names: input list of lists + :param: parameter_for_design_case: input list of lists + :param: design_variables: input list of lists + :param: control_settings: input list of lists + :param: calibration_settings: input list of lists + :param: mtom_loop_vector: input list + :param: calibration_factors: input list + :param: accuracy_list: input list of lists + :param: trim_parameter_list: input list of lists + :param: i_stab: input list + :param: cm_cruise: input list + :param: design_sizing_iteration_flag: input float + :return: parameter_for_design_case: output list of lists, design_variables: output list of lists, + control_settings: output list of lists, mtom_loop_vector: output list, + trim_parameter_list: output list of list, i_stab: output list, cm_cruise: output list, + design_sizing_iteration_flag: output float + """ + + ''' import for python ''' + import os + import shutil + from datetime import datetime + from design_sizing_loop.trim_function import trim_function + from calibration.damp_iteration import damp_iteration + from calibration.perform_mtom_calibration import perform_mtom_calibration + from calibration.final_ome_calibration_steps import final_ome_calibration_steps + from calibration.set_settings_for_mtom_calibration import set_settings_for_mtom_calibration + from design_sizing_loop.estimate_design_sizing_residuals import estimate_design_sizing_residuals + from design_sizing_loop.save_design_sizing_results_to_file import save_design_sizing_results_to_file + from design_sizing_loop.activate_plots_and_reports_for_sizing_loop import activate_plots_and_reports_for_sizing_loop + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory = ([item for item in paths_and_names if 'path_of_working_directory' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + automatic_trim = int(([item for item in parameter_for_design_case if 'automatic_trim' in item])[-1][-1]) + convergence_criteria = ([item for item in parameter_for_design_case if 'convergence_criteria' in item])[-1][-1] + count_of_iteration = ([item for item in parameter_for_design_case if 'count_of_iteration' in item])[-1][-1] + damp_mtom_iteration = int(([item for item in parameter_for_design_case if 'damp_mtom_iteration' in item])[-1][-1]) + number_of_max_iteration = \ + ([item for item in parameter_for_design_case if 'number_of_max_iteration' in item])[-1][-1] + + flag_trim_successful = int(([item for item in trim_parameter_list if 'flag_trim_successful' in item])[-1][-1]) + + calibrate_ome_flag = int(([item for item in calibration_settings if 'calibrate_ome_flag' in item])[-1][-1]) + calibrate_mtom_flag = int(([item for item in calibration_settings if 'free_variable_MTOM_calibration' \ + in item])[-1][-1] > 0) + number_of_final_runs = int(([item for item in calibration_settings if 'number_of_final_runs' in item])[-1][-1]) + number_of_iterations_before_mtom_calibration = \ + int(([item for item in calibration_settings if 'number_of_iterations_before_mtom_calibration' in item])[-1][-1]) + + ''' initialize local parameter ''' + final_ome_iteration_run = False + status_flag_to_skip_design_sizing = \ + int(([item for item in control_settings if 'status_flag_to_skip_design_sizing' in item])[-1][-1]) + + # check if the final plot and report generation loop should be performed + if status_flag_to_skip_design_sizing == 0: + ''' check if ome calibration is performed -> if true: -> perform final steps of ome calibration ''' + if calibrate_ome_flag == 1: + # call function to perform final ome calibration steps isf selected + final_ome_calibration_steps(paths_and_names) + + # set perform ome calibration flag to "False" + ([item for item in calibration_settings if 'calibrate_ome_flag' in item])[-1][-1] = int(0) + + # set flag for final ome iteration run + final_ome_iteration_run = True + + ''' reset and reinitialize values for mtom calibration if selected in workflow configuration file ''' + if calibrate_mtom_flag == 1 and count_of_iteration == 0: + # call function to set settings of mtom calibration + calibration_settings, calibration_factors = set_settings_for_mtom_calibration(paths_and_names, + calibration_settings, + calibration_factors) + + # add iteration flag to list of calibration settings to perform convergence checks of sizing loop + if count_of_iteration == 0: + calibration_settings.append(['iteration_flag', int(0)]) + + ''' add + 1 to count of iteration ''' + count_of_iteration = count_of_iteration + 1 + ([item for item in parameter_for_design_case if 'count_of_iteration' in item])[-1][-1] = count_of_iteration + + ''' estimate relative residuals of iteration variables ''' + # call function to estimate residuals of design sizing loop + design_variables, mtom_loop_vector, valid_data = \ + estimate_design_sizing_residuals(paths_and_names, design_variables, mtom_loop_vector, + number_of_max_iteration - 1, count_of_iteration, + convergence_criteria) + + ''' perform mtom calibration to target value if selected in workflow configuration file ''' + if not os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/temp/workflowExecutionError.dat'): + if calibrate_mtom_flag == 1: + modulo_of_iteration_count = count_of_iteration % number_of_iterations_before_mtom_calibration + if modulo_of_iteration_count == 0: + # call function to perform mtom calibration + calibration_settings, mtom_loop_vector, calibration_factors = \ + perform_mtom_calibration(calibration_settings, parameter_for_design_case, design_variables, + mtom_loop_vector, calibration_factors, count_of_iteration, + automatic_trim, flag_trim_successful, path_of_working_directory_rce, + current_workflow_name) + + ''' initialize local parameter ''' + # date_time_counter is the number of characters of date and time print of workflow logfile + # -> should not be printed in the workflow console + character_length_of_date_and_time = 21 + log_file_list = [] + + ''' reload iteration flags after calibration is performed ''' + iteration_flag = int(([item for item in calibration_settings if 'iteration_flag' in item])[-1][-1]) + calibrate_mtom_flag = int(([item for item in calibration_settings if 'calibrate_mtom_flag' in item])[-1][-1]) + + ''' check if mtom calibration is finished to perform three final iteration loops ''' + if iteration_flag == 1 and calibrate_mtom_flag == 0: + if number_of_final_runs == 3: + ([item for item in calibration_settings if 'free_variable_OME_calibration' in item])[-1][-1] = int(0) + ([item for item in calibration_settings if 'free_variable_MTOM_calibration' in item])[-1][-1] = int(0) + ([item for item in parameter_for_design_case if 'count_of_iteration' in item])[-1][-1] =\ + count_of_iteration + + number_of_final_runs += 1 + ([item for item in calibration_settings if 'number_of_final_runs' in item])[-1][-1] = \ + int(number_of_final_runs) + + ''' perform automatic trim if selected ''' + if not final_ome_iteration_run: + count_for_trimming = count_of_iteration + + # check if calibration mode is selected -> if true: -> reduce iteration counter by 1 + if calibrate_mtom_flag == 1: + count_for_trimming = count_of_iteration - 1 + + # call function to perform automatic trim + trim_parameter_list, parameter_for_design_case, i_stab, cm_cruise =\ + trim_function(paths_and_names, parameter_for_design_case, accuracy_list, trim_parameter_list, i_stab, + cm_cruise, count_for_trimming) + + if calibrate_mtom_flag == 1 and damp_mtom_iteration == 1: + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': * ' + 'Warning: Damping in calibration mode is not possible and will not performed! \n' + ' Only allowed in clean-sheet-design without calibration! \n ') + ([item for item in parameter_for_design_case if 'damp_mtom_iteration' in item])[-1][-1] = int(0) + + ''' save iteration parameter to csv-file ''' + save_design_sizing_results_to_file(paths_and_names, design_variables, count_of_iteration) + + ''' save final aircraft-exchange-file ''' + file_name = aircraft_exchange_file[:len(aircraft_exchange_file) - 4] + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_exchange_file + + file_destination = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' + file_name + '_it' \ + + str(count_of_iteration) + '.xml' + if os.path.isfile(path_of_working_directory_rce + file_destination): + os.remove(path_of_working_directory_rce + file_destination) + shutil.copy(path, path_of_working_directory_rce + file_destination) + + # check for last iteration step left + if number_of_max_iteration - 1 <= 1: + # create backUp-file from aircraft exchange file + file_destination = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' \ + + file_name + '_finalLoop.xml' + shutil.copy(path, path_of_working_directory_rce + file_destination) + + ''' generate outputs for RCE ''' + # set changed parameter for design case to list of list "parameter_for_design_case" + number_of_max_iteration -= 1 + ([item for item in parameter_for_design_case if 'number_of_max_iteration' in item])[-1][-1] =\ + number_of_max_iteration + + ''' damp mtom value for the next loop if mtom damping is selected in workflow configuration file ''' + damp_mtom_iteration = \ + int(([item for item in parameter_for_design_case if 'damp_mtom_iteration' in item])[-1][-1]) + flag_trim_successful = \ + int(([item for item in trim_parameter_list if 'flag_trim_successful' in item])[-1][-1]) + status_residual_mission_energy = \ + ([item for item in design_variables if 'status_residual_mission_energy' in item])[-1][-1] + status_residual_m_take_off_max = \ + ([item for item in design_variables if 'status_residual_m_take_off_max' in item])[-1][-1] + status_residual_m_operating_empty =\ + ([item for item in design_variables if 'status_residual_m_operating_empty' in item])[-1][-1] + status_residual_x_center_of_gravity = \ + ([item for item in design_variables if 'status_residual_x_center_of_gravity' in item])[-1][-1] + + ''' check if max iteration is reached -> if true: -> set trim successful flag to "true" ''' + if automatic_trim == 1 and not valid_data: + (([item for item in trim_parameter_list if 'flag_trim_successful' in item])[-1][-1]) = int(1) + + # check if convergence criteria of each iteration variable is reached + # -> if true: -> send converged output flag to converge module of RCE + if status_residual_mission_energy and status_residual_m_take_off_max and status_residual_m_operating_empty \ + and status_residual_x_center_of_gravity and calibrate_mtom_flag == 0 and flag_trim_successful == 1: + + calibration_target_mtom = \ + ([item for item in calibration_settings if 'calibration_target_mtom' in item])[-1][-1] + + if not os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/temp/workflowExecutionError.dat'): + if iteration_flag == 1: + ([item for item in parameter_for_design_case if 'count_of_iteration' in item])[-1][-1]\ + = count_of_iteration + log_file_list.append('') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ---') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Convergence successful. Result of the MTOM calibration:') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'MTOM set point: ' + str(calibration_target_mtom) + ' kg') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'MTOM actual value: ' + str(mtom_loop_vector[-1]) + ' kg') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ---') + if not flag_trim_successful == 1: + log_file_list.append('') + + # activate plot and report generation if selected + plot_output_on = int(([item for item in control_settings if 'plot_output_on' in item])[-1][-1]) + report_output_on = int(([item for item in control_settings if 'report_output_on' in item])[-1][-1]) + tex_report_on = int(([item for item in control_settings if 'tex_report_on' in item])[-1][-1]) + status_flag_to_skip_design_sizing = \ + int(([item for item in control_settings if 'status_flag_to_skip_design_sizing' in item])[-1][-1]) + + # check if the current loop is the last or if the generation of plots and reports should be performed + if not status_flag_to_skip_design_sizing == 1: + + if flag_trim_successful == 1: + log_file_list.append('') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ---') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Result of the trim:') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Angle of incidence Tailplane: ' + str(i_stab[-1]) + ' deg') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'CM at optimal Cruise-CL: ' + str(cm_cruise[-1])) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ---') + log_file_list.append('') + + # check if at least on report should be generated + if plot_output_on == 1 or report_output_on == 1 or tex_report_on == 1: + status_flag_to_skip = activate_plots_and_reports_for_sizing_loop(paths_and_names, + control_settings, + parameter_for_design_case, + module_list_of_sizing_loop) + + # check if an error is occurred during plot activation + # -> if true: -> send trigger signal to close loop + if status_flag_to_skip: + # set trigger signal to close mission study loop + design_sizing_iteration_flag = design_sizing_iteration_flag + else: + design_sizing_iteration_flag += 100.0 + ([item for item in control_settings + if 'status_flag_to_skip_design_sizing' in item])[-1][-1] = int(1) + ([item for item in parameter_for_design_case + if 'number_of_max_iteration' in item])[-1][-1] = number_of_max_iteration + 1 + + # else condition: plot and report generation disabled -> generate finale aircraft exchange file + else: + name_of_current_aircraft_exchange_file = \ + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' \ + + file_name + '_it' + str(count_of_iteration) + '.xml' + shutil.copy(path_of_working_directory_rce + name_of_current_aircraft_exchange_file, + path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' + + file_name + '_finalLoop.xml') + + # else condition: convergence of each iteration variable is not reached + # -> add +100 to output flag of converge module and perform mtom damping if selected + else: + # check if workflowExecutionError.dat exist in the UNICADOworkflow directory + # -> if true: -> any tool has sent a tool execution error -> terminate design sizing loop + if os.path.isfile(path_of_working_directory_rce + 'UNICADOworkflow/temp/workflowExecutionError.dat'): + # print error message on the workflow console and save the message to workflow log file + log_file_list.append('') + log_file_list.append('------------------------------ Current loop of iteration: ' + + str(count_of_iteration) + ' ---------') + log_file_list.append('') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error in design tool execution!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'At least one of the enabled design tools has send an error. ' + 'The actual design loop is failed and will be canceled!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'If parameter study or optimization is selected, ' + 'current loop of iteration will skipped and the next iteration will be performed!') + + elif not valid_data: + # generate convergence error flag + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/temp/'): + os.mkdir(path_of_working_directory_rce + current_workflow_name + '/temp/') + + convergence_error_dat = open(path_of_working_directory_rce + current_workflow_name + + '/temp/convergenceError.dat', 'a+') + convergence_error_dat.close() + + # print error message on the workflow console and save the message to workflow log file + log_file_list.append('') + log_file_list.append('------------------------------ Current loop of iteration: ' + + str(count_of_iteration) + ' ---------') + log_file_list.append('') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Warning!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Maximum number of iterations reached, but no convergence achieved!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Please check the maximum number of iterations and the ' + 'convergence criterion in the UNICADOworkflow configuration file!') + + else: + design_sizing_iteration_flag += 100.0 + ''' damp mtom iteration value if mode is selected in configuration file ''' + if count_of_iteration > 1 and damp_mtom_iteration == 1 and valid_data: + # call function to damp mtom value for the next loop + mtom_loop_vector[-1] = damp_iteration(paths_and_names, mtom_loop_vector, 'MTOM') + ([item for item in design_variables if 'm_take_off_max' in item])[-1][-1] = mtom_loop_vector[-1] + + ''' write log-file to system ''' + log_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a') + # loop across all elements of log-file list to print to workflow console and write to workflow log-file + for row in log_file_list: + # print current log-file list entry to workflow console + print(row[character_length_of_date_and_time:]) + + # write current entry of log-file list to workflow log-file + log_file.write(row + '\n') + log_file.close() + + # else condition -> the final plot and report generation loop was performed + else: + design_sizing_iteration_flag = design_sizing_iteration_flag + + return parameter_for_design_case, design_variables, calibration_settings, control_settings, mtom_loop_vector, \ + calibration_factors, trim_parameter_list, i_stab, cm_cruise, design_sizing_iteration_flag diff --git a/UNICADOworkflow/src/design_sizing_loop/save_design_sizing_results_to_file.py b/UNICADOworkflow/src/design_sizing_loop/save_design_sizing_results_to_file.py new file mode 100644 index 0000000000000000000000000000000000000000..2c83bb4b8de0c579ea1a1acf62cbbacf994c24e4 --- /dev/null +++ b/UNICADOworkflow/src/design_sizing_loop/save_design_sizing_results_to_file.py @@ -0,0 +1,137 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def save_design_sizing_results_to_file(paths_and_names, design_variables, count_of_iteration): + """ save_design_sizing_results_to_file writes all design sizing results to output csv-file. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "design_variables" contains the following values: + * [0][0] string: 'm_take_off_max_last', [0][1] float: 'value of maximum take off mass of last iteration step' + * [1][0] string: 'm_operating_empty_last', [1][1] float: 'value of operating empty mass of last iteration step' + * [2][0] string: 'mission_energy_last', [2][1] float: 'value of mission energy of last iteration step' + * [3][0] string: 'x_center_of_gravity_last', [3][1] float: 'value of x position of center of gravity of last iteration step' + * [4][0] string: 'cm_cruise', [4][1] float: 'value of the current moment coefficient' + * [5][0] string: 'i_stab', [5][1] float: 'value of the current trimming angle of horizontal stabiliser' + * [6][0] string: 'm_take_off_max', [6][1] float: 'value of maximum take off mass of current iteration step' + * [7][0] string: 'm_operating_empty', [7][1] float: 'value of operating empty mass of current iteration step' + * [8][0] string: 'mission_energy', [8][1] float: 'value of mission energy of current iteration step' + * [9][0] string: 'x_center_of_gravity', [9][1] float: 'value of x position of center of gravity of current iteration step' + * [10][0] string: 'residual_m_take_off_max', [10][1] float: 'value of residual of maximum take off mass of current iteration step' + * [11][0] string: 'residual_m_operating_empty', [11][1] float: 'value of residual of operating empty mass of current iteration step' + * [12][0] string: 'residual_mission_energy', [12][1] float: 'value of residual of mission energy of current iteration step' + * [13][0] string: 'residual_x_center_of_gravity', [13][1] float: 'value of residual of x position of center of gravity of current iteration step' + * [14][0] string: 'status_residual_m_take_off_max', [14][1] bool: 'status of convergence for maximum take of mass' + * [15][0] string: 'status_residual_m_operating_empty', [15][1] bool: 'status of convergence for mass operating empty' + * [16][0] string: 'status_residual_mission_energy', [16][1] bool: 'status of convergence for mission energy' + * [17][0] string: 'status_residual_x_center_of_gravity', [17][1] bool: 'status of convergence for the aft x-position of the center of gravity' + + The input int "count_of_iteration" contains the current number of calibration loop. + + :param: paths_and_names: input list of lists + :param: design_variables: input list of lists + :param: count_of_iteration: input int + :return: none + """ + + ''' imports for python ''' + import os + + ''' read data for script execution ''' + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + + ''' initialize local parameter ''' + results = [] + reporting_of_ome_calibration = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/reporting/' + + ''' check if output temporary reporting folder exist ''' + if not os.path.isdir(reporting_of_ome_calibration): + os.makedirs(reporting_of_ome_calibration) + + ''' prepare output data for csv-file ''' + # check if first loop of iteration -> if true: -> generate file header + if count_of_iteration == 1: + # generate header + results.append('count_of_iteration; ' + 'm_take_off_max in kg; ' + 'residual_m_take_off_max; ' + 'm_operating_empty in kg; ' + 'residual_m_operating_empty; ' + 'mission_energy in J; ' + 'residual_mission_energy; ' + 'x_center_of_gravity in m; ' + 'residual_x_center_of_gravity; ' + 'cm_cruise; ' + 'i_stab in deg') + + # save initial values to csv-file + results.append(str(count_of_iteration - 1) + ';' + + str(round(([item for item in design_variables if 'm_take_off_max_last' in item])[-1][-1], 2)) + + ';' + + 'nan;' + + str(round(([item for item in design_variables if 'm_operating_empty_last' in item])[-1][-1], 2)) + + ';' + + 'nan;' + + str(0.00) + ';' + + 'nan;' + + str(0.000) + ';' + + 'nan;' + + str(0.00000) + ';' + + str(0.0000) + ';') + + results.append(str(count_of_iteration) + ';' + + str(round(([item for item in design_variables if 'm_take_off_max' in item])[-1][-1], 2)) + ';' + + str(round(([item for item in design_variables if 'residual_m_take_off_max' in item])[-1][-1], 6)) + + ';' + + str(round(([item for item in design_variables if 'm_operating_empty' in item])[-1][-1], 2)) + ';' + + str(round(([item for item in design_variables if 'residual_m_operating_empty' in item])[-1][-1], 6)) + + ';' + + str(round(([item for item in design_variables if 'mission_energy' in item])[-1][-1], 2)) + ';' + + str(round(([item for item in design_variables if 'residual_mission_energy' in item])[-1][-1], 6)) + + ';' + + str(round(([item for item in design_variables if 'x_center_of_gravity' in item])[-1][-1], 3)) + ';' + + str(round(([item for item in design_variables if 'residual_x_center_of_gravity' in item]) + [-1][-1], 6)) + ';' + + str(round(([item for item in design_variables if 'cm_cruise' in item])[-1][-1], 5)) + ';' + + str(round(([item for item in design_variables if 'i_stab' in item])[-1][-1], 4))) + + results_file = open(reporting_of_ome_calibration + 'sizing_loop_results.csv', 'a') + for row in results: + results_file.write(row + '\n') + results_file.close() + + return diff --git a/UNICADOworkflow/src/design_sizing_loop/trim_function.py b/UNICADOworkflow/src/design_sizing_loop/trim_function.py new file mode 100644 index 0000000000000000000000000000000000000000..3959f0a1cfe4a842d085d9aa4afd986f827dbb7b --- /dev/null +++ b/UNICADOworkflow/src/design_sizing_loop/trim_function.py @@ -0,0 +1,302 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def trim_function(paths_and_names, parameter_for_design_case, accuracy_list, trim_parameter_list, i_stab, cm_cruise, + count_for_trimming): + """ trim_function calculates the angle of incidence and moment coefficient of cruise flight. + Attention: Automatically trimming must be selected otherwise trimming will skipped. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The input list of lists "accuracy_list" contains the following values: + * [0][0] string: 'accuracy_low', [0][1] float: 'value of low accuracy condition' + * [1][0] string: 'accuracy_medium', [1][1] float: 'value of medium accuracy condition' + * [2][0] string: 'accuracy_high', [2][1] float: 'value of high accuracy condition' + + The input list of lists "trim_parameter_list" contains the following values: + * [0][0] string: 'i_stab', [0][1] array: 'array of values of angle of incidence of horizontal stabilizer' + * [1][0] string: 'i_stab_tmp', [1][1] float: 'value of temporary angle of incidence of horizontal stabilizer' + * [2][0] string: 'i_stab_last', [2][1] float: 'value of last angle of incidence of horizontal stabilizer' + * [3][0] string: 'cm_cruise', [3][1] array: 'array of values of moment coefficient of cruise flight' + * [4][0] string: 'cm_cruise_current', [4][1] float: 'value of temporary moment coefficient of cruise flight' + * [5][0] string: 'cm_cruise_last', [5][1] float: 'value of last moment coefficient of cruise flight' + * [6][0] string: 'flag_trim_successful', [6][1] int: 'value to signalize that trim is successful' + * [7][0] string: 'retries', [7][1] int: 'value to count the retries of trim function' + * [8][0] String: 'trim_accuracy' [8][1] float: 'value of trim accuracy if the ohn convergence criterion should be used' + + The input list "i_stab" contains the following values: + * [count_of_iteration] float: 'values of angle of incidence of horizontal stabilizer' + + The input list "cm_cruise" contains the following values: + * [count_of_iteration] float: 'values of moment coefficient of cruise flight' + + The output list of lists "trim_parameter_list" contains the following values: + * [0][0] string: 'i_stab', [0][1] array: 'array of values of angle of incidence of horizontal stabilizer' + * [1][0] string: 'i_stab_tmp', [1][1] float: 'value of temporary angle of incidence of horizontal stabilizer' + * [2][0] string: 'i_stab_last', [2][1] float: 'value of last angle of incidence of horizontal stabilizer' + * [3][0] string: 'cm_cruise', [3][1] array: 'array of values of moment coefficient of cruise flight' + * [4][0] string: 'cm_cruise_current', [4][1] float: 'value of temporary moment coefficient of cruise flight' + * [5][0] string: 'cm_cruise_last', [5][1] float: 'value of last moment coefficient of cruise flight' + * [6][0] string: 'flag_trim_successful', [6][1] int: 'value to signalize that trim is successful' + * [7][0] string: 'retries', [7][1] int: 'value to count the retries of trim function' + * [8][0] String: 'trim_accuracy' [8][1] float: 'value of trim accuracy if the ohn convergence criterion should be used' + + The output list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The output list "i_stab" contains the following values: + * [count_of_iteration] float: 'value of angle of incidence of horizontal stabilizer' + + The output list "cm_cruise" contains the following values: + * [count_of_iteration] float: 'value of moment coefficient of cruise flight' + + :param: paths_and_names: input list of lists + :param: parameter_for_design_case: input list of lists + :param: accuracy_list: input list of lists + :param: trim_parameter_list: list of lists + :param: i_stab: input list + :param: cm_cruise: input list + :param: count_for_trimming: input integer + :return: trim_parameter_list: output list of lists, parameter_for_design_case: output list of lists, i_stab: output list, cm_cruise: output: list + """ + + ''' import for python ''' + import math + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + automatic_trim = int(([item for item in parameter_for_design_case if 'automatic_trim' in item])[-1][-1]) + + accuracy_low = ([item for item in accuracy_list if 'accuracy_low' in item])[-1][-1] + accuracy_medium = ([item for item in accuracy_list if 'accuracy_medium' in item])[-1][-1] + + i_stab_last = ([item for item in trim_parameter_list if 'i_stab_last' in item])[-1][-1] + cm_cruise_last = ([item for item in trim_parameter_list if 'cm_cruise_last' in item])[-1][-1] + flag_trim_successful = ([item for item in trim_parameter_list if 'flag_trim_successful' in item])[-1][-1] + retries = ([item for item in trim_parameter_list if 'retries' in item])[-1][-1] + trim_accuracy = ([item for item in trim_parameter_list if 'trim_accuracy' in item])[-1][-1] + + ''' initialize local parameter ''' + # date_time_counter is the number of characters of date and time print of workflow logfile + # -> should not be printed in the workflow console + character_length_of_date_and_time = 21 + log_file_list = [] + function_name = getframeinfo(currentframe()).function + + ''' open and read aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + aircraft_exchange_file + root_of_aircraft_exchange_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + ''' check if automatic trim is enabled and the use own convergence criterion is set to true + -> if true: -> overwrite local accuracy_low requirement by user input value ''' + if automatic_trim == 1: + accuracy_low = trim_accuracy + + ''' check if auto trim is disabled in workflow configuration + file or the current cm is lower than the given accuracy requirement ''' + cm_cruise.append(float(0.0)) + + # if condition one or condition two is true + # -> check if the trim successful flag has to set to 1 to skip auto trim function + if automatic_trim == 0 or abs(cm_cruise[-1]) <= accuracy_low: + if abs(cm_cruise[-1]) <= accuracy_low: + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': * ' + 'Trim successful (current CM =' + str(cm_cruise[-1]) + ')!') + + flag_trim_successful = 1 + + # Else condition: no condition is true -> check if the trim successful flag is set to 1 + # -> if true: -> after successful trimming, again deviation in the CM -> restart auto trim function + else: + if flag_trim_successful == 1: + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'WARNING: After successful trimming, again deviation in the CM (current CM =' + + str(cm_cruise[-1]) + ')!') + flag_trim_successful = 0 + + cm_cruise_current = cm_cruise[-1] + i_stab_tmp = float(0.0) + + ''' calculate trim parameter if automatic trim is active ''' + if flag_trim_successful == 0: + # set current cruise CM for output file + if count_for_trimming == 1: + i_stab = [] + + if count_for_trimming == 2: + trim_adjustment_tmp = float(0.0) + cm_cruise_last = cm_cruise_current + # set trim adjustment value according to RWTH-Aachen convergenceLoop + if abs(cm_cruise_current) < accuracy_low: + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': * Trim: CM already in 1st run smaller than limit value 0.0001.') + + elif (abs(cm_cruise_current) <= 0.001) and (abs(cm_cruise_current) > 0.0001): + trim_adjustment_tmp = round(float(0.1), 1) + + elif (abs(cm_cruise_current) <= 0.01) and (abs(cm_cruise_current) > 0.001): + trim_adjustment_tmp = round(float(0.5), 1) + + elif (abs(cm_cruise_current) <= 0.1) and (abs(cm_cruise_current) > 0.01): + trim_adjustment_tmp = round(float(1.0), 1) + + else: + trim_adjustment_tmp = round(float(2.0), 1) + + if cm_cruise_current > 0: + i_stab_tmp += trim_adjustment_tmp + else: + i_stab_tmp -= trim_adjustment_tmp + + if count_for_trimming > 2: + if abs(cm_cruise_current - cm_cruise_last) <= accuracy_medium: + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'ERROR during Trim: Change of moment coefficient too small at CM = ' + + str(cm_cruise_current)) + if abs(cm_cruise_current) <= 0.001: + if retries <= 2: + retries += 1 + else: + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Finish trim with CM = ' + str(cm_cruise_current) + '.') + flag_trim_successful = 1 + else: + if retries <= 4: + retries += 1 + i_stab_tmp *= 0.001 + else: + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Trim not successful. Finish trim with CM = ' + + str(cm_cruise_current) + '.') + flag_trim_successful = 1 + else: + x_rel = float((0 - cm_cruise_last) / (cm_cruise_current - cm_cruise_last)) + i_stab_tmp = (1 - x_rel) * i_stab_last + x_rel * i_stab[-1] + + # Handling regarding high i_Tailplane values (not quite clear how this is created) + if abs(cm_cruise_last) < 0.01 and abs(i_stab_tmp - i_stab_last) > 2: + i_stab_tmp *= 1.05 + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'WARNING: Change of the i_Tailplane = ' + str(i_stab_tmp) + + ' too big at trim regarding last value (i_Tailplane_last = ' + + str(i_stab_last) + ').') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'WARNING: Use new value i_Tailplane = ' + str(i_stab_tmp) + + ' (Amount increased by 5%).') + + # set the penultimate value + if abs(cm_cruise_current) > abs(cm_cruise[-1]): + cm_cruise_last = cm_cruise[-1] + i_stab_last = i_stab[-2] + else: + cm_cruise_last = cm_cruise_current + i_stab_last = i_stab[-1] + + check_nan = math.isnan(i_stab_tmp) + if not check_nan: + i_stab.append(i_stab_tmp) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': * Trim: CM (current) = ' + + str(cm_cruise[-1]) + ' | i_Tailplane (new) = ' + str(i_stab_tmp)) + root_of_aircraft_exchange_tree.find( + '*/LiftingSurface[@ID="Stabiliser"]/SurfaceParameters/i_Surface').text = str(i_stab_tmp) + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + else: + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Angle of incidence for tailplane is NaN. Automatic trim aborted!') + automatic_trim = 0 + + ''' set current trim parameter to trim parameter list ''' + ([item for item in trim_parameter_list if 'i_stab_tmp' in item])[-1][-1] = round(i_stab_tmp, 4) + ([item for item in trim_parameter_list if 'i_stab_last' in item])[-1][-1] = i_stab_last + ([item for item in trim_parameter_list if 'cm_cruise_current' in item])[-1][-1] = round(cm_cruise_current, 5) + ([item for item in trim_parameter_list if 'cm_cruise_last' in item])[-1][-1] = cm_cruise_last + ([item for item in trim_parameter_list if 'flag_trim_successful' in item])[-1][-1] = int(flag_trim_successful) + ([item for item in trim_parameter_list if 'retries' in item])[-1][-1] = retries + + ''' set current value of automatic_trim to list parameter_for_design_case ''' + ([item for item in parameter_for_design_case if 'automatic_trim' in item])[-1][-1] = int(automatic_trim) + + ''' write log-file to system ''' + log_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a') + # loop across all elements of log-file list to print to workflow console and write to workflow log-file + for row in log_file_list: + # print current log-file list entry to workflow console + print(row[character_length_of_date_and_time:]) + + # write current entry of log-file list to workflow log-file + log_file.write(row + '\n') + log_file.close() + + return trim_parameter_list, parameter_for_design_case, i_stab, cm_cruise diff --git a/UNICADOworkflow/src/mission_study_loop/activate_plots_and_reports_for_mission_study.py b/UNICADOworkflow/src/mission_study_loop/activate_plots_and_reports_for_mission_study.py new file mode 100644 index 0000000000000000000000000000000000000000..8327c3c9faa42951be6e38a26ca2832727ae1842 --- /dev/null +++ b/UNICADOworkflow/src/mission_study_loop/activate_plots_and_reports_for_mission_study.py @@ -0,0 +1,216 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def activate_plots_and_reports_for_mission_study(paths_and_names, control_settings, count_of_mission_study_loop): + """ activate_plots_and_reports_for_mission_study sets switches in configuration files to activate plot- and report generation of mission study loop. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The input integer "count_of_mission_study_loop" contains the following values: + * int: 'value of temporary count of iteration of mission study loop' + + :param: paths_and_names: input list of lists + :param: control_settings: input list of lists + :param: count_of_mission_study_loop: integer + :return: none + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory = ([item for item in paths_and_names if 'path_of_working_directory' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + write_info_files = ([item for item in control_settings if 'write_info_files' in item])[-1][-1] + write_info_files_only_at_last_step_of_iteration = \ + ([item for item in control_settings if 'write_info_files_only_at_last_step_of_iteration' in item])[-1][-1] + plot_output_on = int(([item for item in control_settings if 'plot_output_on' in item])[-1][-1]) + report_output_on = int(([item for item in control_settings if 'report_output_on' in item])[-1][-1]) + tex_report_on = int(([item for item in control_settings if 'tex_report_on' in item])[-1][-1]) + + ''' initialize local parameter ''' + # date_time_counter is the number of characters of date and time print of workflow logfile + # -> should not be printed in the workflow console + character_length_of_date_and_time = 21 + status_flag_to_skip = False + function_name = getframeinfo(currentframe()).function + + ''' create list for log-file string ''' + if not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'): + ''' create list for log-file string ''' + log_file_list = ['********************* End of mission study iteration: Convergence reached after ' + + str(count_of_mission_study_loop) + ' iterations! **********************', + '', + '*********************************** activate plots and reports for mission study ' + '***********************************'] + else: + log_file_list = ['', + '*************************** Convergence could not be reached due to a design tool error! ' + '***************************', + '', + '*********************************** activate plots and reports for mission study ' + '***********************************'] + + ''' restore aircraft-exchange-file of last loop ''' + file_name = aircraft_exchange_file[:len(aircraft_exchange_file) - 4] + + ''' save final aircraft exchange file of mission analysis loop to results ''' + name_of_current_aircraft_exchange_file = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_study_loop/' + file_name + '_it' \ + + str(count_of_mission_study_loop) + '.xml' + destination = current_workflow_name + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files/' \ + + file_name + '_final_study_loop_file.xml' + shutil.copy(path_of_working_directory_rce + name_of_current_aircraft_exchange_file, + path_of_working_directory_rce + destination) + + # Check if the tool execution error flag is not existing and plot or report generation is not disabled + # -> if true: -> prepare module configuration files to generate plots and reports by restoring + # the pre last mission study aircraft exchange file + if not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat') \ + and (plot_output_on == 1 or report_output_on == 1 or tex_report_on == 1): + count = count_of_mission_study_loop - 1 + if count < 0: + count = 0 + name_of_current_aircraft_exchange_file = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_study_loop/' + file_name + '_it' \ + + str(count) + '.xml' + destination = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_exchange_file + shutil.copy(path_of_working_directory_rce + name_of_current_aircraft_exchange_file, destination) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Aircraft exchange file for output generation restored!') + + ''' create list of files in working directory ''' + files_in_working_directory = os.listdir(path_of_working_directory) + # loop for all elements in list of files + for file_name in files_in_working_directory: + if (file_name == 'mission_analysis') or (file_name == 'systems_design') or (file_name == 'create_mission_xml'): + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + file_name + '_conf.xml' + file_name_tree_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, file_name, + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # enable plot and/or report generation for mission study if selected in workflow configuration file + if plot_output_on == 1: + file_name_tree_root.find('./control_settings/plot_output/enable/value').text = \ + str(bool(1)).lower() + if report_output_on == 1: + file_name_tree_root.find('./control_settings/report_output/value').text = \ + str(bool(1)).lower() + if tex_report_on == 1: + file_name_tree_root.find('./control_settings/tex_report/value').text = str(bool(1)).lower() + + if write_info_files_only_at_last_step_of_iteration == 1 and write_info_files == 1: + file_name_tree_root.find('./control_settings/write_info_files/value').text = str(bool(1)).lower() + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Switch of WriteInfoFile only for last loop of study mission in ' + file_name + + '_conf.xml successfully set to active!') + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'All switches set to generate plots and reports!') + + # delete temporary mission study flag + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/perform_mission_study.dat'): + os.remove(path_of_working_directory_rce + current_workflow_name + '/temp/perform_mission_study.dat') + + else: + status_flag_to_skip = True + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Plots and reports of mission study loop were not generated!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error in study tool execution or generate plots or reports is disabled in ' + 'workflow configuration file.') + + ''' write log-file to system ''' + log_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a') + # check if error in tool execution has occurred + # -> if true: initialize loop counter with zero to skip the first four entries of log-file list + # to print to workflow console + if status_flag_to_skip: + i = 0 + # Else condition: no error in tool execution has occurred -> skip only the first three lines of log-file list + else: + i = 1 + + # loop across all elements of log-file list to print to workflow console and write to workflow log-file + for row in log_file_list: + # check if the actual loop counter is greater than 3 + # -> if true: -> print log-file list entry to workflow console + if i > 3: + print(row[character_length_of_date_and_time:]) + + # write current entry of log-file list to workflow log-file + log_file.write(row + '\n') + i += 1 + log_file.close() + + return status_flag_to_skip diff --git a/UNICADOworkflow/src/mission_study_loop/estimate_mission_study_residuals.py b/UNICADOworkflow/src/mission_study_loop/estimate_mission_study_residuals.py new file mode 100644 index 0000000000000000000000000000000000000000..8a37a33fbde481375763f6a4dbde178900f9b770 --- /dev/null +++ b/UNICADOworkflow/src/mission_study_loop/estimate_mission_study_residuals.py @@ -0,0 +1,243 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def estimate_mission_study_residuals(paths_and_names, mission_study_variables, count_of_mission_study_loop, + convergence_criteria): + """ estimate_mission_study_residuals calculates the residuals of design variables of mission study loop + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "mission_study_variables" contains the following values: + * [0][0] string: 'm_take_off_max_study_last', [0][1] float: 'value of maximum take of mass of last mission study loop' + * [1][0] string: 'mission_energy_study_last', [1][1] float: 'value of mission energy of last mission study loop' + * [2][0] string: 'range_study_last', [2][1] float: 'value of range of of last mission study loop' + * [3][0] string: 'fl_initial_cruise_study_last', [3][1] float: 'value of cruise flight level of last mission study loop' + + The input int "count_of_iteration" contains the current number of iteration loop. + + The input float "convergence_criteria" contains the convergence criteria of current iteration process. + + The output list of lists "mission_study_variables" contains the following values: + * [0][0] string: 'm_take_off_max_study', [0][1] float: 'value of maximum take off mass of current mission study loop' + * [1][0] string: 'mission_energy_study', [1][1] float: 'value of mission energy of current mission study loop' + * [2][0] string: 'range_study', [2][1] float: 'value of range of current mission study loop' + * [3][0] string: 'fl_initial_cruise_study', [3][1] float: 'value of cruise flight level of current mission study loop' + * [4][0] string: 'residual_m_take_off_max_study', [4][1] float: 'value of residual of maximum take off mass of current mission study loop' + * [5][0] string: 'residual_mission_energy_study', [5][1] float: 'value of residual of mission energy of current mission study loop' + * [6][0] string: 'residual_range_study', [6][1] float: 'value of residual of range of current mission study loop' + * [7][0] string: 'residual_fl_initial_cruise_study', [7][1] float: 'value of residual of cruise flight level of current mission study loop' + * [8][0] string: 'status_m_take_off_max_study', [8][1] bool: 'status of convergence for study take of mass' + * [9][0] string: 'status_mission_energy_study', [9][1] bool: 'status of convergence for study mission energy' + * [10][0] string: 'status_range_study', [10][1] bool: 'status of convergence for mission study range' + * [11][0] string: 'status_fl_initial_cruise_study', [11][1] bool: 'status of convergence of initial mission study flight level' + + The output list "mtom_loop_vector" contains all estimated mtom values. + + :param: paths_and_names: input list of lists + :param: mission_study_variables: input list of lists + :param: count_of_mission_study_loop: input int + :param: convergence_criteria: input float + :return: design_variables: output list of lists + """ + + ''' import for python ''' + import os + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.get_mission_energy_specific_segment import get_mission_energy_specific_segment + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + m_take_off_max_study_last = \ + ([item for item in mission_study_variables if 'm_take_off_max_study_last' in item])[-1][-1] + mission_energy_study_last = \ + ([item for item in mission_study_variables if 'mission_energy_study_last' in item])[-1][-1] + range_study_last = \ + ([item for item in mission_study_variables if 'range_study_last' in item])[-1][-1] + fl_initial_cruise_study_last = \ + ([item for item in mission_study_variables if 'fl_initial_cruise_study_last' in item])[-1][-1] + + ''' initialize local parameter ''' + log_file_list = ['', '------------------------------ Current loop of mission study: ' + + str(count_of_mission_study_loop + 1) + ' ---------', '* results:'] + status_residual_range_study = False + status_fl_initial_cruise_study = False + status_residual_mission_energy_study = False + status_residual_m_take_off_max_study = False + + function_name = getframeinfo(currentframe()).function + + ''' open and read aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + aircraft_exchange_file + root_of_aircraft_exchange_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + # read iteration variables + m_take_off_max_study = root_of_aircraft_exchange_tree.find("./analysis/mission/study_mission/takeoff_mass/value") + if m_take_off_max_study is not None: + m_take_off_max_study = float(m_take_off_max_study.text) + else: + m_take_off_max_study = 0 + + fl_initial_cruise_study = root_of_aircraft_exchange_tree.find( + "./analysis/mission/study_mission/cruise/cruise_steps/cruise_step[" + "@ID='0'" + "]/altitude/value") + if fl_initial_cruise_study is not None: + fl_initial_cruise_study = float(fl_initial_cruise_study.text) + else: + fl_initial_cruise_study = 0 + + mission_energy_study = get_mission_energy_specific_segment( + root_of_aircraft_exchange_tree, 'study_mission', 'loaded_mission_energy/mission_energy') + + range_study = root_of_aircraft_exchange_tree.find("./analysis/mission/study_mission/range/value") + if range_study is not None: + range_study = float(range_study.text) + else: + range_study = 0 + + # rel. residual m_take_off_max_study + if m_take_off_max_study > 0: + residual_m_take_off_max_study = round(abs(1 - m_take_off_max_study_last / m_take_off_max_study), 6) + if residual_m_take_off_max_study < convergence_criteria: + status_residual_m_take_off_max_study = True + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current mTOM_study: ' + str(m_take_off_max_study) + + '; Res. mTOM_study: ' + str(residual_m_take_off_max_study) + '; Convergence: ' + + str(status_residual_m_take_off_max_study)) + else: + residual_m_take_off_max_study = 1 + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current mTOM_study: ' + str(m_take_off_max_study) + '; Res. mTOM_study: ' + + str(residual_m_take_off_max_study) + '; Convergence: ' + + str(status_residual_m_take_off_max_study)) + + # rel. residual mission range + if range_study > 0: + residual_range_study = round(abs(1 - range_study_last / range_study), 6) + if residual_range_study < convergence_criteria: + status_residual_range_study = True + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current missionRange_study: ' + str(range_study) + '; Res. missionRange_study: ' + + str(residual_range_study) + '; Convergence: ' + str(status_residual_range_study)) + + else: + residual_range_study = 1 + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current missionRange_study: ' + str(range_study) + '; Res. missionRange_study: ' + + str(residual_range_study) + '; Convergence: ' + str(status_residual_range_study)) + + # rel. residual fl_initial_cruise_study + if fl_initial_cruise_study > 0: + residual_fl_initial_cruise_study = round(abs(1 - fl_initial_cruise_study_last / fl_initial_cruise_study), 6) + if residual_fl_initial_cruise_study < convergence_criteria: + status_fl_initial_cruise_study = True + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current initialCruiseFlightLevel_study: ' + str(fl_initial_cruise_study) + + '; Res. initialCruiseFlightLevel_study: ' + str(residual_fl_initial_cruise_study) + + '; Convergence: ' + str(status_fl_initial_cruise_study)) + else: + residual_fl_initial_cruise_study = 1 + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current initialCruiseFlightLevel_study: ' + str(fl_initial_cruise_study) + + '; Res. initialCruiseFlightLevel_study: ' + str(residual_fl_initial_cruise_study) + + '; Convergence: ' + str(fl_initial_cruise_study)) + + # rel. residual mission_energy + if mission_energy_study > 0: + residual_mission_energy_study = round(abs(1 - mission_energy_study_last / mission_energy_study), 6) + if residual_mission_energy_study < convergence_criteria: + status_residual_mission_energy_study = True + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current mission_energy_study: ' + str(mission_energy_study) + + '; Res. mission_energy_study: ' + str(residual_mission_energy_study) + '; Convergence: ' + + str(status_residual_mission_energy_study)) + else: + residual_mission_energy_study = 1 + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current mission_energy_study: ' + str(mission_energy_study) + '; Res. mission_energy_study: ' + + str(residual_mission_energy_study) + '; Convergence: ' + + str(status_residual_mission_energy_study)) + + ''' save aircraft-exchange-file of each loop ''' + file_name = aircraft_exchange_file[:len(aircraft_exchange_file) - 4] + file_destination = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_study_loop/' + file_name + '_it' \ + + str(count_of_mission_study_loop + 1) + '.xml' + shutil.copy(path, path_of_working_directory_rce + file_destination) + + log_file_list.append('') + + ''' write log-file to system ''' + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/workflowExecutionError.dat'): + log_file_list = ['', '------------------------------ Current loop of mission study: ' + + str(count_of_mission_study_loop + 1) + ' ---------', '', + str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error in design tool execution!', + str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'At least one of the enabled design tools has send an error. ' + 'The actual design loop is failed and will be canceled!', + str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'If parameter study or optimization is selected, ' + 'current loop of iteration will skipped and the next iteration will be performed!'] + + log_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a') + for row in log_file_list: + print(row[21:]) + log_file.write(row + '\n') + log_file.close() + + ''' append calculated design values to list of list "design_variables" ''' + mission_study_variables.append(['m_take_off_max_study', m_take_off_max_study]) + mission_study_variables.append(['mission_energy_study', mission_energy_study]) + mission_study_variables.append(['range_study', range_study]) + mission_study_variables.append(['fl_initial_cruise_study', fl_initial_cruise_study]) + mission_study_variables.append(['residual_m_take_off_max_study', residual_m_take_off_max_study]) + mission_study_variables.append(['residual_mission_energy_study', residual_mission_energy_study]) + mission_study_variables.append(['residual_range_study', residual_range_study]) + mission_study_variables.append(['residual_fl_initial_cruise_study', residual_fl_initial_cruise_study]) + mission_study_variables.append(['status_m_take_off_max_study', status_residual_m_take_off_max_study]) + mission_study_variables.append(['status_mission_energy_study', status_residual_mission_energy_study]) + mission_study_variables.append(['status_range_study', status_residual_range_study]) + mission_study_variables.append(['status_fl_initial_cruise_study', status_fl_initial_cruise_study]) + + return mission_study_variables diff --git a/UNICADOworkflow/src/mission_study_loop/final_operations_of_study_loop.py b/UNICADOworkflow/src/mission_study_loop/final_operations_of_study_loop.py new file mode 100644 index 0000000000000000000000000000000000000000..09ff80b8e854a675c0ca5dde46068d46322025b0 --- /dev/null +++ b/UNICADOworkflow/src/mission_study_loop/final_operations_of_study_loop.py @@ -0,0 +1,212 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def final_operations_of_study_loop(paths_and_names, control_settings, parameter_for_design_case): + """ final_operations_of_mission_study_loop combines the results of the mission study analysis loop to one csv file. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + :param: paths_and_names: input list of lists + :param: control_settings: input list of lists + :param: parameter_for_design_case: input list of lists + :return: none + """ + + ''' import for python ''' + import os + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + aircraft_exchange_directory = ([item for item in paths_and_names if 'aircraft_exchange_directory' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + design_mode = int(([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1]) + + ''' initialize local parameter ''' + function_name = getframeinfo(currentframe()).function + + # check if mission study analysis should not be performed (design_mode == 4) + # -> if true: -> skip final operations of mission analysis loop and perform post operations of workflow + if not design_mode == 4: + ''' create list for log-file string ''' + log_file_list = [str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Creation of plots and reports for study mission completed!', + '********************************* end activate plots and reports for study mission ' + '*********************************', + '', + '**************************************** final operations of mission study ' + '****************************************'] + + ''' paths to temporary results of current workflow ''' + path_of_mission_study_files = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/config_files/studyLoop/' + os.makedirs(path_of_mission_study_files) + + files_to_copy_list = ['create_mission_xml_conf.xml', 'systems_design_conf.xml', 'mission_analysis_conf.xml'] + for file_name in files_to_copy_list: + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + file_name): + copy_target_path = path_of_mission_study_files + file_name + # copy study mission configuration file to temporary results directory + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/' + file_name, copy_target_path) + + # open current configuration file to reset absolut paths to relativ + file_name = file_name.split('_')[0] + frame_info = getframeinfo(currentframe()) + root_of_config_tree, xml_tree = read_xml_file(copy_target_path, + path_of_working_directory_rce, + file_name, function_name, + frame_info.lineno, + log_file_list, + current_workflow_name) + + # Check if the IODir entry is in the config file + # -> if true: -> reset to relative path + if root_of_config_tree.find('./control_settings/aircraft_exchange_file_directory/value') is not None: + root_of_config_tree.find('./control_settings/aircraft_exchange_file_directory/value').text = \ + aircraft_exchange_directory + + # Check if the LogFile entry is in the config file + # -> if true: -> reset to name of file + if root_of_config_tree.find('./control_settings/log_file/value') is not None: + root_of_config_tree.find('./control_settings/log_file/value').text = \ + file_name + '.log' + + # Check if the cpacsDir entry is in the config file + # -> if true: -> reset to relative path + if root_of_config_tree.find('./control_settings/program_specific/cpacsDir/value') \ + is not None: + root_of_config_tree.find('./control_settings/program_specific/cpacsDir/value').text = \ + aircraft_exchange_directory + # write settings to configuration xml file + + xml_tree.write(copy_target_path, encoding='utf-8') + + ''' write log-file to system ''' + print('Important switches of the mission study reset to initial values!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Important switches of the mission study reset to initial values!') + + log_file_list.append('************************************** end final operations of mission study ' + '**************************************') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + else: + log_file_list = [''] + + # set switches in create_mission_xml_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/create_mission_xml_conf.xml' + create_mission_conf_xml_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'create_mission_xml', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # Change switch from study mission to requirement mission, in order to create a requirement mission + create_mission_conf_xml_root.find('./program_settings/mission_selector/value').text = "requirements_mission" + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + # set switches in systems_design_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/systems_design_conf.xml' + systems_design_conf_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'systems_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # Change switch from design mission to study mission, + # in order to calculate systems characteristics for a requirement mission + systems_design_conf_root.find('./program_settings/mission_mode/value').text = "requirement" + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + # set switches in mission_analysis_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/mission_analysis_conf.xml' + mission_analysis_conf_xml_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'mission_analysis', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # for a requirement mission - set mode to requirement_mission + mission_analysis_conf_xml_root.find('./program_settings/mode/mission_methods/mission_type/value').text = \ + "requirements_mission" + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') \ No newline at end of file diff --git a/UNICADOworkflow/src/mission_study_loop/initialize_mission_study_analysis.py b/UNICADOworkflow/src/mission_study_loop/initialize_mission_study_analysis.py new file mode 100644 index 0000000000000000000000000000000000000000..73392ff616183c3fc808a32c4c0b7c308ebe3a76 --- /dev/null +++ b/UNICADOworkflow/src/mission_study_loop/initialize_mission_study_analysis.py @@ -0,0 +1,341 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def initialize_mission_study_analysis(paths_and_names, control_settings, parameter_for_design_case, + module_list_of_sizing_loop): + """ initialize_mission_study_analysis initialize the mission study sizing loop to perform off design analysis. + Set initial design variables of mission study analysis to output list of lists. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The input list of lists "module_list_of_sizing_loop" is a dynamic list of used sizing loop modules of current workflow execution: + * [:][0] string: 'sizing_loop_module', [0][:] string: 'name of the used sizing loop module of current workflow execution' + + The output list of lists "mission_study_variables" contains the following values: + * [0][0] string: 'm_take_off_max_study', [0][1] float: 'value of initial maximum take off mass of mission study' + * [1][0] string: 'mission_energy_study', [1][1] float: 'value of initial mission energy of mission study' + * [2][0] string: 'range_study', [2][1] float: 'value of initial range of mission study' + * [3][0] string: 'fl_initial_cruise_study', [3][1] float: 'value of initial cruise flight level of mission study' + + :param: paths_and_names: input list of lists + :param: control_settings: input list of lists + :param: parameter_for_design_case: input list of lists + :param: module_list_of_sizing_loop: input list of lists + :return: mission_study_variables: output list of lists + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.get_mission_energy_specific_segment import get_mission_energy_specific_segment + from sub_function.write_to_log_file import write_to_log_file + + ''' create list for log-file string ''' + log_file_list = [str(datetime.now().strftime( + '%Y-%m-%d %H:%M:%S')) + ': Generation of plots and reports of design sizing loop finished!', + '****************************************** end activate plots and reports ' + '******************************************', + '', + '**************************************** initialize mission study analysis ' + '****************************************'] + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory = ([item for item in paths_and_names if 'path_of_working_directory' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + write_info_files = ([item for item in control_settings if 'write_info_files' in item])[-1][-1] + write_info_files_only_at_last_step_of_iteration = \ + ([item for item in control_settings if 'write_info_files_only_at_last_step_of_iteration' in item])[-1][-1] + switch_off_plots = int(([item for item in control_settings if 'switch_off_plots' in item])[-1][-1]) + switch_off_reports = int(([item for item in control_settings if 'switch_off_reports' in item])[-1][-1]) + switch_off_tex = int(([item for item in control_settings if 'switch_off_tex' in item])[-1][-1]) + + count_of_iteration = ([item for item in parameter_for_design_case if 'count_of_iteration' in item])[-1][-1] + design_mode = int(([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1]) + + function_name = getframeinfo(currentframe()).function + + # check if mission study analysis should not be performed (design_mode == 4) + # -> if true: -> skip mission analysis loop and perform post operations of workflow + if not design_mode == 4: + ''' restore aircraft-exchange-file of last loop ''' + # The -4 removes the file extension ".xml" from the passed string + file_name = aircraft_exchange_file[:len(aircraft_exchange_file) - 4] + + # check if convergence or maximum iteration steps reached + if not count_of_iteration == 0: + file_source = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' \ + + file_name + '_finalLoop.xml' + destination = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_exchange_file + shutil.copy(path_of_working_directory_rce + file_source, destination) + print('Aircraft exchange file for mission study loop restored!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Aircraft exchange file for mission study loop restored!') + + # copy and remove old file + ''' save aircraft exchange files to results folder ''' + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files'): + os.makedirs(path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files') + + if not count_of_iteration == 0: + file = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_sizing_loop/' \ + + file_name + '_finalLoop.xml' + shutil.copy(path_of_working_directory_rce + file, + path_of_working_directory_rce + current_workflow_name + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files/' + file_name + + '_final_sizing_loop_file.xml') + os.remove(path_of_working_directory_rce + file) + + ''' open and read aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_exchange_file + root_of_aircraft_exchange_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, + frame_info.lineno, log_file_list, + current_workflow_name) + + # read variables for missionStudy iteration + m_take_off_max_study = root_of_aircraft_exchange_tree.find( + "./analysis/mission/study_mission/takeoff_mass/value") + if m_take_off_max_study is not None: + m_take_off_max_study = float(m_take_off_max_study.text) + else: + m_take_off_max_study = 0 + + range_study = root_of_aircraft_exchange_tree.find( + "./analysis/mission/study_mission/range/value") + if range_study is not None: + range_study = float(range_study.text) + else: + range_study = 0 + + fl_initial_cruise_study = root_of_aircraft_exchange_tree.find( + "./analysis/mission/study_mission/cruise/cruise_steps/cruise_step/altitude/value") + if fl_initial_cruise_study is not None: + fl_initial_cruise_study = float(fl_initial_cruise_study.text) + else: + fl_initial_cruise_study = 0 + + mission_study_variables = [['m_take_off_max_study', m_take_off_max_study], + ['mission_energy_study', get_mission_energy_specific_segment( + root_of_aircraft_exchange_tree, 'study_mission', + 'loaded_mission_energy/mission_energy')], + ['range_study', range_study], + ['fl_initial_cruise_study', fl_initial_cruise_study]] + + ''' paths to temporary results of current workflow ''' + path_of_mission_study_files = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/config_files/preExecution/studyLoop/' + os.makedirs(path_of_mission_study_files) + + # copy aircraft exchange file to temporaryResults directory + path_of_mission_study_exchange_files = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_study_loop/' + os.makedirs(path_of_mission_study_exchange_files) + shutil.copy(path, path_of_mission_study_exchange_files + aircraft_exchange_file[:-4] + '_it0.xml') + + ''' Convert switches in config file to analysis mode ''' + # set switches in create_mission_xml_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/create_mission_xml_conf.xml' + create_mission_conf_xml_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'create_mission_xml', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # Change switch from design mission to study mission, in order to create a study mission + create_mission_conf_xml_root.find('./program_settings/mission_selector/value').text = "study_mission" + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + # copy create_mission_xml_conf.xml file to temporaryResults directory + shutil.copy(path, path_of_mission_study_files + 'create_mission_xml_conf.xml') + + # set switches in systems_design_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/systems_design_conf.xml' + systems_design_conf_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'systems_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # Change switch from design mission to study mission, + # in order to calculate systems characteristics for a study mission + systems_design_conf_root.find('./program_settings/mission_mode/value').text = "study" + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + # copy systems_design_conf.xml file to temporaryResults directory + shutil.copy(path, path_of_mission_study_files + 'systems_design_conf.xml') + + # set switches in mission_analysis_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/mission_analysis_conf.xml' + mission_analysis_conf_xml_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'mission_analysis', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # for a study mission - switch off the MTOM estimation + mission_analysis_conf_xml_root.find('./program_settings/mode/mission_methods/mission_type/value').text = \ + "study_mission" + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + # copy mission_analysis_conf.xml file to temporaryResults directory + shutil.copy(path, path_of_mission_study_files + 'mission_analysis_conf.xml') + + ''' create list of files in working directory ''' + files_in_working_directory = os.listdir(path_of_working_directory) + # Check if switch switchOfPlots set to active + if switch_off_plots == 1 or switch_off_reports == 1 or switch_off_tex == 1: + # loop for all elements in list of files to find the necessary tools to perform mission study loop + for file_name in files_in_working_directory: + if (file_name == 'mission_analysis') or (file_name == 'systems_design') \ + or (file_name == 'create_mission_xml'): + # disable plot and report generation for mission study + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + file_name + '_conf.xml' + file_name_tree_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, file_name, + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + if switch_off_plots == 1: + file_name_tree_root.find('./control_settings/plot_output/enable/value').text = \ + str(bool(0)).lower() + if switch_off_reports == 1: + file_name_tree_root.find('./control_settings/report_output/value').text = str(bool(0)).lower() + if switch_off_tex == 1: + file_name_tree_root.find('./control_settings/tex_report/value').text = str(bool(0)).lower() + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + ''' Write info file after last step of sizing loop iteration ''' + # Check if attribute 'onlyAtLastStepOfIteration' of 'WriteInfoFiles' and is the switch them self equal to 1 + # -> if true: -> activate writeInfoFiles in sizing loop configuration files only for the last loop of iteration + if write_info_files_only_at_last_step_of_iteration == 1 and write_info_files == 1: + i = 0 + for _ in module_list_of_sizing_loop: + module_name = module_list_of_sizing_loop[i][-1] + # try to open module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + module_name + '_conf.xml' + file_name_tree_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, file_name, + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + file_name_tree_root.find('./control_settings/write_info_files/value').text = str(bool(0)).lower() + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + print('Switch of WriteInfoFile only for last step of iteration in ' + module_name + + '_conf.xml successfully set to inactive!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Switch of WriteInfoFile only for last step of iteration in ' + module_name + + '_conf.xml successfully set to inactive!') + i += 1 + + ''' write log-file to system ''' + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'All switches set to perform mission study sizing loop!') + log_file_list.append('*************************************** end initialize mission study analysis ' + '***************************************') + log_file_list.append('') + log_file_list.append('****************************************** Start Mission Study Iteration! ' + '******************************************') + log_file_list.append('') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + else: + mission_study_variables = [['m_take_off_max_study', 0.0], + ['mission_energy_study', 0.0], + ['range_study', 0.0], + ['fl_initial_cruise_study', 0.0]] + + return mission_study_variables diff --git a/UNICADOworkflow/src/mission_study_loop/post_operation_of_mission_study_analysis.py b/UNICADOworkflow/src/mission_study_loop/post_operation_of_mission_study_analysis.py new file mode 100644 index 0000000000000000000000000000000000000000..81fc92d54b9b8ae4be9db5f3559a9f3967b5730f --- /dev/null +++ b/UNICADOworkflow/src/mission_study_loop/post_operation_of_mission_study_analysis.py @@ -0,0 +1,220 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def post_operation_of_mission_study_analysis(paths_and_names, mission_study_variables, control_settings, + count_of_mission_study_loop, convergence_criteria, + mission_study_iteration_flag): + """ post_operation_of_mission_Study_analysis prepares mission study variables for converge component of RCE and calculates the residuals of study variables. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "mission_study_variables" contains the following values: + * [0][0] string: 'm_take_off_max_study_last', [0][1] float: 'value of maximum take of mass of last mission study loop' + * [1][0] string: 'mission_energy_study_last', [1][1] float: 'value of mission energy of last mission study loop' + * [2][0] string: 'range_study_last', [2][1] float: 'value of range of of last mission study loop' + * [3][0] string: 'fl_initial_cruise_study_last', [3][1] float: 'value of cruise flight level of last mission study loop' + + The input list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The input float "convergence_criteria" contains the convergence criteria of current iteration process. + + The input float "mission_study_iteration_flag" contains the status of the mission study loop is finished or not. + + The output list of lists "mission_study_variables" contains the following values: + * [0][0] string: 'm_take_off_max_study', [0][1] float: 'value of maximum take off mass of current mission study loop' + * [1][0] string: 'mission_energy_study', [1][1] float: 'value of mission energy of current mission study loop' + * [2][0] string: 'range_study', [2][1] float: 'value of range of current mission study loop' + * [3][0] string: 'fl_initial_cruise_study', [3][1] float: 'value of cruise flight level of current mission study loop' + * [4][0] string: 'residual_m_take_off_max_study', [4][1] float: 'value of residual of maximum take off mass of current mission study loop' + * [5][0] string: 'residual_mission_energy_study', [5][1] float: 'value of residual of mission energy of current mission study loop' + * [6][0] string: 'residual_range_study', [6][1] float: 'value of residual of range of current mission study loop' + * [7][0] string: 'residual_fl_initial_cruise_study', [7][1] float: 'value of residual of cruise flight level of current mission study loop' + * [8][0] string: 'status_m_take_off_max_study', [8][1] bool: 'status of convergence for study take of mass' + * [9][0] string: 'status_mission_energy_study', [9][1] bool: 'status of convergence for study mission energy' + * [10][0] string: 'status_range_study', [10][1] bool: 'status of convergence for mission study range' + * [11][0] string: 'status_fl_initial_cruise_study', [11][1] bool: 'status of convergence of initial mission study flight level' + + The output list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The output float "mission_study_iteration_flag" contains the status of the mission study loop is finished or not. + + :param: paths_and_names: input list of lists + :param: mission_study_variables: input list of lists + :param: control_settings: input list of lists + :param: count_of_mission_study_loop: input integer + :param: convergence_criteria: input float + :param: mission_study_iteration_flag: input float + :return: mission_study_variables: output list of lists, control_settings: output list of lists + """ + + ''' import for python ''' + import shutil + from mission_study_loop.estimate_mission_study_residuals import estimate_mission_study_residuals + from mission_study_loop.save_mission_study_results_to_file import save_mission_study_results_to_file + from mission_study_loop.activate_plots_and_reports_for_mission_study import\ + activate_plots_and_reports_for_mission_study + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + ''' initialize local parameter ''' + status_flag_to_skip_study_mission = \ + int(([item for item in control_settings if 'status_flag_to_skip_study_mission' in item])[-1][-1]) + + if status_flag_to_skip_study_mission == 0: + ''' save iteration parameter to csv-file ''' + # call function to estimate residuals of mission study loop + mission_study_variables = estimate_mission_study_residuals(paths_and_names, mission_study_variables, + count_of_mission_study_loop, convergence_criteria) + + ''' estimate relative residuals of iteration variables ''' + save_mission_study_results_to_file(paths_and_names, mission_study_variables, count_of_mission_study_loop) + + ''' damp mtom value for the next loop if mtom damping is selected in workflow configuration file ''' + status_residual_m_take_off_max =\ + ([item for item in mission_study_variables if 'status_m_take_off_max_study' in item])[-1][-1] + status_residual_mission_energy = \ + ([item for item in mission_study_variables if 'status_mission_energy_study' in item])[-1][-1] + status_range_study = \ + ([item for item in mission_study_variables if 'status_range_study' in item])[-1][-1] + status_fl_initial_cruise_study = \ + ([item for item in mission_study_variables if 'status_fl_initial_cruise_study' in item])[-1][-1] + + # check if convergence criteria of each iteration variable is reached + # -> if true: -> send converged output flag to converge module of RCE + if status_residual_m_take_off_max and status_residual_mission_energy and status_range_study \ + and status_fl_initial_cruise_study: + + plot_output_on = int(([item for item in control_settings if 'plot_output_on' in item])[-1][-1]) + report_output_on = int(([item for item in control_settings if 'report_output_on' in item])[-1][-1]) + tex_report_on = int(([item for item in control_settings if 'tex_report_on' in item])[-1][-1]) + status_flag_to_skip_study_mission = \ + int(([item for item in control_settings if 'status_flag_to_skip_study_mission' in item])[-1][-1]) + + # check if the current loop is the last one or if the generation of plots and reports should be performed + if not status_flag_to_skip_study_mission == 1: + # check if at least on report should be generated + if plot_output_on == 1 or report_output_on == 1 or tex_report_on == 1: + status_flag_to_skip = activate_plots_and_reports_for_mission_study(paths_and_names, + control_settings, + count_of_mission_study_loop) + + # check if an error is occurred during plot activation + # -> if true: -> send trigger signal to close loop + if status_flag_to_skip: + # set trigger signal to close mission study loop + mission_study_iteration_flag = mission_study_iteration_flag + else: + # add +100 to iteration flag to prevent the converger-unit closing the loop before finishing it + mission_study_iteration_flag += 100.0 + ([item for item in control_settings if 'status_flag_to_skip_study_mission' in item])[-1][-1] = \ + int(1) + + # else condition: plot and report generation disabled -> generate finale aircraft exchange file + else: + file_name = aircraft_exchange_file[:len(aircraft_exchange_file) - 4] + name_of_current_aircraft_exchange_file =\ + current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/aircraft_exchange_files_of_study_loop/' \ + + file_name + '_it' + str(count_of_mission_study_loop) + '.xml' + destination = current_workflow_name \ + + '/temporaryResults/aircraft_exchange_files/final_aircraft_exchange_files/' \ + + file_name + '_final_study_loop_file.xml' + shutil.copy(path_of_working_directory_rce + name_of_current_aircraft_exchange_file, + path_of_working_directory_rce + destination) + + # else condition: send trigger signal to close mission study loop + else: + # set trigger signal to close mission study loop + mission_study_iteration_flag = mission_study_iteration_flag + + # else condition: convergence of each iteration variable is not reached + # -> add +100 to output flag to prevent the converger-unit closing the loop before finishing it + else: + mission_study_iteration_flag += 100.0 + + else: + count_of_mission_study_loop -= 1 + mission_study_iteration_flag = mission_study_iteration_flag + + return mission_study_variables, control_settings, count_of_mission_study_loop, mission_study_iteration_flag diff --git a/UNICADOworkflow/src/mission_study_loop/save_mission_study_results_to_file.py b/UNICADOworkflow/src/mission_study_loop/save_mission_study_results_to_file.py new file mode 100644 index 0000000000000000000000000000000000000000..d7adc9aa599cea90204aba7e6992c6f584278cc2 --- /dev/null +++ b/UNICADOworkflow/src/mission_study_loop/save_mission_study_results_to_file.py @@ -0,0 +1,129 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def save_mission_study_results_to_file(paths_and_names, mission_study_variables, count_of_mission_study_loop): + """ save_mission_study_results_to_file writes all mission study results to output csv-file. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "mission_study_variables" contains the following values: + * [0][0] string: 'm_take_off_max_study', [0][1] float: 'value of maximum take off mass of current mission study loop' + * [1][0] string: 'mission_energy_study', [1][1] float: 'value of mission energy of current mission study loop' + * [2][0] string: 'range_study', [2][1] float: 'value of range of current mission study loop' + * [3][0] string: 'fl_initial_cruise_study', [3][1] float: 'value of cruise flight level of current mission study loop' + * [4][0] string: 'residual_m_take_off_max_study', [4][1] float: 'value of residual of maximum take off mass of current mission study loop' + * [5][0] string: 'residual_mission_energy_study', [5][1] float: 'value of residual of mission energy of current mission study loop' + * [6][0] string: 'residual_range_study', [6][1] float: 'value of residual of range of current mission study loop' + * [7][0] string: 'residual_fl_initial_cruise_study', [7][1] float: 'value of residual of cruise flight level of current mission study loop' + * [8][0] string: 'status_residual_m_take_off_max', [8][1] bool: 'status of convergence for study take of mass' + * [9][0] string: 'status_residual_mission_energy', [9][1] bool: 'status of convergence for study mission energy' + * [10][0] string: 'status_range_study', [10][1] bool: 'status of convergence for mission study range' + * [11][0] string: 'status_fl_initial_cruise_study', [11][1] bool: 'status of convergence of initial mission study flight level' + + The input int "count_of_mission_study_loop" contains the current number of calibration loop. + + :param: paths_and_names: input list of lists + :param: mission_study_variables: input list of lists + :param: count_of_mission_study_loop: input int + :return: none + """ + + ''' imports for python ''' + import os + + ''' read data for script execution ''' + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + ''' initialize local parameter ''' + results = [] + reporting_of_ome_calibration = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/reporting/' + + ''' check if output temporary reporting folder exist ''' + if not os.path.isdir(reporting_of_ome_calibration): + os.makedirs(reporting_of_ome_calibration) + + ''' prepare output data for csv-file ''' + # check if first loop of iteration -> if true: -> generate file header + if count_of_mission_study_loop == 0: + # generate header + results.append('count_of_iteration; ' + 'm_take_off_max in kg; ' + 'residual_m_take_off_max; ' + 'mission_energy in J; ' + 'residual_mission_energy; ' + 'fl_initial_cruise; ' + 'residual_fl_initial_cruise; ' + 'range in nm; ' + 'residual_range;') + + # save initial values to csv-file + results.append(str(count_of_mission_study_loop) + ';' + + str(0.00) + + 'nan;' + + str(0.00) + + 'nan;' + + str(0.00) + ';' + + 'nan;' + + str(0.000) + ';' + + 'nan;') + + count_of_mission_study_loop += 1 + + results.append(str(count_of_mission_study_loop) + ';' + + str(round(([item for item in mission_study_variables + if 'm_take_off_max_study' in item])[-1][-1], 2)) + ';' + + str(round(([item for item in mission_study_variables + if 'residual_m_take_off_max_study' in item])[-1][-1], 6)) + ';' + + str(round(([item for item in mission_study_variables + if 'mission_energy_study' in item])[-1][-1], 2)) + ';' + + str(round(([item for item in mission_study_variables + if 'residual_mission_energy_study' in item])[-1][-1], 6)) + ';' + + str(round(([item for item in mission_study_variables + if 'fl_initial_cruise_study' in item])[-1][-1], 2)) + ';' + + str(round(([item for item in mission_study_variables + if 'residual_fl_initial_cruise_study' in item])[-1][-1], 1)) + ';' + + str(round(([item for item in mission_study_variables + if 'range_study' in item])[-1][-1], 2)) + ';' + + str(round(([item for item in mission_study_variables + if 'residual_range_study' in item])[-1][-1], 6)) + ';') + + results_file = open(reporting_of_ome_calibration + 'study_loop_results.csv', 'a') + for row in results: + results_file.write(row + '\n') + results_file.close() + + return diff --git a/UNICADOworkflow/src/optimization/_kernel.py b/UNICADOworkflow/src/optimization/_kernel.py new file mode 100644 index 0000000000000000000000000000000000000000..0fa1131eddf2954769839a2092b733d2e901f2fd --- /dev/null +++ b/UNICADOworkflow/src/optimization/_kernel.py @@ -0,0 +1,151 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +""" +A kind of sub-module of a stand-alone module gaussianProcess.py + +Author: Daigo Maruyama +Technical contact: d.maruyama@tu-braunschweig.de +""" + +### standard libraries (includig numpy, scipy) ### +import numpy as np + + +class _Kernel: + def __init__(self, X): + self._X = X + self._N, self._D = X.shape + + def covariance(self, K=None): # so-called Gram matrix + """ + Create the covariance matrix (so called Gram matrix). + + :param K: a covariance matrix (square and symmetric matrix) + :type K: np.ndarray (2D) + """ + if K is None: + K = np.zeros( (self._N, self._N), dtype=np.float64 ) + self._computeKernel(K) + return K + + def vectorPrediction(self, x, k=None): # correlation vector + """ + The number of thepredicted point is fixed at 1 (Nnew=1), not multiple points. + + :param x: arbitrary single point of the input + :type x: np.ndarray (1D) + :param k: a part of the whole covariance matrix when a prediction input x is included + :type k: np.ndarray (1D) + """ + if k is None: + k = np.zeros( (self._N, 1), dtype=np.float64 ) + self._computeKernel(k, x) + return k + + def scalarPrediction(self, x, k=None): # k + """ + The number of thepredicted point is fixed at 1 (Nnew=1), not multiple points. + + :param x: arbitrary single point of the input + :type x: np.ndarray (1D) + :param k: a diagonal part of the whole covariance matrix when a prediction input x is included + :type k: float + """ + if k is None: + k = 0. + k += self._kernelDiag(x) + return k + + def _kernel(self, x1, x2): + raise NotImplementedError("Do not directly access here.") + + def _kernelDiag(self, x): + raise NotImplementedError("Do not directly access here.") + + def _computeKernel(self, K, x=None): + if x is None: + for i in range(self._N): + K[i,i] += self._kernelDiag(self._X[i]) + for j in range(i+1, self._N): + K[i,j] += self._kernel(self._X[i], self._X[j]) + K[j,i] = K[i,j] + else: + for i in range(self._N): + K[i,0] += self._kernel(self._X[i], x) + + +class GaussianKernel(_Kernel): + def __init__(self, X, theta, p=2): + _Kernel.__init__(self, X) + self._theta = theta + self._p = p + + def _kernel(self, x1, x2): + c = sum( [ float(np.power(10,self._theta[i], dtype=np.float64)) * np.power( abs(float(x1[i])-float(x2[i])), self._p, dtype=np.float64 ) for i in range(self._D) ] ) + return np.exp(-float(c), dtype=np.float64) + + def _kernelDiag(self, x): + return 1. + +class ConstantKernel(_Kernel): + def __init__(self, X, theta): # X is actully not used at all. + _Kernel.__init__(self, X) + self._theta = theta + + def _computeKernel(self, K, x=None): # due to the property of this kernel, x is actually not used. + if x is None: + for i in range(self._N): + K[i,i] += self._kernelDiag() + for j in range(i+1, self._N): + K[i,j] += self._kernel() + K[j,i] = K[i,j] + else: + for i in range(self._N): + K[i,0] += self._kernel() + + def _kernel(self, x1=None, x2=None): + return self._theta + + def _kernelDiag(self, x=None): + return self._theta + +class LinearKernel(_Kernel): + def __init__(self, X, theta): + _Kernel.__init__(self, X) + self._theta = theta + + def _kernel(self, x1, x2): + return self._theta * np.dot(float(x1), float(x2)) + + def _kernelDiag(self, x): + return self._kernel(x, x) + +class RegularizationKernel(_Kernel): + def __init__(self, X, theta): + _Kernel.__init__(self, X) + self._theta = theta + + def _kernel(self, x1=None, x2=None): + return 0. + + def _kernelDiag(self, x): + return float(np.power(10,self._theta, dtype=np.float64)) # x is not used. + diff --git a/UNICADOworkflow/src/optimization/_main.py b/UNICADOworkflow/src/optimization/_main.py new file mode 100644 index 0000000000000000000000000000000000000000..691c883c122ffb69dfb2ecad4640e770634913d0 --- /dev/null +++ b/UNICADOworkflow/src/optimization/_main.py @@ -0,0 +1,161 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +import numpy as np +import sys +import os +import time +import userinput # userinput file, which defines "formulation" +import optimization # The API file of the package + +""" +The main file to execute EGO (Efficient Global Optimization) described by optimization.py +run: python main.py +in this package + +Author: Daigo Maruyama +Technical contact: d.maruyama@tu-braunschweig.de +""" + +''' initialize local parameter ''' +# absolute path to working directory of current workflow execution +# Attention this path will set dynamically during workflow execution!!! Do not enter anything here!!! +path_to_current_working_dir = 'path' + +# --- 1. Formulation ----------------------------------------------------------------------------- +# The ingredients for the formulation is extracted from the module "userinput". +functions = userinput.functionsUNICADO +x_bounds, g_bounds = userinput.boundary_preparation_unicado(path_to_current_working_dir) +formulation = optimization.Formulation(functions, x_bounds, g_bounds) + +# ------------------------------------------------------------------------------------------------ + +# --- 1.5. (optional: ordinary optimization) --- +# xopt, yopt = formulation.ordinary() +# print("xopt =", xopt) +# print("yopt =", yopt) +# ---------------------------------------------- + +# --- 2. Optimization (EGO) ---------------------------------------------------------------------- +""" +User-Input: + +Define additional parameters for Bayesian optimization +N + Nimposed = "Total computational cost" + +The computation in gaussianProcess.py sometimes stops during the optimization of the likelihood function due to violated values of the hyperparameer theta. In that case, please run it again. Random effects are integrated in the algorithm. The solutions for this are related to the issue 1 in below. This process will be improved to be robust. + +Notes on accuracy vs efficiency: +1. The greater "multiStart" is, the higher the accuracy and the robustness of the result is. However, the complexity of the computational cost becomes squre proportional to the number of "multiStart". +2. The computational costs (of the surrogate model part) is CUBIC proportional to the number of sample size (N+Nimposed) + (Strictly to say, the rank of the covariance matrix in K in gaussianProcess.py) +The issues 1 and 2 arise independently of each other. Further computational time can be accelerated by using cython, etc. + +Solutions for issue 1: There are various approaches. The efficiency is dependent on cases for users. + - multistart with random with evolutional algorithm + - multistart with random initial point with gradient-based opt +Solutions for issue 2: Approximated methods - summarized in the deliverable (in 2020) +""" + +# --- example of User-Input --- +""" +Indication of sample size: + +1D: +N = 5 +Nimposed = 3 + +2D: +N = 30 to 50 +Nimposed = 10 + +2Dconstraints: +N = 30 to 50 (or N=10, Nimposed=30) +Nimposed = 10 +""" +''' +N = 10#5#50 # initial sample size +Nimposed = 30#10 # additional sample size searched in the process of Bayesian optimization +proc = 1 # the number of processors allocated for one simulation when run in parallel + +# some parameters for surrogate models (Details of the parameter explanation ca be seen in gaussianProcess.py) +regularization = True # False: The surrogate model passes through all the sample points. True: No guarantee that the surrogate model passes through all the sample points. However, higher probability that the less errors in the processes related to surrogate models. The sample points are assumed to have a monovariate Gaussian noise. +# kernelmodel = {"Gaussian": True, "Constant": False, "Linear": False} +# trend = "ordinary" # "simple" or "ordinary" +doeMethod = "Sobol" # "LHS" or "Halton" or "Sobol" + +method = "EIPI" # "EI" or "EIPI" or some others +multiStart = 1#10 # greter: higher accuracy but lower efficiency. multi trials of the optimization of the likelihood function (and the acquisition function as well) to make the surrogate models more robust (the computational time for the construction becomes larger.). If gradientOptSurrogate is True, higher number can be an option for the robustness (avoiding local optimal). +### ----------------------------- ### +gradientOptSurrogate = False # method to optimize the likelihood function in constructing surrogate models, True: BFGS +''' + +''' initialize optimization parameter ''' +# read optimization settings from optimization configuration file +N, Nimposed, proc, regularization, doeMethod, method, multiStart, gradientOptSurrogate = \ + userinput.read_optimization_settings(path_to_current_working_dir) + +multiFidelity = False#True + +''' +Parameters defined inside EGO : + self._regularization = regularization + self._basisFunction = basisFunction + self._doeMethod = doeMethod + self._kernelmodel = kernelmodel + self._multiStart = multiStart + self._trend = 0. + + # temporary for my graph + self._N = N + self._Nimposed = Nimposed + self._activeLearningMethod = activeLearningMethod +''' + +if multiFidelity == False: + xopt, yopt = formulation.EGO(N, Nimposed, proc, regularization = regularization, doeMethod= doeMethod, multiStart= multiStart) +# elif multiFidelity == True: +# xopt, yopt = formulation.EGO(N, Nimposed, proc).MFEGO(Nlow, N, Nimposed, proc) + +print("xopt =", xopt) # optimal solution of the design variable +print("yopt =", yopt) # optimal solution of the cost function +print("Running parallel function is also fine.\n") +print("Terminated normally") + +# visualization (only after Bayesian opt) +input_dim = len(x_bounds) +if input_dim == 1 or input_dim == 2: + formulation.visualization(Npre=100) # Npre: the number of grid for each dimension + +for i in range(1+len(g_bounds)): + print("sensitivity for each function =", formulation.surrogate[i].automatic_relevance_determination()) + +''' write finish flag to temporary working directory to terminate workflow execution ''' +if not os.path.isfile(path_to_current_working_dir + '/temp/optimizationFinishFlag.dat'): + with open(path_to_current_working_dir + '/temp/optimizationFinishFlag.dat', 'w') as file: + file.close() + +time.sleep(3) + +''' delete workflow semaphore to finish workflow ''' +# check if the semaphore wait flag for the optimization framework is existing +# -> if true: -> remove flag to execute optimization framework +if os.path.isfile(path_to_current_working_dir + '/temp/semaphoreFlagOptimization.dat'): + os.remove(path_to_current_working_dir + '/temp/semaphoreFlagWorkflowExecution.dat') diff --git a/UNICADOworkflow/src/optimization/_userinput.py b/UNICADOworkflow/src/optimization/_userinput.py new file mode 100644 index 0000000000000000000000000000000000000000..e40f0b39b19c58b3d8759475422226cafc68d49a --- /dev/null +++ b/UNICADOworkflow/src/optimization/_userinput.py @@ -0,0 +1,590 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +# imports for python +import csv +import numpy as np +import os +import sys +import time +import xml.etree.ElementTree +import subprocess, sys, shlex, shutil, os, time +import xml.etree.ElementTree as ET +from datetime import datetime + +""" +Userinput file to define a blackbox function which returns all the output values to be evaluated (one cost function ++ arbitrary number of constraints) for an input vector x, which is design variables (Userinput1). +The search bounds of the design variables are also required to be defined (Userinput2). +Then, based this rule please adjust the blackbox function for your optimization formulation. + +Author: Daigo Maruyama +Technical contact: d.maruyama@tu-braunschweig.de +""" + + +def read_optimization_settings(path_to_current_working_dir): + """ + Preparation of optimization settings to run the optimization framework. + + * The input string 'path_to_current_working_dir' contains the system path of working directory of current workflow execution. + + * The output integer 'n' contains the number of initial samples. + + * The output integer 'n_imposed' contains the number of imposed samples. + + * The output integer 'proc' contains the number of processors to use. + + * The output bool 'regularization' contains the True or False flag for pass surrogate model through all sample points. + + * The output string 'doe_method' contains the name of the doe methode which should be used. + + * The output string 'method' contains the name of the methode which should be used. + + * The output integer 'multi_start' contains the value which accuracy should be reached. + + * The output bool 'gradient_opt_surrogate' contains the status flag which surrogate mode should be used. + + :param: path_to_current_working_dir, input string + :return: x_bounds_unicado, output numpy array; g_bounds_unicado, output numpy array + """ + + # try to read optimization configuration file + try: + xml_tree = xml.etree.ElementTree.ElementTree(file=path_to_current_working_dir + '/optimization_conf.xml') + root_of_optimization_tree = xml_tree.getroot() + + n = int(root_of_optimization_tree.find( + './ProgramSettings/OptimizationSettings/numberOfInitialSamples').text) + n_imposed = int(root_of_optimization_tree.find( + './ProgramSettings/OptimizationSettings/numberOfImposedSamples').text) + proc = int(root_of_optimization_tree.find( + './ProgramSettings/OptimizationSettings/numberOfProcessors').text) + regularization = bool(int(root_of_optimization_tree.find( + './ProgramSettings/OptimizationSettings/regularization').text)) + doe_method = str(root_of_optimization_tree.find( + './ProgramSettings/OptimizationSettings/doeMethod').text) + method = str(root_of_optimization_tree.find( + './ProgramSettings/OptimizationSettings/method').text) + multi_start = int(root_of_optimization_tree.find( + './ProgramSettings/OptimizationSettings/multiStart').text) + gradient_opt_surrogate = bool(int(root_of_optimization_tree.find( + './ProgramSettings/OptimizationSettings/gradientOptSurrogate').text)) + + except OSError: + print('ERROR: The optimization configuration file of current workflow execution could not be opened or is ' + 'corrupt!\n' + ' Optimization could not be performed! The optimization framework is aborted!') + sys.exit(1) + + return n, n_imposed, proc, regularization, doe_method, method, multi_start, gradient_opt_surrogate + + +def boundary_preparation_unicado(path_to_current_working_dir): + """ + Preparation of upper and lower boundaries of design variables and requirements for UNICADO function. + + * The input string 'path_to_current_working_dir' contains the system path of working directory of current workflow execution. + + :param: path_to_current_working_dir, input string + :return: x_bounds_unicado, output numpy array; g_bounds_unicado, output numpy array + """ + + # constants + feet = 0.304800609601219 + + ''' read design variable-, cost function- and design requirement keys from optimization configuration file ''' + try: + xml_tree = xml.etree.ElementTree.ElementTree(file=path_to_current_working_dir + '/optimization_conf.xml') + root_of_optimization_tree = xml_tree.getroot() + + # read upper and lower boundaries of design variables + x_bounds_unicado = [] + number_of_design_variables = int(root_of_optimization_tree.find( + './ProgramSettings/designParameter/designVariables').text) + + for i in range(0, number_of_design_variables): + # read lower boundary of design variables and check for infinity + lower_boundary = root_of_optimization_tree.find( + "./ProgramSettings/designParameter/designVariable[" + "@ID='" + str(i) + "'" + + "]lowerBoundary").text + if lower_boundary == 'inf': + lower_boundary = np.inf + elif lower_boundary == '-inf': + lower_boundary = -np.inf + else: + lower_boundary = float(lower_boundary) + + # read unit of lower boundary of design variables and check for "feet" or "ft" + lower_boundary_unit = root_of_optimization_tree.find( + "./ProgramSettings/designParameter/designVariable[" + "@ID='" + str(i) + "'" + + "]lowerBoundary").get('Unit') + if lower_boundary_unit == 'feet' or lower_boundary == 'ft': + lower_boundary *= feet + + # read upper boundary of design variables and check for infinity + upper_boundary = root_of_optimization_tree.find( + "./ProgramSettings/designParameter/designVariable[" + "@ID='" + str(i) + "'" + + "]upperBoundary").text + if upper_boundary == 'inf': + upper_boundary = np.inf + elif upper_boundary == '-inf': + upper_boundary = -np.inf + else: + upper_boundary = float(upper_boundary) + + # read unit of upper boundary of design variables and check for "feet" or "ft" + upper_boundary_unit = root_of_optimization_tree.find( + "./ProgramSettings/designParameter/designVariable[" + "@ID='" + str(i) + "'" + + "]upperBoundary").get('Unit') + if upper_boundary_unit == 'feet' or upper_boundary_unit == 'ft': + upper_boundary *= feet + + # add design variables to x_bound array + design_variable_boundaries = [lower_boundary, upper_boundary] + x_bounds_unicado.append(design_variable_boundaries) + + # read upper and lower boundaries of design variables + g_bounds_unicado = [] + number_of_design_requirements = int(root_of_optimization_tree.find( + './ProgramSettings/designRequirementParameter/designRequirements').text) + + for i in range (0, number_of_design_requirements): + # read lower boundary of design variables and check for infinity + lower_boundary = root_of_optimization_tree.find( + "./ProgramSettings/designRequirementParameter/designRequirement[" + "@ID='" + str(i) + "'" + + "]lowerBoundary").text + if lower_boundary == 'inf': + lower_boundary = np.inf + elif lower_boundary == '-inf': + lower_boundary = -np.inf + else: + lower_boundary = float(lower_boundary) + + # read unit of lower boundary of design variables and check for "feet" or "ft" + lower_boundary_unit = root_of_optimization_tree.find( + "./ProgramSettings/designRequirementParameter/designRequirement[" + "@ID='" + str(i) + "'" + + "]lowerBoundary").get('Unit') + if lower_boundary_unit == 'feet' or lower_boundary == 'ft': + lower_boundary *= feet + + # read upper boundary of design variables and check for infinity + upper_boundary = root_of_optimization_tree.find( + "./ProgramSettings/designRequirementParameter/designRequirement[" + "@ID='" + str(i) + "'" + + "]upperBoundary").text + if upper_boundary == 'inf': + upper_boundary = np.inf + elif upper_boundary == '-inf': + upper_boundary = -np.inf + else: + upper_boundary = float(upper_boundary) + + # read unit of upper boundary of design variables and check for "feet" or "ft" + upper_boundary_unit = root_of_optimization_tree.find( + "./ProgramSettings/designRequirementParameter/designRequirement[" + "@ID='" + str(i) + "'" + + "]upperBoundary").get('Unit') + if upper_boundary_unit == 'feet' or upper_boundary_unit == 'ft': + upper_boundary *= feet + + # add design variables to x_bound array + design_requirement_boundaries = [lower_boundary, upper_boundary] + g_bounds_unicado.append(design_requirement_boundaries) + + except OSError: + print('ERROR: The optimization configuration file of current workflow execution could not be opened or is ' + 'corrupt!\n' + ' Optimization could not be performed! The optimization framework is aborted!') + sys.exit(1) + + return x_bounds_unicado, g_bounds_unicado + +""" +Example: 1D function +""" +def functions1D(x): + """ + Define blackbox functions for your problem setting. + + :param x: design variables + :type x: np.ndarray (1D) + + + f: cost function (a scalar) + g: constraint functions (a vector) + return: (f, g), status + (f, g): np.ndarray (1D) + status: boolean (if the output is successfully obtained) + """ +# f = np.power( (6.*(1.-x)-2.), 2 ) * np.sin(12.*(1.-x)-4.) + f = np.power( (6.*x-2.), 2 ) * np.sin(12.*x-4.) +# g1 = 10.*x - 10. + """ + generalized: + + g2 = ... + g3 = ... + ... + gM = ... + + if not all( [f == f, g1 == g1, ..., gM == gM] ): + status = "Failure" + else: + status = "Success" + + return np.hstack((f, g1, ..., gM)), status + """ + +# if not all( [f == f, g1 == g1] ): +# status = "Failure" +# else: +# status = "Success" + +# return np.hstack((f, g1)), status + return f, "Success" + + +""" +Example: 2D function +""" +def functions2D(x): + """ + The same rule as the 1D case + """ + D = 2 + f = sum( 100. * np.power( x[i+1] - np.power( x[i], 2 ), 2 ) + np.power( ( 1. - x[i] ), 2 ) for i in range(D-1) ) # Rosenbrock function + + if f is None: + status = "Failure" + else: + status = 'Success' + + return np.array([f]), status + + +def functionsUNICADO(x): + """ + The same as the examples in the above (1D, 2D functions) + Define blackbox functions for your problem setting. + + :param: x: design variables + :type: x: numpy array + """ + ''' initialize local parameter ''' + return_code = 0 + + # absolute path to working directory of current workflow execution + # Attention this path will set dynamically during workflow execution!!! Do not enter anything here!!! + path_to_current_working_dir = 'path' + path_to_output_dir = 'output_path' + + ''' write current x values to csv output file ''' + array_str = np.array2string(x, separator=' ', precision=16) + array_str = array_str[1:-1] + "\n" + # Write to a text file + if os.path.isfile(path_to_output_dir + 'X-values.csv'): + with open(path_to_output_dir + 'X-values.csv', 'a') as file: + file.write(array_str) + file.close() + + ''' loop to wait for the semaphore trigger flag to prepare current optimization loop ''' + while True: + if x is None: + break + + # ToDo: hier abbruchbedinung einbauen??? + + # check if the semaphore flag is deleted by the UNICADOworkflow -> if true: -> perform preparation steps + if not os.path.isfile(path_to_current_working_dir + '/temp/semaphoreFlagOptimizationPreparation.dat'): + with open(path_to_current_working_dir + '/temp/semaphoreFlagOptimizationPreparation.dat', 'w') as file: + file.close() + break + # else condition: -> semaphore flag is existing -> wait 30 seconds and retry the check + else: + # check if the working directory of current workflow execution is not existing + # -> if true: -> raise an error and abort optimization framework + if not os.path.isdir(path_to_current_working_dir): + print('ERROR: The specified path to the working directory of current workflow execution does not exist!' + '\n' + ' Optimization could not be performed! The optimisation framework is aborted!') + sys.exit(1) + + # else condition: working directory is still existing -> wait 30 seconds to retry semaphore check + else: + time.sleep(30) + + # check if the UNICADOworkflow configuration file of current execution is existing + # -> if false: -> raise an error an abort program + if not os.path.isfile(path_to_current_working_dir + '/unicado_workflow_conf.xml'): + if not os.path.isfile(path_to_current_working_dir + '/temp/optimizationRuntimeError.dat'): + with open(path_to_current_working_dir + '/temp/optimizationRuntimeError.dat', 'w') as file: + file.close() + print('ERROR: The UNICADOworkflow configuration file of current workflow execution does not exist!\n' + ' Optimization could not be performed! The optimisation framework is aborted!') + sys.exit(1) + + ''' open and read parameter from unicado_workflow_conf.xml configuration file ''' + try: + xml_tree = xml.etree.ElementTree.ElementTree(file=path_to_current_working_dir + '/unicado_workflow_conf.xml') + root_of_workflow_tree = xml_tree.getroot() + aircraft_exchange_file = root_of_workflow_tree.find('./control_settings/aircraft_exchange_file_name/value').text + aircraft_project = aircraft_exchange_file[:-4] + + except OSError: + print('ERROR: The UNICADOworkflow configuration file of current workflow execution could not be opened!\n' + ' Optimization could not be performed! The optimization framework is aborted!') + sys.exit(1) + + ''' read design variable-, cost function- and design requirement keys from optimization configuration file ''' + try: + xml_tree = xml.etree.ElementTree.ElementTree(file=path_to_current_working_dir + '/optimization_conf.xml') + root_of_optimization_tree = xml_tree.getroot() + + # read design variables from optimization configuration file + # X + design_variable_keys = [] + design_variable_xml_paths = [] + design_variable_system_paths = [] + number_of_design_variables = int(root_of_optimization_tree.find( + './ProgramSettings/designParameter/designVariables').text) + + # loop across the number of design variables to read parameter xml paths + for i in range(0, number_of_design_variables): + design_variable_keys.append(root_of_optimization_tree.find( + "./ProgramSettings/designParameter/designVariable[" + "@ID='" + str(i) + "'" + + "]ParameterName").text) + design_variable_xml_paths.append(root_of_optimization_tree.find( + "./ProgramSettings/designParameter/designVariable[" + "@ID='" + str(i) + "'" + + "]PathInXmlFile").text) + design_variable_system_paths.append(root_of_optimization_tree.find( + "./ProgramSettings/designParameter/designVariable[" + "@ID='" + str(i) + "'" + + "]PathToFile").text) + + # read cost function keys from optimization configuration file + # F(x) + cost_functions_keys = [] + cost_functions_xml_paths = [] + cost_functions_system_paths = [] + number_of_cost_function_parameter = int(root_of_optimization_tree.find( + './ProgramSettings/costFunctions/costFunctionsParameters').text) + + # loop across the number of cost function parameter to read parameter xml paths + for i in range(0, number_of_cost_function_parameter): + cost_functions_keys.append(root_of_optimization_tree.find( + "./ProgramSettings/costFunctions/costFunctionsParameter[" + "@ID='" + str(i) + "'" + + "]ParameterName").text) + cost_functions_xml_paths.append(root_of_optimization_tree.find( + "./ProgramSettings/costFunctions/costFunctionsParameter[" + "@ID='" + str(i) + "'" + + "]PathInXmlFile").text) + cost_functions_system_paths.append(root_of_optimization_tree.find( + "./ProgramSettings/costFunctions/costFunctionsParameter[" + "@ID='" + str(i) + "'" + + "]PathToFile").text) + + # read design requirement keys from optimization configuration file + # G(x), H(x) --> constraints + design_requirement_keys = [] + design_requirement_xml_paths = [] + design_requirement_system_paths = [] + number_of_design_requirements = int(root_of_optimization_tree.find( + './ProgramSettings/designRequirementParameter/designRequirements').text) + + # loop across the number of design requirements to read parameter xml paths + for i in range(0, number_of_design_requirements): + design_requirement_keys.append(root_of_optimization_tree.find( + "./ProgramSettings/designRequirementParameter/designRequirement[" + "@ID='" + str(i) + "'" + + "]ParameterName").text) + design_requirement_xml_paths.append(root_of_optimization_tree.find( + "./ProgramSettings/designRequirementParameter/designRequirement[" + "@ID='" + str(i) + "'" + + "]PathInXmlFile").text) + design_requirement_system_paths.append(root_of_optimization_tree.find( + "./ProgramSettings/designRequirementParameter/designRequirement[" + "@ID='" + str(i) + "'" + + "]PathToFile").text) + + except OSError: + print('ERROR: The optimization configuration file of current workflow execution could not be opened or is ' + 'corrupt!\n' + ' Optimization could not be performed! The optimization framework is aborted!') + sys.exit(1) + + ''' set paths to file directory and aircraft exchange files ''' + cost_functions = {} + design_requirement = {} + # check if the current given input x is not None -> if true: -> perform workflow preparation and execution + if x is not None: + file_directory = path_to_current_working_dir + '/' + aircraft_project + '/' + aircraft_exchange_default_file = file_directory + aircraft_project + '_Default.xml' + aircraft_exchange_file = file_directory + aircraft_project + '.xml' + + ''' read aircraft exchange default file as element tree to write candidate values to the file ''' + tree = xml.etree.ElementTree.ElementTree(file=aircraft_exchange_default_file) + root = tree.getroot() + + # loop across all given design varaibles to set candidate values to the aircraft exchange file + for i in range(0, number_of_design_variables): + root.find(design_variable_xml_paths[i]).text = str(x[i]) + + tree.write(aircraft_exchange_file, encoding='utf-8') + + time.sleep(3) + + if os.path.isfile(path_to_current_working_dir + '/temp/semaphoreFlagWorkflowExecution.dat'): + os.remove(path_to_current_working_dir + '/temp/semaphoreFlagWorkflowExecution.dat') + + ''' loop to wait for the semaphore trigger flag to perform optimization ''' + print('Attention: Optimization framework is waiting for the finishing of the current workflow loop!') + print('Execution of UNIACDOworkflow is running for: \n') + for i, key in enumerate(design_variable_keys): + print(' ' + key + ' = ' + str(x[i]) + '\n') + + while True: + # check if the semaphore flag is deleted by the UNICADOworkflow -> if true: -> perform optimization steps + if not os.path.isfile(path_to_current_working_dir + '/temp/semaphoreFlagOptimization.dat'): + with open(path_to_current_working_dir + '/temp/semaphoreFlagOptimization.dat', 'w') as file: + file.close() + break + # else condition: -> semaphore flag is existing -> wait 10 seconds and retry the check + else: + # check if the working directory of current workflow execution is not existing + # -> if true: -> raise an error and abort optimization framework + if not os.path.isdir(path_to_current_working_dir): + print('ERROR: Temporary working directory of current workflow execution does not exist!\n' + ' Optimization framework is shut down, due to a runtime error!') + sys.exit(1) + + # else condition: working directory is still existing -> wait 10 seconds to retry semaphore check + else: + time.sleep(10) + + # check if the current workflow loop is failed -> if true: -> return error code 1 + if os.path.isfile(path_to_current_working_dir + '/temp/workflowExecutionError.dat'): + os.remove(path_to_current_working_dir + '/temp/workflowExecutionError.dat') + return_code = 1 + + if os.path.isfile(path_to_current_working_dir + '/temp/convergenceError.dat'): + os.remove(path_to_current_working_dir + '/temp/convergenceError.dat') + return_code = 2 + + # Else condition: The given input x is None -> Set rerun code to 3 and skipp workflow execution for current input + else: + return_code = 3 + + # check if the workflow execution is not successfully -> if true: -> set status flag to 'Failure' + if return_code != 0: + status = 'Failure' + print('Current loop of UNICADOworkflow failed! \n' + 'Results will not be used for optimization!') + + print('Execution of UNIACDOworkflow failed for: \n') + for key in design_variable_keys: + print(' ' + key + ' = "None" ' + '\n') + + print(cost_functions_keys) + for key in cost_functions_keys: + cost_functions[key] = None + for key in design_requirement_keys: + design_requirement[key] = None + + # Else condition: The workflow execution is successfully -> set status flag to 'Success' + else: + status = 'Success' + print('Execution of UNIACDOworkflow successful for: \n') + for i, key in enumerate(design_variable_keys): + print(' ' + key + ' = ' + str(x[i]) + '\n') + + # --- output (cost functions )--- + for i in range(0, number_of_cost_function_parameter): + tree = xml.etree.ElementTree.ElementTree(file=cost_functions_system_paths[i]) + root_of_cost_functions_file = tree.getroot() + cost_functions[cost_functions_keys[i]] = float(root_of_cost_functions_file.find( + cost_functions_xml_paths[i]).text) + + # --- output (constraints) --- + for i in range(0, number_of_design_requirements): + tree = xml.etree.ElementTree.ElementTree(file=design_requirement_system_paths[i]) + root_of_design_requirement_file = tree.getroot() + design_requirement[design_requirement_keys[i]] = float(root_of_design_requirement_file.find( + design_requirement_xml_paths[i]).text) + + print('Attention: Optimization framework is running to perform optimization steps!\n' + ' The current workflow execution is waiting for the finishing of optimization steps of current run!') + + ''' your definition of a scalar cost function ''' + # define one scalar value output function, f: scaler + # (e.g. linear combination of several output values such mission energy, ...) + for value in cost_functions.values(): + print('cost_functions_value is: ' + str(value)) + + f = sum(value if value is not None else np.inf for value in cost_functions.values()) + print('f is: ' + str(f)) + # Write to a text file + if os.path.isfile(path_to_output_dir + 'Y-values.csv'): + with open(path_to_output_dir + 'Y-values.csv', "a", newline='') as csvfile: + csv_writer = csv.writer(csvfile) + # Write a single row containing the float value + csv_writer.writerow([f]) + + g = [value if value is not None else np.inf for value in design_requirement.values()] + print('g is: ' + str(g)) + # Write to a text file + if os.path.isfile(path_to_output_dir + 'G-values.csv'): + with open(path_to_output_dir + 'G-values.csv', "a", newline='') as csvfile: + # Convert the list to a string where values are separated by spaces + line = ' '.join(map(str, g)) # Convert each element to a string and join with a space + csvfile.write(line + "\n") + + return np.array([f]+g), status + + +""" +User-Input 2: + +Define "formulation" of your optimization problem + - Write down f and g in the module main.function (in the beginning of this file) + - Define the bounds of x (input) and g (constraints) +""" + + +# --- example of User-Input 1 --- +""" +Example: 1D function +""" +xbounds1D = [[0., 1.]] # for 1D test function +gbounds1D = [[-np.inf, -15.]]#[] # unconstrained otimization can be defined by gbounds = [] # TLARs itself in UNICADO + + +""" +Example: 2D function +""" +xbounds2D = [[-2., 2.], [-1., 3.]] # for 2D Rosenbrock function +gbounds2D = [] + + +""" +Example: 1D function constraints +""" +xbounds1Dconstraints = [[0., 1.]] +gbounds1Dconstraints = [[-1., 1.], [0., 0.75]] + + +""" +Example: 2D function constraints +""" +#xbounds2D = [ [-5., 10.], [0., 15.] ] # for the Braine Test Function +xbounds2Dconstraints = [[0., 1.], [0., 1.]] # for the Braine Test Function +gbounds2Dconstraints = [[0.2, np.inf]] diff --git a/UNICADOworkflow/src/optimization/doe.py b/UNICADOworkflow/src/optimization/doe.py new file mode 100644 index 0000000000000000000000000000000000000000..ac3af3b27de885b5b213cefdc9170029965c4532 --- /dev/null +++ b/UNICADOworkflow/src/optimization/doe.py @@ -0,0 +1,135 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +""" +A stand-alone module to do execute DoE (Design of Experiments) +The orginal functionalities of the algorithms of generating sample points are assisted by direct use of scipy.stats. + +Author: Daigo Maruyama +Technical contact: d.maruyama@tu-braunschweig.de +""" + +### standard libraries (includig numpy, scipy) ### +import numpy as np +from scipy.stats import qmc # latest version + + +class _DoE: + def __init__(self, N, bounds): + self._N = N + self._D = len(bounds) + self._bounds = np.asarray(bounds) + + def __getitem__(self, i): + return self._transform()[i] + + def _gneration(self): + self._X = self._sampler.random(self._N) + + def _transform(self): + return qmc.scale(self._X, self._bounds[:,0], self._bounds[:,1]) + +class LHS(_DoE): + """ + Generate Latin Hypercube sampling. + + :param N: sample size + :type N: integer + :param bounds: bounds of the inputx + :type bounds: list + """ + def __init__(self, N, bounds): + _DoE.__init__(self, N, bounds) + self._sampler = qmc.LatinHypercube(self._D) + self._gneration() + +class _QMC(_DoE): + def nextSampling(self, N): + """ + Additional sample data is generated as a sequence after the current sample data. Same as the method "sampling", the output is kept to be _QMC class. + This property is peculiar to the quasi Monte Carlo method basically in order to maintain the "low-discrepancy (uniformity)" in the whole set of sample data. + Note: The property of reproducibility is also important in the quasi monte Carlo. + + :param N: sample size + :type N: integer + """ + self._N = N # update + self._gneration() # next sampling with the method .random + return self + +class QMC(_QMC): + @classmethod + def Halton(cls, N, bounds, scramble=False): + """ + Generate Halton sequence as one of the quasi Monte Carlo methods. + + :param N: sample size + :type N: integer + :param bounds: bounds of the inputx + :type bounds: list + :param scramble: (see scipy docs) If True, use Owen scrambling. Otherwise no scrambling is done. Default is True. + :type scramble: boolean + """ + sample = cls(N, bounds) + sample._sampler = qmc.Halton(sample._D, scramble=scramble) + sample._gneration() + return sample + + @classmethod + def Sobol(cls, N, bounds, scramble=False): + """ + Generate Sobol sequence as one of the quasi Monte Carlo methods. + + :param N: sample size + :type N: integer + :param bounds: bounds of the inputx + :type bounds: list + :param scramble: (see scipy docs) If True, use Owen scrambling. Otherwise no scrambling is done. Default is True. + :type scramble: boolean + """ + sample = cls(N, bounds) + sample._sampler = qmc.Sobol(sample._D, scramble=scramble) + sample._gneration() + return sample + + +if __name__ == "__main__": + """ + An example of generaiton of sample + """ + N = 5 # sample size + bounds = [ [0, 3], [-1, 5] ] # bounds (a hypercube) + + + ### --- LHS + X = LHS(N, bounds) + print("\nX by LHS=\n", X[:]) + + + ### --- Sobol (as QMC) + X = QMC.Sobol(N, bounds) + Xorg = X[:] # store the 1st sample dataset as ndarray + + # the 1st set + print("\nX by Sobol (1st set)=\n", X[:]) + + # the 2nd set + Xnew = X.nextSampling(N)[:] # store the 2nd sample dataset as ndarray + print("\nX by Sobol (2nd set) =\n", Xnew[:]) diff --git a/UNICADOworkflow/src/optimization/gaussianProcess.py b/UNICADOworkflow/src/optimization/gaussianProcess.py new file mode 100644 index 0000000000000000000000000000000000000000..1ba91da0cc597dd687f31373682f85426b259024 --- /dev/null +++ b/UNICADOworkflow/src/optimization/gaussianProcess.py @@ -0,0 +1,535 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +""" +A stand-alone module to create a surrogate model (currently only Gaussian Processes) + +Author: Daigo Maruyama +Technical contact: d.maruyama@tu-braunschweig.de +""" + +### standard libraries (includig numpy, scipy) ### +import numpy as np +import scipy +import scipy.optimize +from scipy.stats import norm +from scipy.special import erf +import sys + +### the modules in this package ### +#import updated_optimisation_code.kernel as kernel # a kind of submodule of this module +import _kernel # a kind of submodule of this module + + +class _GPGeneral: + """ + A generalized Gaussiap Process, which covers arbitrary kernel functions. + """ + def __init__(self, X, theta, regularization, kernelmodel, basisFunction): + self._Xorg = X # basically not used in the algorithm (no need to stock this) + self._N = X.shape[0] # N: sample size, D: dimension (D is not used) + self.theta = theta + self.regularization = regularization + self._kernelmodel = kernelmodel + self._basisFunction = basisFunction +# self._M = len(basisFunction) # = len(w) + + # --- standersized --- + scales = [(np.min(d), np.max(d)) for d in X.T] + self._scales = np.array([[xmin, xmax-xmin] for xmin, xmax in scales], dtype=float) + # -------------------- + self._X = self._standerdized(X) # standerdized (X is scaled between 0 and 1) + + if not any(self._kernelmodel.values()): + raise ValueError("At least one element of kernelmodel has to be True.") + +# if not (trend == "simple" or trend == "ordinary" or callable(trend)): +# raise ValueError("Please set 'simple' or 'ordinary' or callable function with respect to the input x, for trend.") + + # - Example + # self._???KernelInfo = _???kernel.Kernel(X, self.theta_???) + # ... + + """ + stocked values here: + + self._X + self._N + self.theta + self.regularization + self._kernelmodel + self._basisFunction + """ + + def _standerdized(self, Xorg): + X = Xorg.copy() + X -= self._scales[:, 0] + X /= self._scales[:, 1] + return X + + def _computeAnalytical(self, Y): + self._Ymin = np.min(Y) # used only for EI + + # --- only using X + K = self._gramMatrix() # Gram matrix + self._luK = scipy.linalg.lu_factor(K) # DIscussion: more precise and faster (the most important part) +# if any(self._luK[0][i,i] < 0. for i in range(self._N)): +# print("K is not positive semi-definite.") + + # --- using Y + # preprocessing of Y (for the trend) issue + if self._basisFunction == (0.,): # simple + self.w = None + self._Ytrend = lambda x: 0. + else: + Phi = np.array( [ [ v(x)[0] if callable(v) else v for v in self._basisFunction ] for x in self._Xorg ] ) # generalized (The element of basisFunction has to be callable (scalar output) or scalr value) + try: # GLS in general + luA = scipy.linalg.lu_factor(np.dot( Phi.T, scipy.linalg.lu_solve(self._luK, Phi))) # usually max size 2 for the invese matrix A, which is computationally very cheap + self.w = scipy.linalg.lu_solve(luA, np.dot( Phi.T, scipy.linalg.lu_solve(self._luK, Y))).reshape(-1) +# self.w = scipy.linalg.lu_solve(scipy.linalg.lu_factor(np.dot( Phi.T, scipy.linalg.lu_solve(self._luK, Phi))), np.dot( Phi.T, scipy.linalg.lu_solve(self._luK, Y))).reshape(-1) # GLS closed-form operation in one line + except: + print("GLS in the linear regression trend computation failed.") + self.w = None + self._YKY = None + return + self._Ytrend = lambda x: sum( [ np.dot( self.w[i], self._basisFunction[i](x) if callable(self._basisFunction[i]) else self._basisFunction[i] ) for i in range(len(self.w)) ] ) # linear regression function (trend) after learning w by the GLS in the above + + Ycentered = Y - self._Ytrend(self._X) # Ytrend using the data point set X + self._weights = scipy.linalg.lu_solve(self._luK, Ycentered) # This value corresponds to the weighted parameter in the Kriging perspective. + self._YKY = np.dot(Ycentered.T, self._weights) # for likelihood + """ + stocked values here: + + self.w # a set of all the hyparameters except for theta, which has a closed-form expression wrt theta + self._luK + self._Ytrend + self._weights + self._YKY + """ + + def _positiveSemiDefinite(self): + if any(self._luK[0][i,i] < 0. for i in range(self._N)): +# print("K is not positive semi-definite.") + return False + else: + return True + + # --- for Learning + def _gramMatrix(self): + NotImplementedError("Currently no need to use other kernel types.") + # - Example -: + # K = np.zeros((self._N, self._N), dtype=np.float64) + # if self._kernelmodel["???"]: + # K = self._???KernelInfo.covariance(K) + # ... + # return K + + def _errorFunction(self): # negative log of likelihood (=error function) + if not self._positiveSemiDefinite(): + return 1e4 + else: + lnK = np.sum( np.log( np.diag( self._luK[0] ) ) ) + E = self._YKY + lnK + return E + # --- + + # --- for Prediction + def prediction(self, xpre): # mean of the predictive distribution + """ + Predict the output on a new input xpre. + (More precisely to say, output the mean of the predictive distirbution when the input is xpre.) + + :param xpre: arbitrary single point of the input + :type xpre: np.ndarray (1D) + """ + xpre = self._standerdized(xpre) + ypre = self._Ytrend(xpre) + np.dot( self._corrVector(xpre).T, self._weights ) + return ypre[0,0] +# return np.squeeze(ypre) + + def uncertainty(self, xpre): # variance (not std) of the predictive distribution + """ + Predict the uncertainty on a new input xpre. + (More precisely to say, output the variance of the predictive distirbution when the input is xpre.) + + :param xpre: arbitrary single point of the input + :type xpre: np.ndarray (1D) + """ + xpre = self._standerdized(xpre) + k = self._corrVector(xpre) + yvar = self._corrScalar(xpre) - np.dot( k.T, scipy.linalg.lu_solve( self._luK, k ) ) + return np.squeeze(yvar) + + def _corrVector(self, xpre): # used for both prediction and uncertainty + NotImplementedError("Currently no need to use other kernel types.") + # - Example -: + # k = np.zeros((self._N, 1), dtype=np.float64) + # if self._kernelmodel["???"]: + # k = self._???KernelInfo.vectorPrediction(xpre, k) + # ... + # return k + + def _corrScalar(self, xpre): # used only for uncertainty + NotImplementedError("Currently no need to use other kernel types.") + # - Example -: + # k = 0. + # if self._kernelmodel["???"]: + # k = self._???KernelInfo.scalarPrediction(xpre, k) + # ... + # return k + + def acquisitionFunction(self, x, functionName): # re-arranged later + """ + Compute the axquisition function that you specified for your puropose at an arbitrary single input point. + + :param x: arbitrary single point of the input + :type x: np.ndarray (1D) + :param functionName: specify the acquisition function from "EI", "PI", ... + :type functionName: string + """ + yvar = np.fmax(sys.float_info.epsilon, self.uncertainty(x)) # variance + if functionName == "EI": + ypre = self._Ymin - self.prediction(x) # min - mean + ystd = np.sqrt(yvar) # std + f = ypre * (0.5 + 0.5 * erf(ypre / (ystd * np.sqrt(2.)))) + ystd / np.sqrt(2. * np.pi) * np.exp(-np.power(ypre, 2) / (2. * yvar)) + elif functionName == "PI": + raise NotImplementedError("PI is actually on the way to compute EI, but anyway later") + elif method == "variance": + f = yvar + return np.squeeze(f) + # --- + +class _GP(_GPGeneral): + """ + A conventional Gaussiap Process, which covers conventional kernel functions. + conventional kernel functions: kernelfunction(x, x', theta) = theta0*Gaussian(x, x', theta1) + theta2*Constant() + theta3*Linear(x, x') + """ + def __init__(self, X, theta, regularization, kernelmodel, basisFunction): + _GPGeneral.__init__(self, X, theta, regularization, kernelmodel, basisFunction) + + ### want to modify to make it more generic ### + if self._kernelmodel["Gaussian"]: + D = self._X.shape[1] + else: + D = 0 + if self._kernelmodel["Constant"]: + M = 1 + else: + M = 0 + if self._kernelmodel["Linear"]: + N = 1 + else: + N = 0 + if self.regularization is True: + L = 1 + else: + L = 0 + self.theta_Gaussian = theta[0 :D ] # used for ARD + self._theta_Constant = theta[D :D+M ] + self._theta_Linear = theta[D+M :D+M+N ] + self._theta_Regularization = theta[D+M+N:D+M+N+L] + ############################################## + self._GaussianKernelInfo = _kernel.GaussianKernel(self._X, self.theta_Gaussian) + self._ConstantKernelInfo = _kernel.ConstantKernel(self._X, self._theta_Constant) + self._LinearKernelInfo = _kernel.LinearKernel(self._X, self._theta_Linear) + if self.regularization is True: + self._RegularizationKernelInfo = _kernel.RegularizationKernel(self._X, self._theta_Regularization) + else: + self._RegularizationKernelInfo = _kernel.RegularizationKernel(self._X, self.regularization) + + """ + stocked values here: + + self._X + self._N + self.theta + self.regularization + self._kernelmodel + self._basisFunction + self.theta_Gaussian + self._theta_Constant + self._theta_Linear + self._theta_Regularization + """ + + def _computeAnalytical(self, Y): + _GPGeneral._computeAnalytical(self, Y) + if self._YKY is None: + self._variance = None + else: + self._variance = self._YKY / float(self._N) + """ + stocked values here: + + self._luK + self._Ytrend + self._weights + self._YKY + self._variance + """ + + # --- for Learning + def _gramMatrix(self): + K = np.zeros((self._N, self._N), dtype=np.float64) + if self._kernelmodel["Gaussian"]: + K = self._GaussianKernelInfo.covariance(K) + if self._kernelmodel["Constant"]: + K = self._ConstantKernelInfo.covariance(K) + if self._kernelmodel["Linear"]: + K = self._LinearKernelInfo.covariance(K) + if self.regularization: + K = self._RegularizationKernelInfo.covariance(K) + return K + + def _errorFunction(self): # negative log of likelihood (=error function) + if self._variance is None: + return 1e4 + else: + self._variance = max(self._variance, sys.float_info.epsilon) + lnK = np.sum( np.log( np.diag( self._luK[0] ) ) ) + E = self._N*np.log(self._variance) + lnK + if E != E: # NaN + return 1e4 + else: + return np.squeeze(E) + # --- + + # --- for prediction + def uncertainty(self, xpre): # variance (not std) of the predictive distribution + """ + Predict the uncertainty on a new input xpre. + (More precisely to say, output the variance of the predictive distirbution when the input is xpre.) + + :param xpre: arbitrary single point of the input + :type xpre: np.ndarray (1D) + """ + return self._variance * _GPGeneral.uncertainty(self, xpre) + + def _corrVector(self, xpre): # used for both prediction and uncertainty + k = np.zeros((self._N, 1), dtype=np.float64) + if self._kernelmodel["Gaussian"]: + k = self._GaussianKernelInfo.vectorPrediction(xpre, k) + if self._kernelmodel["Constant"]: + k = self._ConstantKernelInfo.vectorPrediction(xpre, k) + if self._kernelmodel["Linear"]: + k = self._LinearKernelInfo.vectorPrediction(xpre, k) +# if self.regularization: # theoretically meaningless +# k = self._RegularizationKernelInfo.vectorPrediction(xpre, k) + return k + + def _corrScalar(self, xpre): # used only for uncertainty + k = 0. + if self._kernelmodel["Gaussian"]: + k = self._GaussianKernelInfo.scalarPrediction(xpre, k) + if self._kernelmodel["Constant"]: + k = self._ConstantKernelInfo.scalarPrediction(xpre, k) + if self._kernelmodel["Linear"]: + k = self._LinearKernelInfo.scalarPrediction(xpre, k) + if self.regularization: + k = self._RegularizationKernelInfo.scalarPrediction(xpre, k) + return k + # --- + + # --- postprocess + def automatic_relevance_determination(self): + if not self._kernelmodel == {"Gaussian": True, "Constant": False, "Linear": False}: +# raise ValueError("To be fair for the global sensitivity analysis, the kernel should be only Gaussian.") + print("To be fair for the global sensitivity analysis, the kernel should be only Gaussian.") + return None + else: + return self.theta_Gaussian + # --- + +class GP(_GP): + """ + A class on how to define the hyperparameters (theta) + """ + def __init__(self, X, Y, theta, regularization, kernelmodel, basisFunction): + """ + Create a Gaussian Process regression model with specifying the values of the hyperparameter theta (usually not used by users). + """ + _GP.__init__(self, X, theta, regularization, kernelmodel, basisFunction) + self._computeAnalytical(Y) + + @classmethod + def MLE(cls, X, Y, regularization=np.log10(sys.float_info.epsilon), kernelmodel={"Gaussian": True, "Constant": False, "Linear": False}, basisFunction=(0.,), multiStart=1, maxiter=1000, tol=1e-3, disp=True): + """ + Create a Gaussian Process regression model. The hyperparameters to fix/control the model is determined by the maximum liklhood estimation (MLE). + + :param X: A set of input values + :type X: np.ndarray(2D) + :param Y: A set of output (function) values, copposponding to the input values. The dimensionality of each samplint has to be 1 (a scaler value). + :type Y: np.ndarray(2D) + + :param regularization: A noise is considered or not. If it is, the model is not guaranteed to pass throgh all the data points. (More strictly to say, assume the existance of aleatory uncertainty or not. The noise is the variance with homoscedasticity in a monovariate Gaussian distribution) + :type regularization: True or scalr (log10 scale) + :param kernelmodel: switchin on/off each kernel function "Gaussian", "Constant", "Linear" + :type kernelmodel: dictionary + :param trend: Specify on which model the basic Gaussian Process regression model (whoise mean is 0) is defined. + :type trend: String + + :param multiStart: Number of trials of the oprimization algorithm with randomness + :type multiStart: integer + :param maxiter: Number of iteration of the optimization + :type maxiter: integer + :param tol: Tolerance for the optimizaiton + :type tol: float + :param disp: If the iteration of the optimization is displayed or not + :type disp: boolean + """ + args = (X, Y, regularization, kernelmodel, basisFunction) + + bounds = [] + if kernelmodel["Gaussian"]: + boundsTheta_Gaussian = [ [-4, 3 ] ]*X.shape[1] # serch in log scale with base 10 +# boundsTheta_Gaussian = [ [-3, 2 ] ]*X.shape[1] + bounds += boundsTheta_Gaussian + if kernelmodel["Constant"]: + boundsTheta_Linear = [ [0, 10 ] ] # the original scale + bounds += boundsTheta_Linear + if kernelmodel["Linear"]: + boundsTheta_Linear = [ [0, 10 ] ] # the original scale + bounds += boundsTheta_Linear + if regularization is True: + boundsReg = [ [-10, 0] ] # serch in log scale with base 10 + bounds += boundsReg + + fopt = 1e3 # large value + xopt = None + for i in range(multiStart): + opt = scipy.optimize.differential_evolution(cls._MLEobjective, bounds=bounds, args=args, maxiter=maxiter, tol=tol, disp=disp) + if opt.fun < fopt: # update only when it is better + fopt = opt.fun + xopt = opt.x + +# xopt = np.array([2.]) + return cls(X, Y, xopt, regularization, kernelmodel, basisFunction) + + @classmethod + def _MLEobjective(cls, theta, X, Y, regularization, kernelmodel, basisFunction): + return cls(X, Y, theta, regularization, kernelmodel, basisFunction)._errorFunction() + + + +if __name__ == "__main__": + + """ + An example of construction of a surrogate model and predictions using a test case of UNICADO + (the dataset is red by "DoE" for X, "mission_energy_data" for Y) + """ + + import doe + from matplotlib import pyplot as plt + from mpl_toolkits.mplot3d import Axes3D # for 3D figures + + def plotting1D(name, function, xbounds, Npre=100, sigma_ratio=1.): + Xpre = np.linspace(xbounds[0][0], xbounds[0][1], Npre, dtype=np.float64) + Xpre = Xpre.reshape(len(Xpre),-1) + Ypre = np.empty(Npre) + Yvar = np.empty(Npre) + for j in range(Npre): + Ypre[j] = surrogate.prediction(Xpre[j]) + Yvar[j] = surrogate.uncertainty(Xpre[j]) + YpreU = Ypre + sigma_ratio*np.sqrt(Yvar) + YpreL = Ypre - sigma_ratio*np.sqrt(Yvar) + + Yref = function(Xpre) + fig = plt.figure() + plt.plot(Xpre, Yref, linestyle="dashed") + plt.plot(Xdata, Ydata, "o", color="b") + plt.plot(Xpre, Ypre, color="g") + plt.fill_between(Xpre.reshape(len(Xpre)), YpreU, YpreL, facecolor='y',alpha=0.5) +# plt.ylim(-12.5, 17.5) + plt.savefig("1D.jpg") + plt.close() + + def plotting2D(name, Npre=100, sigma_ratio=1): + x1 = np.linspace(xbounds[0][0], xbounds[0][1], Npre, dtype=np.float64) + x2 = np.linspace(xbounds[1][0], xbounds[1][1], Npre, dtype=np.float64) + X1, X2 = np.meshgrid(x1, x2) + Y = np.empty( (Npre, Npre), dtype=np.float64 ) + for i in range(Npre): + for j in range(Npre): + xpre = np.array( ( x1[i], x2[j] ), dtype=np.float64) + Y[j,i] = surrogate.prediction(xpre) + + fig = plt.figure() + ax1 = Axes3D(fig) + ax1.plot_surface(X1, X2, Y, cmap = "summer", alpha = 0.5) + ax1.scatter(Xdata[ :,0], Xdata[ :,1], Ydata , c="k") + fig.suptitle("theta, E = {} {}".format(surrogate.theta, surrogate._errorFunction())) + ax1.set_zlim([5950, 6150]) + plt.savefig("2D,jpg") + plt.close() + + + + def highFidelityFunction(x): + y = np.power( (6.*x-2.), 2 ) * np.sin(12.*x-4.) + return np.squeeze(y) + + def lowFidelityFunction(x, A=0.5, B=10., C=-5.): + y = A*highFidelityFunction(x) + B*(x-0.5) + C + return np.squeeze(y) + + + # --- process + function = highFidelityFunction + xbounds = [ [0., 1.] ] + + N = 4 +# X = doe.QMC.Sobol(N, xbounds) +# Xdata = X[:] + + Xdata = np.array( [0, 0.4, 0.6, 1.] ).reshape(-1, 1) + Ydata = function(Xdata).reshape(-1, 1) + print("Xdata =", Xdata) + print("Ydata =", Ydata) +# exit(1) + + # regularization true or log scale value + # to make the computation (of the inverse of the covariance matrix) stable, a small amount of value is intentionally added. If it is still not stable, please increase the value (e.g. regularization = -10.) or "regularization=True" + regularization = True#np.log10(sys.float_info.epsilon)#=-16 # all lthe hyperparameters including regularization are in log scale in the operation in the code. +# regularization = True + + """ example of design of basisFunction ### + basisFunction = (1., NN) + basisFunction = (1., lambda x: x, lambda x: np.power(x,2), lambda x: np.power(x,3)) # polynomial functions for 1D input x + """ + trendset = "manual" + ### useful package for user ### + if trendset == "simple": + basisFunction = (0.,) + elif trendset == "ordinary": + basisFunction = (1.,) + elif trendset == "NN": + basisFunction = (lowFidelityFunction,) + elif trendset == "manual": + basisFunction = (1, lowFidelityFunction) + ############################### + + multiStart = 5 + surrogate = GP.MLE(Xdata, Ydata, regularization, basisFunction=basisFunction, multiStart=multiStart) + + print("surrogate.theta =", surrogate.theta) + print("surrogate.w =", surrogate.w) + print("surrogate.regularization =", surrogate.regularization) + print("surrogate._errorFunction =", surrogate._errorFunction()) + plotting1D("{}".format(str(function)), function, xbounds, sigma_ratio=1.) diff --git a/UNICADOworkflow/src/optimization/optimization.py b/UNICADOworkflow/src/optimization/optimization.py new file mode 100644 index 0000000000000000000000000000000000000000..9383e532d2180d68cd83daa6100301426c55ae14 --- /dev/null +++ b/UNICADOworkflow/src/optimization/optimization.py @@ -0,0 +1,411 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +""" +This module is a kind of API, which is directly called from main.py + +Surrogate-based optimization (Bayesian optimization) itself is an application of fundamental methods distributed in other modules. +Therefore, this module is a bit more hard-codded than the stand-alone modules. + +Author: Daigo Maruyama +Technical contact: d.maruyama@tu-braunschweig.de +""" + +### standard libraries (includig numpy, scipy) ### +import numpy as np +import scipy.optimize +from scipy.optimize import NonlinearConstraint#, Bounds +import concurrent.futures # for running in parallel +from matplotlib import pyplot as plt # for visualization +from mpl_toolkits.mplot3d import Axes3D # for 3D visualization +import functools # used only for ordinary optimization +import sys + +### the modules in this package ### +import gaussianProcess, doe # stand-alone modules in the package + + +class Formulation: + def __init__(self, functions, xbounds, gbounds=[]): + """ + Fix required information "in the generalized formulation": + - the functions f(x), g(x) : functions + - the search domain of the input x : xbounds + - the ranges of the constraint output ranges g(x) : gbounds + + :param functions: simulation function which outputs the function evaluation (f and multiple g) + :type functions: callable + :param xbounds: bounds of search in design variables in global optimization + :type xbounds: list + :param gbounds: bounds to define constraints on the constraints functions + :type gbounds: list + """ + self._functions = functions + self._xbounds = xbounds + self._gbounds = gbounds +# self._D = len(xbounds) # number of design variables, not used (maybe used when doe.py code is changed.) + self._M = len(gbounds) # number of constraints + + def runSingle(self, x): + """ + Run the functions defined in the userinput module. + + :param x: design variables + :type x: np.ndarray (1D) + """ + return self._functions(x) + + def runParallel(self, X, proc): + """ + Run the functions defined in the userinput module, with parallelization specified by proc number. + + :param X: The set of design variables + :type X: np.ndarray (2D) + :param proc: Number of Processors used + :type proc: integer greater than 0 + """ + N = X.shape[0] # sample size + Y = [] + Del_x = [] #--- To store the index of Failed Data samples --- + with concurrent.futures.ThreadPoolExecutor(max_workers=proc) as Executor: ### be aware of Thread-Safe ### + for i, (y, status) in zip(range(N), Executor.map(self.runSingle, X)): + if status == 'Success': + Y.append(y) + else: + print('Failed point is omitted') + Del_x.append(i) + return np.array(Y), Del_x + + def _optimization(self, func, constraints, args=(), multiStart=1, maxiter=1000, tol=1e-3, disp=True): # Note: intentionally hard-coded only when the search space is in the domain of the design variables X + fopt = 1e3 + xopt = None + for i in range(multiStart): + opt = scipy.optimize.differential_evolution(func, bounds=self._xbounds, constraints=constraints, args=args, maxiter=maxiter, tol=tol, disp=disp) + if opt.fun < fopt: # update only when it is better + fopt = opt.fun + xopt = opt.x + return xopt, fopt + + def ordinary(self, multiStart=1, maxiter=1000, tol=1e-3, disp=True): + """ + Conduct optimization with direct evaluation of the cost function at each iteration of the optimization process (named ordinary optimization here). + + :param multiStart: Number of trials of the oprimization algorithm with randomness + :type multiStart: integer + :param maxiter: Number of iteration of the optimization + :type maxiter: integer + :param tol: Tolerance for the optimizaiton + :type tol: float + :param disp: If the iteration of the optimization is displayed or not + :type disp: boolean + """ + output = Functions(self._functions) + nlc = [ scipy.optimize.NonlinearConstraint( functools.partial(output.constraintFunction, i=i), self._gbounds[i][0], self._gbounds[i][1] ) for i in range(self._M) ] + return self._optimization(output.costFunction, nlc, args=(), multiStart=multiStart, maxiter=maxiter, tol=tol, disp=disp) + + def EGO(self, N, Nimposed, proc, activeLearningMethod="EI", regularization=np.log10(sys.float_info.epsilon), basisFunction=(0.,), multiStart=5, doeMethod="Sobol", kernelmodel={"Gaussian": True, "Constant": False, "Linear": False}, maxiter=1000, tol=1e-3, disp=True): + """ + Conduct EGO: Efficient Global Optimization (by Bayesian optimization with approximation of the cost function by using surrogate models). + + :param N: Samle size. Or if it is 0, read a (X, Y) data file (this approach will be modified to be more userfriendly) + :type N: integer + :param Nimposed: Additional sample size derived by the aquisition function + :type Nimposed: integer + + :param doeMethod: Method of DoE (Design of Experiments) + :type doeMethod: string + + :param regularization: Whether the regurlarization kernel is considered or not in all the surrogate model construction processes here + :type regularization: boolean + :param kernelmodel: + :type kernelmodel: + :param activeLearningMethod: The type of the acquisition function + :type activeLearningMethod: string + + :param gradientOptSurrogate: method of tuning the hyperparameter of the surrogate models, True: differential evolution, False: BFGS + :type gradientOptSurrogate: boolean + :param multiStart: Number of trials of the oprimization algorithm with randomness + :type multiStart: integer + :param maxiter: Number of iteration of the optimization + :type maxiter: integer + :param tol: Tolerance for the optimizaiton + :type tol: float + :param disp: If the iteration of the optimization is displayed or not + :type disp: boolean + """ + self._regularization = regularization + self._basisFunction = basisFunction + self._doeMethod = doeMethod + self._kernelmodel = kernelmodel + self._multiStart = multiStart + self._trend = 0. + + # temporary for my graph + self._N = N + self._Nimposed = Nimposed + self._activeLearningMethod = activeLearningMethod + # + + # 1. --- DoE --- + self._dataGeneration(N, proc) # self._X, self._Y are created. + + # 2. --- surrogate construction --- + self._surrogateConstruction() # self.surrogate, which is a list (many surrogate models inside), is created. + + # 3. --- surrogate update - update self.surrogate --- (Bayesian Optimization) + self._surrogateUpdate(Nimposed, activeLearningMethod) # self.surrogate is updated. + + # 4. --- optimization on the surrogates --- # find the optimal solution on the surrogate models + args = () + nlc = [ NonlinearConstraint(_ConstraintsSurrogate(self.surrogate[1+i]).predict, self._gbounds[i][0], self._gbounds[i][1]) for i in range(self._M) ] # constraints (TLARs in the UNICADO case) + multiStart = 1 # only 1 trial on the surrogate models + while True: + self.xopt, self.yopt_tilda = self._optimization(self.surrogate[0].prediction, nlc, args, multiStart, maxiter, tol, disp) + yopt = self.runSingle(self.xopt) # overwrite f on f_tilda + if yopt[1] == 'Success': + self.yopt = yopt[0] + break + return self.xopt, self.yopt + + + def _dataGeneration(self, N, DoEmethod="Sobol", proc=1): + if N is False: # will be replaced by more intuitive way. + """ + read data files of X, Y + """ + self._X = np.loadtxt("DoE") + self._Y = np.loadtxt("mission_energy_data").reshape(-1, 1) + self._N = self._Y.shape[0] + + + else: + if N == 4: + self._X = np.array( [0., 0.4, 0.6, 1.] ).reshape(-1, 1) + else: + if self._doeMethod == "Sobol": + X = doe.QMC.Sobol(N, self._xbounds) + elif self._doeMethod == "Halton": + X = doe.QMC.Halton(N, self._xbounds) + elif self._doeMethod == "LHS": + X = doe.LHS(N, self._xbounds) + self._X = X[:] + print("self._X =", self._X) + self._Y, delX = self.runParallel(self._X, proc) # run the simulation in parallel + self._N = self._Y.shape[0] # the sample size is adjusted to the simulation results with success + + if len(delX) > 0: + print("Several simulations failed due to violations of some values of the design variables.") + for i in range(len(delX)): + print("The simulation at the design variable:\n{}\nfailed.".format(self._X)) + self._X = np.array([i for j, i in enumerate(self._X) if j not in delX]) # Writing the DoE sample file again with the valid samples + + if self._N < 2: + print("The actual sample size is too small. Please use a greater number for the original sample size N") + exit(1) + + self._Xorg = self._X.copy() + self._Yorg = self._Y.copy() + + print("self._Y =", self._Y) + print(type(self._Y)) + + def _surrogateConstruction(self): +# if S == 1: +# self.surrogate = [ gaussianProcess.GP.MLE(self._X, self._Y.T[i].reshape(-1,1), self._regularization, self._kernelmodel, self._trend, self._gradientOptSurrogate, self._multiStart) for i in range (1+self._M) ] + self.surrogate = [ gaussianProcess.GP.MLE(self._X, self._Y.T[i].reshape(-1,1), self._regularization, self._kernelmodel) for i in range (1+self._M) ] + + """ + else: + Ydata = [] + for i in range(1+self._M): + Ydata.append([]) + Ydata[i].extend( [ Y[j].T[i] for j in range(self._S) ] ) + self.surrogate = [ gaussianProcess.MFGP(S, self._X , Ydata[i], basisFunction, BayesFunction, b, regularization, kernelmodel, + Xdomain=Xdomain, multiStart=multiStart, + trueFunctions=(lowFidelityFunction, highFidelityFunction), independent=independent, NNGP=NNGP) + for i in range (1+self._M) ] + """ + self.sensitivity = [ self.surrogate[i].automatic_relevance_determination() for i in range (1+self._M) ] # just as by-product: sensitivity analysis (only when only the Gaussian kernel is used) + + + + + def _surrogateUpdate(self, Nimposed, activeLearningMethod, maxiter=1000, tol=1e-3, disp=True): + self._Xadp = [] + self._Yadp = [] + for i in range(Nimposed): + if activeLearningMethod == "EI" or activeLearningMethod == "PI" or activeLearningMethod == "variance": # use the info from only the cost function + args = (self.surrogate[0], activeLearningMethod) + xnew, _ = self._optimization(negAcquisitionFunction, (), args, self._multiStart, maxiter, tol, disp) + elif activeLearningMethod == "EIPI": # use the info of both the cost function and the constraints + args = (self.surrogate, self._gbounds) + xnew, _ = self._optimization(negComposedAcquisitionFunction, (), args, self._multiStart, maxiter, tol, disp) + else: + raise ValueError("Please set 'EI' or 'EIPI' or 'variance' for 'method'.") + ynew, status = self.runSingle(xnew) + if status != "Success": + continue + self._X = np.vstack((self._X, xnew)) # Data X,Y is updated. + self._Y = np.vstack((self._Y, ynew)) + self._Xadp.append(xnew) + self._Yadp.append(ynew) + self._surrogateConstruction() # a new surrogate based on the update data + self._Xadp = np.array(self._Xadp) + self._Yadp = np.array(self._Yadp) + + def visualization(self, Npre): + """ + Visualize the data, the surrogate models and the optimum solution. + + :param Npre: Number of predicted points (per one dimension) + :type Npre: integer greater than 0 + """ + sigma_ratio = 1.#10. # tmp parameter to visualize "sigma_ratio" times sigma (instead of one sigma) + proc = 1 # runnig simulation functions to make a reference (a series of this process will not be used for expensive simulations, e.g. UNICADO cases ) + + D = len(self._xbounds) + if D == 1: + Xpre = np.linspace(self._xbounds[0][0], self._xbounds[0][1], Npre, dtype=np.float64) + Xpre = Xpre.reshape(-1,1) + Ypre = np.empty((1+self._M, Npre)) + Yvar = np.empty((1+self._M, Npre)) + + for i in range(self._M+1): + for j in range(Npre): + Ypre[i,j] = self.surrogate[i].prediction(Xpre[j]) + Yvar[i,j] = self.surrogate[i].uncertainty(Xpre[j]) + + YpreU = Ypre + sigma_ratio*np.sqrt(Yvar) + YpreL = Ypre - sigma_ratio*np.sqrt(Yvar) + + color_dataOrg = ["b", "b"] + color_dataAdp = ["r", "r"] + color_pred = ["g", "c"] + + Yref = self.runParallel(Xpre, proc=proc)[0].T + fig = plt.figure() + for l in range(1+self._M): + plt.plot(Xpre, Yref[i], linestyle="dashed") # Reference: only when analytical function is used. + plt.plot(self._Xorg, self._Yorg[:,l], "o", color=color_dataOrg[l]) # data points (only original) + if len(self._Xadp) != 0:# np.array([]): + plt.plot(self._Xadp, self._Yadp[:,l], "o", color=color_dataAdp[l]) # data points (only adaptive) + plt.plot(Xpre, Ypre[l], color=color_pred[l]) # surrogate models (prediction) + plt.fill_between(Xpre.reshape(len(Xpre)), YpreU[l], YpreL[l], facecolor='y',alpha=0.5) # surrogate models (uncertainty - one sigma) + plt.plot(self.xopt, self.yopt[l]) # the point of the optimum solution + plt.savefig("figure_{}.jpg".format(l)) + plt.close() + + elif D == 2: + for l in range(1+self._M): # make a graphs for each output (one cost function + other constraint functions) + x1 = np.linspace(self._xbounds[0][0], self._xbounds[0][1], Npre, dtype=np.float64) + x2 = np.linspace(self._xbounds[1][0], self._xbounds[1][1], Npre, dtype=np.float64) + X1, X2 = np.meshgrid(x1, x2) + Y = np.empty( (Npre, Npre), dtype=np.float64 ) + if l != 0: + YboundsL = np.empty( (Npre, Npre), dtype=np.float64 ) + YboundsU = np.empty( (Npre, Npre), dtype=np.float64 ) + for i in range(Npre): + for j in range(Npre): + xpre = np.array( ( x1[i], x2[j] ), dtype=np.float64) + Y[j,i] = self.surrogate[l].prediction(xpre) + if l != 0: + YboundsL[j,i] = self._gbounds[l-1][0] + YboundsU[j,i] = self._gbounds[l-1][1] + + fig = plt.figure() + ax1 = Axes3D(fig) + ax1.plot_surface(X1, X2, Y, cmap = "summer", alpha = 0.5) + if l != 0: + if not np.isinf(self._gbounds[l-1][0]): + print("showing the lower bound") + ax1.plot_surface(X1, X2, YboundsL, cmap = "plasma_r", alpha = 0.5) + if not np.isinf(self._gbounds[l-1][1]): + print("showing the upper bound") + ax1.plot_surface(X1, X2, YboundsU, cmap = "plasma_r", alpha = 0.5) + ax1.scatter(self._Xorg[ :,0], self._Xorg[ :,1], self._Yorg[:,l], c="k", s=18) # original sample points by DoE (black) + if self._Xadp.size != 0: + ax1.scatter(self._Xadp[ :,0], self._Xadp[ :,1], self._Yadp[:,l], c="b", s=36) # adaptive sample points (blue) + ax1.scatter(self.xopt[0] , self.xopt[1] , self.yopt[l], c="r", s=36) # opt point (red) + fig.suptitle("ACq={}, xopt={}, yopt={}, gradientOptSurrogate={}, theta={}, E={}".format(self._method, self.xopt, self.yopt[l], self._gradientOptSurrogate, self.surrogate[l].theta, self.surrogate[l]._errorFunction())) +# plt.savefig("N={}, Ni={}, method={}, xopt={}, yopt={}, gradientOptSurrogate={}, theta={}, E={}.jpg".format(self._N, self._Nimposed, self._method, self.xopt, self.yopt[l], self._gradientOptSurrogate, self.surrogate[l].theta, self.surrogate[l]._errorFunction())) + plt.show() + plt.close() + + else: + raise NotImplementedError("no visalization for this dimension of the input variables") + + +class _ConstraintsSurrogate: + def __init__(self, surrogate): # surrogate: _GP class (not a list of models) + self._surrogate = surrogate + def predict(self, x): + return self._surrogate.prediction(x) + + +class Functions: + """ + used only for the method "ordinary" to separately treat the output values of userinput.functions + """ + def __init__(self, functions): + self._functions = functions + self._last_x = None + def compute(self, x): + if self._last_x is None or not np.all(self._last_x==x): + self.fg = self._functions(x) # "Success" or "Failure" is ignored in the current version (since this class is used only for the method "ordinary"). + self._last_x = x + def costFunction(self, x): + self.compute(x) + return self.fg[0][0] + def constraintFunction(self, x, i): + self.compute(x) + return self.fg[0][i+1] + + +def negAcquisitionFunction(x, surrogate, functionName): + """ + Return the negative value of the acquisition function computed in gaussianProcess.py + + :param x: input variables + :type x: np.ndarray(2D) + :param surrogate: a surrogate model instance created by the GP class in gaussianProcess.py + :type surrogate: class GP + :param functionName: specify the acquisition function from "EI", "PI", "variance" + :type functionName: string + """ + return -surrogate.acquisitionFunction(x, functionName) + +def negComposedAcquisitionFunction(x, surrogates, gbounds): + """ + Compute a composed acquisition function used for constrained optimization. For the precision of the computations for optimal solution of product of several acquisiton funcitons, the log scale is used. + + :param x: input variables + :type x: np.ndarray(2D) + :param surrogates: list of surrogate model instances, each of which is created by the GP class in gaussianProcess.py + :type surrogates: list + :param gbounds: min and max values of each of the constraint functions + :type gbounds: list + """ + M = len(gbounds) + f = np.log(np.fabs(surrogates[0].acquisitionFunction(x, "EI"))) + for i in range(M): + if gbounds[i][0] == gbounds[i][1]: + continue + f += np.log(np.fabs(surrogates[i+1].acquisitionFunction(x, "PI", gbounds[i][0], gbounds[i][1]))) + return -f diff --git a/UNICADOworkflow/src/optimization/sensitivityAnalysis.py b/UNICADOworkflow/src/optimization/sensitivityAnalysis.py new file mode 100644 index 0000000000000000000000000000000000000000..bac1783344d260c36f7768f11f18044cee2c874a --- /dev/null +++ b/UNICADOworkflow/src/optimization/sensitivityAnalysis.py @@ -0,0 +1,96 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +""" +A temporary API module just as an example if the sensitivity analysis is necesary. +(As a theory, the results of the sensitivity analysis is dependent on the output and the ranges of the input.) + +Author: Daigo Maruyama +Technical contact: d.maruyama@tu-braunschweig.de +""" + +### standard libraries (includig numpy, scipy) ### +import numpy as np + +### the modules in this package ### +import gaussianProcess, doe # stand-alone modules in the package +import userinput + +### a special library for Sobol Indices - SALib ### +#from SALib.sample import saltelli +#from SALib.analyze import sobol + + +class globalSensitivity: + def __init__(self, X, Y, multiStart=10): + self.surrogate = gaussianProcess.GP.MLE(X, Y, regularization=False, multiStart=multiStart) + + def ard(self): + sensitivity = self.surrogate.automatic_relevance_determination() + # surrogate update based on acqisitionFunction (with method="variance") can be inserted here to enhance the quality of the surrogate model efficiently. + return sensitivity + + def sobolIndices(self): + NotImplementedError("can be added when necessary.") + """ + a process using self.surrogate and the module SALib + """ +# return sensitivity + + +if __name__ == "__main__": + """ + The easiest way in the current API is: + + just execute main.py + Then, do: + M = len(gbounds) + for i in range(1+M): + print(formulation.surrogate[i].automatic_relevance_determination()) + """ + + """ + Need to generate Data: (X, Y): + """ + + # if you already have a dataset: +# X = np.loadtxt("DoE") # bounds = [ [600, 650], [0.3, 0.34] ] +# Y = np.loadtxt("mission_energy_data").reshape(-1, 1) + + # Otherwise, generate a dataset by yourself: + N = 75 + X = doe.QMC.Sobol(N, bounds=[ [-2., 2.], [-1., 3.] ])[:] + Y = np.empty((N, 1), dtype=np.float64) + delX = np.empty(N, dtype=str) + for i in range(N): + Y[i], delX[i] = userinput.functions2D(X[i]) # your function evaluation (e.g. extracted from userinput.py) + if len(delX) > 0: + X = np.array([i for j, i in enumerate(X) if j not in delX]) + + print("X =", X) + print("Y =", Y) + + ingredients = globalSensitivity(X, Y, multiStart=1) + + sensitivityARD = ingredients.ard() + print(sensitivityARD) + +# sensitivitySobol = ingredients.sobolIndices() +# print(sensitivitySobol) diff --git a/UNICADOworkflow/src/parameter_study/estimate_input_value_from_configuration_file.py b/UNICADOworkflow/src/parameter_study/estimate_input_value_from_configuration_file.py new file mode 100644 index 0000000000000000000000000000000000000000..7bbf6f848c3069206fc6de6fb687292310f4093a --- /dev/null +++ b/UNICADOworkflow/src/parameter_study/estimate_input_value_from_configuration_file.py @@ -0,0 +1,273 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def estimate_input_value_from_configuration_file(root_of_study_xml_file, input_parameter_settings, + path_to_current_study, corrected_xml_path, log_file_list): + """ Function to set study counter dependent input parameter from given parameter study configuration file. + + The input elementTree 'root_of_study_xml_file' contains the parameter of study configuration file as element tree. + + The input list of lists "input_parameter_settings" contains ato following values: + * [0][0] string: 'parameter_name', [0][1] string: 'name of the current study input parameter' + * [1][0] string: 'input_directory_name', [1][1] string: 'name of the input directory of current study parameter' + * [2][0] string: 'input_file_name' [2][1] string: 'name of the input file of the current study parameter' + * [3][0] string: 'path_in_xml_file' [3][1] string: 'path to the study parameter in the input xml-file' + * [4][0] string: 'step_type' [4][1] string: 'mode for step value handling' + * [5][0] string: 'read_values_from_text_file', [5][1] int: 'switch to read iteration values from an external data file' + * [6][0] string: 'step_size', [8][1] float: 'value of step size of current study parameter' + * [7][0] string: 'number_of_steps_up', [9][1] int: 'value of maximum iteration steps upwards are to be performed' + * [8][0] string: 'number_of_steps_down', [10][1] int: 'value of maximum iteration steps downwards are to be performed' + * [9][0] string: 'study_counter' [11][1] int: 'number of iteration loop of current input parameter' + + The input string 'path_to_current_study' contains the absolute path to the working directory of current parameter study. + + The input string 'corrected_xml_path' contains the corrected absolute xml-path of current input parameter. + + The input list "log_file_list" contains all system prints of function: perform_parameter_study.py. + + The output float 'new_value_of_input' contains the new value of current input parameter of current parameter study loop. + + The output bool 'xml_path_status' contains the current status "True" or "False" of current xml-path. + + The output list "log_file_list" contains all system prints of functions: perform_parameter_study.py and read_parameter_study_settings.py. + + :param: root_of_study_xml_file: input string + :param: input_parameter_settings: input list of lists + :param: path_to_current_study: input string + :param: corrected_xml_path: input string + :param: log_file_list: input list + :return: new_value_of_input: output float, xml_path_status: output bool, log_file_list: output list + """ + + ''' imports for python ''' + import os + from datetime import datetime + + ''' initialize local parameter ''' + current_parameter_values = str() + file_value = 1.0 + find_flag = False + number_of_steps_up = 0 + number_of_steps_down = 0 + number_of_runs_to_perform = 1 + step_size = 0 + + ''' read data for script execution ''' + parameter_name = ([item for item in input_parameter_settings if 'parameter_name' in item])[-1][-1] + step_type = ([item for item in input_parameter_settings if 'step_type' in item])[-1][-1] + read_values_from_text_file = \ + int(([item for item in input_parameter_settings if 'read_values_from_text_file' in item])[-1][-1]) + study_counter = int(([item for item in input_parameter_settings if 'study_counter' in item])[-1][-1]) + + # check if the switch of current parameter is selected to read values from csv file -> if true: + # -> initialize parameter to perform study from csv file + if read_values_from_text_file == 1: + if os.path.isfile(path_to_current_study + '/reference_aircraft/parameter_study_values.csv'): + with open(path_to_current_study + '/reference_aircraft/parameter_study_values.csv', 'r') as input_file: + for line in input_file: + if parameter_name in line: + index = line.find(';') + current_parameter_values = line[index+1:] + find_flag = True + number_of_runs_to_perform = current_parameter_values.count(';') + break + input_file.close() + + # error handling if the current parameter does not exist in the parameter study value csv-file + if not find_flag: + read_values_from_text_file = 0 + ([item for item in input_parameter_settings if 'read_values_from_text_file' in item])[-1][-1] =\ + str(read_values_from_text_file) + print('Error: Current parameter "' + parameter_name + + '" does not exist in parameter study value csv-file!\n ' + ' Step up and step down study will be performed!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: Current parameter "' + parameter_name + + '" does not exist in parameter study value csv-file!\n ' + ' Step up and step down study will be performed!') + + else: + read_values_from_text_file = 0 + print('Error: CSV-file for read values for parameter study does not exist!\n' + ' For current parameter "' + parameter_name + + '" step up and step down study will be performed!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: CSV-file for read values for parameter study does not exist!\n' + ' For current parameter "' + parameter_name + + '" step up and step down study will be performed!') + + # check if the switch of current parameter is not selected to read values from csv file + # -> initialize parameter to perform step up and step down study + if not read_values_from_text_file == 1: + step_size = float(([item for item in input_parameter_settings if 'step_size' in item])[-1][-1]) + number_of_steps_up = int(([item for item in input_parameter_settings if 'number_of_steps_up' in item])[-1][-1]) + number_of_steps_down = \ + int(([item for item in input_parameter_settings if 'number_of_steps_down' in item])[-1][-1]) + + ''' set local parameters ''' + xml_path_status = True + new_value_of_input = float(0.0) + current_value_of_input = float(0.0) + reference_value_of_input = float(0.0) + + ''' set study count dependent input value ''' + # check if current study counter is equal to 1 -> if true: -> set new reference value to temporary *.dat file + if study_counter == 1: + current_value_of_input = root_of_study_xml_file.find(corrected_xml_path).text + + # check for existing temporary reference value file + if os.path.isdir(path_to_current_study + '/temp/'): + if os.path.isfile(path_to_current_study + '/temp/reference_value_of_current_input.dat'): + os.remove(path_to_current_study + '/temp/reference_value_of_current_input.dat') + # else condition: create temporary directory + else: + os.mkdir(path_to_current_study + '/temp/') + + # write reference value to temporary *.dat file + reference_file = open(path_to_current_study + '/temp/reference_value_of_current_input.dat', 'a') + reference_file.write(str(current_value_of_input)) + reference_file.close() + + # else condition: current study counter is greater than 1 + # -> read reference value from temporary reference *.dat file + else: + reference_file = open(path_to_current_study + '/temp/reference_value_of_current_input.dat', 'r') + reference_value_of_input = reference_file.read() + reference_file.close() + + ''' set new value for next workflow execution ''' + if step_type == "mode_0": # use values as absolute values + if read_values_from_text_file: + i = 1 + while i <= study_counter: + index = current_parameter_values.find(';') + file_value = current_parameter_values[:index] + current_parameter_values = current_parameter_values[index + 1:] + i += 1 + + new_value_of_input = file_value + else: + # check if the first run of current input parameter should be performed + if study_counter == 1: + # check if any steps-up have to be performed + # -> estimate the highest step change as new input study value + if number_of_steps_up > 0: + new_value_of_input = float(current_value_of_input) + (number_of_steps_up * step_size) + # else if condition: # check if any steps-down have to be performed + # -> estimate the lowest step change as new input study value + elif number_of_steps_down > 0: + new_value_of_input = float(current_value_of_input) - step_size + # else condition: no steps up and no steps down are set in the parameter study configuration file + # -> input parameter will be skipped + else: + xml_path_status = False + + # else condition: current run is not the first one of current input parameter + else: + # check if any steps up have to be performed -> if true: -> estimate new input value for step up case + if (number_of_steps_up - (study_counter - 1)) > 0: + new_value_of_input = \ + float(reference_value_of_input) + ((number_of_steps_up - (study_counter - 1)) * step_size) + # else condition: no more steps up have to be performed -> estimate new input value for step down case + else: + diff = (number_of_steps_up - number_of_steps_down) + new_value_of_input = float(reference_value_of_input) - \ + (((number_of_steps_down - study_counter + diff) * -1) * step_size) + elif step_type == "mode_1": # use values as delta values + if read_values_from_text_file: + i = 1 + while i <= study_counter: + index = current_parameter_values.find(';') + file_value = current_parameter_values[:index] + current_parameter_values = current_parameter_values[index + 1:] + i += 1 + + if study_counter == 1: + new_value_of_input = round(float(current_value_of_input) + float(file_value), 6) + else: + new_value_of_input = round(float(reference_value_of_input) + float(file_value), 6) + else: + # check if the first run of current input parameter should be performed + if study_counter == 1: + # check if any steps-up have to be performed + # -> estimate the highest step change as new input study value + if number_of_steps_up > 0: + new_value_of_input = float(current_value_of_input) + (number_of_steps_up * step_size) + # else if condition: # check if any steps-down have to be performed + # -> estimate the lowest step change as new input study value + elif number_of_steps_down > 0: + new_value_of_input = float(current_value_of_input) - step_size + # else condition: no steps up and no steps down are set in the parameter study configuration file + # -> input parameter will be skipped + else: + xml_path_status = False + + # else condition: current run is not the first one of current input parameter + else: + # check if any steps up have to be performed -> if true: -> estimate new input value for step up case + if (number_of_steps_up - (study_counter - 1)) > 0: + new_value_of_input = \ + float(reference_value_of_input) + ((number_of_steps_up - (study_counter - 1)) * step_size) + # else condition: no more steps up have to be performed -> estimate new input value for step down case + else: + diff = (number_of_steps_up - number_of_steps_down) + new_value_of_input = float(reference_value_of_input) - \ + (((number_of_steps_down - study_counter + diff) * -1) * step_size) + elif step_type == "mode_2": # use values as relative values to reference + if read_values_from_text_file: + i = 1 + while i <= study_counter: + index = current_parameter_values.find(';') + file_value = current_parameter_values[:index] + current_parameter_values = current_parameter_values[index + 1:] + i += 1 + + if study_counter == 1: + new_value_of_input = round(float(current_value_of_input) * (1 + float(file_value)), 6) + else: + new_value_of_input = round(float(reference_value_of_input) * (1 + float(file_value)), 6) + else: + # check if the first run of current input parameter should be performed + if study_counter == 1: + # check if any steps-up have to be performed + # -> estimate the highest step change as new input study value + if number_of_steps_up > 0: + new_value_of_input = float(current_value_of_input) * (1 + (number_of_steps_up * step_size)) + # else if condition: # check if any steps-down have to be performed + # -> estimate the lowest step change as new input study value + elif number_of_steps_down > 0: + new_value_of_input = float(current_value_of_input) * (1 - step_size) + # else condition: no steps up and no steps down are set in the parameter study configuration file + # -> input parameter will be skipped + else: + xml_path_status = False + # else condition: current run ist not the first one of current input parameter + else: + # check if any steps up have to be performed -> if true: -> estimate new input value for step up case + if (number_of_steps_up - (study_counter-1)) > 0: + new_value_of_input = \ + float(reference_value_of_input) * (1 + ((number_of_steps_up - (study_counter-1)) * step_size)) + # else condition: no more steps up have to be performed -> estimate new input value for step down case + else: + diff = (number_of_steps_up - number_of_steps_down) + new_value_of_input = float(reference_value_of_input) * \ + (1 - ((number_of_steps_down - study_counter + diff) * -1) * step_size) + + return new_value_of_input, xml_path_status, number_of_runs_to_perform, log_file_list diff --git a/UNICADOworkflow/src/parameter_study/initialize_parameter_study.py b/UNICADOworkflow/src/parameter_study/initialize_parameter_study.py new file mode 100644 index 0000000000000000000000000000000000000000..159e6ce7a0cf8f9757aabb5d2507f252857c0410 --- /dev/null +++ b/UNICADOworkflow/src/parameter_study/initialize_parameter_study.py @@ -0,0 +1,391 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def initialize_parameter_study(paths_and_names, log_file_list): + """ Function to prepare parameter study output folder and generate back-up data. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list "log_file_list" contains all system prints of function: set_configuration_parameter.py. + + The output bool "abort_parameter_study_flag" contains the status to abort the parameter study or not. + + The output list "log_file_list" contains all system prints of functions: set_configuration_parameter.py and initialize_parameter_study.py. + + :param: paths_and_names: input list of lists + :param: log_file_list: input list + :return: abort_parameter_study_flag: output bool, log_file_list: output list + """ + + ''' imports of python ''' + import os + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.path_check import path_check + from sub_function.read_xml_file import read_xml_file + from parameter_study.prepare_resume_of_parameter_study import prepare_resume_of_parameter_study + from parameter_study.set_parameter_for_resume_parameter_study import set_parameter_for_resume_parameter_study + + ''' read data for script execution ''' + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory = ([item for item in paths_and_names if 'path_of_working_directory' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + ''' initialize local parameter ''' + parameter_list = [] + csv_row_counter = 0 + csv_file_read_flag = False + number_of_total_steps = 0 + abort_parameter_study_flag = False + function_name = getframeinfo(currentframe()).function + + ''' open and read parameter from parameter_study_conf.xml configuration file to element tree ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/parameter_study_conf.xml' + root_of_parameter_study_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'parameter_study', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + reproduce_output_file_from_old_study = int(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/ReproduceOutputFileFromOldStudy").text) + path_to_folder_old_study = str(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/PathToFolderOldStudy").text) + save_results = int(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/SaveResults").text) + save_only_aircraft_exchange_files = int(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/SaveResults").get('OnlyAiXFile')) + ''' estimate necessary working folder size ''' + maximum_allowed_folder_size = float(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/MaxFolderSize").text) + number_of_input_parameter = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameters").text) + number_of_output_parameter = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameters").text) + + ''' set paths of current working directory to the configuration file of to the parameter study mode ''' + i = 1 + # loop across all input parameter to set paths + while i <= number_of_input_parameter: + path_in_xml_file = str(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(i) + "'" + + "]PathInXmlFile").text) + + # check if the string "AcftExchangeFile" in the given xml-path -> if true: -> set path to aircraft exchange file + if "AcftExchangeFile" in path_in_xml_file: + root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(i) + "'" + "]RelDirectory").text \ + = str('../workingDirectoryRCE/' + current_workflow_name + '/' + aircraft_project) + + # check if the string "ConfigFile" in the given xml-path -> if true: -> set path to module configuration file + elif "ConfigFile" in path_in_xml_file: + root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(i) + "'" + "]RelDirectory").text \ + = str('../workingDirectoryRCE/' + current_workflow_name) + i += 1 + + i = 1 + # loop across all output parameter to set paths + while i <= number_of_output_parameter: + path_in_xml_file = str(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameter[" + "@ID='" + str(i) + "'" + + "]PathInXmlFile").text) + + # check if the string "AcftExchangeFile" in the given xml-path -> if true: -> set path to aircraft exchange file + if "AcftExchangeFile" in path_in_xml_file: + root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameter[" + "@ID='" + str(i) + "'" + "]RelDirectory").text\ + = str('../workingDirectoryRCE/' + current_workflow_name + '/' + aircraft_project) + + # check if the string "ConfigFile" in the given xml-path -> if true: -> set path to module configuration file + elif "ConfigFile" in path_in_xml_file: + root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameter[" + "@ID='" + str(i) + "'" + "]RelDirectory").text\ + = str('../workingDirectoryRCE/' + current_workflow_name) + i += 1 + + xml_tree.write(path, encoding='utf-8') + + ''' initialize working directory of parameter study ''' + # check if the reproduce output from old study switch is selected + # -> if true: -> use working directory of old study if it exists + if reproduce_output_file_from_old_study == 1: + # check if the working directory of old study is existing + # -> if true: -> set path of old study to path of current + if os.path.isdir(path_to_folder_old_study): + # call function to check the path of old study + _, path_to_folder_old_study = path_check(path_to_folder_old_study) + + # set path to reference case of old parameter study to resume + path_to_folder_old_reference = path_to_folder_old_study + 'reference_aircraft/' + + # check if the reference aircraft directory exist -> if true perform the resume of the parameter study + if os.path.isdir(path_to_folder_old_reference): + temporary_working_directory = path_of_working_directory_rce + current_workflow_name + # call function to prepare resuming of old parameter study + paths_and_names, abort_parameter_study_flag, log_file_list =\ + prepare_resume_of_parameter_study(paths_and_names, path_to_folder_old_reference, + temporary_working_directory, log_file_list) + + # call function to check which parameter is next to analyse + abort_parameter_study_flag, number_of_total_steps, log_file_list = \ + set_parameter_for_resume_parameter_study(paths_and_names, path_to_folder_old_study, + log_file_list) + + # else condition: the reference aircraft directory does not exist -> abort parameter study + else: + abort_parameter_study_flag = True + print('Error: The entered path to the folder of old parameter study does not exist! \n' + 'After finishing the reference aircraft estimation the parameter study will be aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Error: The entered path to the folder of old parameter study does not exist!' + '\n' + 'After finishing the reference aircraft estimation the parameter study will be' + ' aborted!') + + # else condition: entered path to old study does not exist + else: + abort_parameter_study_flag = True + print('Error: The entered path to the folder of old parameter study does not exist! \n' + 'After finishing the reference aircraft estimation the parameter study will be aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Error: The entered path to the folder of old parameter study does not exist! \n' + 'After finishing the reference aircraft estimation the parameter study will be' + ' aborted!') + + # else condition: reproduce output from old study switch is not selected + # -> create new output working directory for parameter study + else: + # generate working dir + working_dir_name = path_of_working_directory + 'workflowResults/' + current_workflow_name + '_' \ + + aircraft_project + '_parameter_study' + # set path of parameter study working directory to parameter study configuration file + root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/PathToCurrentStudy").text = working_dir_name + xml_tree.write(path, encoding='utf-8') + # check if the working_dir_name directory is not existing + # -> if true: -> create parameter study working and output directory + if not os.path.isdir(working_dir_name): + # create parameter study working and output directory + os.makedirs(working_dir_name + '/output_csv/') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Path to parameter study working directory: ' + working_dir_name) + + # copy module pre-execution configuration files to reference directory + shutil.copytree(path_of_working_directory_rce + current_workflow_name + '/temporaryResults', + working_dir_name + '/reference_aircraft/') + + # copy engine_data to reference directory + # -> if an engine_data directory exist in the current project directory copy that + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/engine_data/'): + shutil.copytree(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/engine_data/', working_dir_name + '/reference_aircraft/engine_data') + # else copy from engine tool directory + else: + shutil.copytree(path_of_working_directory + 'databases/engines/', + working_dir_name + '/reference_aircraft/engine_data') + + # copy aero data if retrofit data exist + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/aero_data/'): + shutil.copytree(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/aero_data/', working_dir_name + '/reference_aircraft/aero_data') + + # copy geometry data if retrofit data exist + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/geometry_data/'): + shutil.copytree(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/geometry_data/', working_dir_name + '/reference_aircraft/geometry_data') + + # copy mission data if retrofit data exist + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/mission_data/'): + shutil.copytree(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/mission_data/', working_dir_name + '/reference_aircraft/mission_data') + + # copy aircraft exchange file of current project to reference directory + shutil.copyfile(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + + aircraft_project + '.xml', + working_dir_name + '/reference_aircraft/' + aircraft_project + '_start.xml') + + # copy cpacs file of current project to reference directory + #shutil.copyfile(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + # + aircraft_project + '_CPACS.xml', + # working_dir_name + '/reference_aircraft/' + aircraft_project + '_CPACS.xml') + + # copy parameter study configuration file of current project to reference directory + shutil.copyfile(path_of_working_directory_rce + current_workflow_name + '/parameter_study_conf.xml', + working_dir_name + '/reference_aircraft/' + 'parameter_study_conf.xml') + + # copy parameter study value file of current project to reference directory + shutil.copyfile(path_of_working_directory_rce + current_workflow_name + '/parameter_study_values.csv', + working_dir_name + '/reference_aircraft/' + 'parameter_study_values.csv') + + # copy starting workflow configuration file of current project as back up file to reference directory + shutil.copyfile(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow_conf.xml', + working_dir_name + '/reference_aircraft/' + 'unicado_workflow_conf_start.xml') + + # read workflow configuration file as element tree to set necessary switches to avoid outer manipulation + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/unicado_workflow_conf.xml' + root_of_workflow_tree, xml_workflow_tree = read_xml_file(path, path_of_working_directory_rce, + 'unicado_workflow', function_name, + frame_info.lineno, log_file_list, + current_workflow_name) + + root_of_workflow_tree.find( + './control_settings/program_specific_settings/' + 'pre_workflow_operation_settings/set_project_folder_to_default/value').text = str(bool(0)).lower() + root_of_workflow_tree.find( + './control_settings/program_specific_settings/' + 'pre_workflow_operation_settings/delete_engines_before_run/value').text = str(bool(0)).lower() + root_of_workflow_tree.find( + './control_settings/program_specific_settings/' + 'iteration_settings/use_configs_from_existing_project/config_copy_mode/value').text = "mode_0" + root_of_workflow_tree.find( + './control_settings/program_specific_settings/' + 'iteration_settings/use_engine_from_existing_project/engine_copy_mode/value').text = "mode_0" + xml_workflow_tree.write(path, encoding='utf-8') + + # copy new parameter loop starting workflow configuration file to reference directory + shutil.copyfile(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow_conf.xml', + working_dir_name + '/reference_aircraft/' + 'unicado_workflow_conf.xml') + + # copy range type specific factor file to reference directory if it exists + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/range_type_specific_factors.xml'): + shutil.copyfile(path_of_working_directory_rce + current_workflow_name + + '/range_type_specific_factors.xml', + working_dir_name + '/reference_aircraft/' + 'range_type_specific_factors.xml') + + print('All necessary aircraft reference files have successfully been copied to parameter study working ' + 'directory.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'All necessary aircraft reference files have successfully been copied to parameter' + ' study working directory.') + + # loop across the number of input parameters to estimate total number of necessary workflow loops + for i in range(1, number_of_input_parameter+1): + # hier muss jeder paramter geprüft werden, welcher mode und dann die steps für jeden parameter berechnen + input_selector_of_current_parameter = root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(i) + "'" + + "]ParametricStudy/input_selector").text + if input_selector_of_current_parameter == 'mode_0': + number_of_steps_up = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(i) + "'" + + "]ParametricStudy/input_selector_specific_settings/mode_0/NumberOfStepsUp").text) + number_of_steps_down = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(i) + "'" + + "]ParametricStudy/input_selector_specific_settings/mode_0/NumberOfStepsDown").text) + number_of_total_steps = number_of_total_steps + number_of_steps_up + number_of_steps_down + i += 1 + elif input_selector_of_current_parameter == 'mode_1' and not abort_parameter_study_flag: + if not csv_file_read_flag: + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/parameter_study_values.csv'): + with open(path_of_working_directory_rce + current_workflow_name + '/parameter_study_values.csv', "r") as csv_file: + for line in csv_file: + fields = line.strip().split(";") # Adjust delimiter if needed + parameter_list.append(fields) + else: + abort_parameter_study_flag = True + print('Error: The file parameter_study_values.csv could not be found, but at least one parameter in the' + ' file parmater_study_conf.xml wants to read the input values from there! Program aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: The file parameter_study_values.csv could not be found, but at least one parameter in the' + ' file parmater_study_conf.xml wants to read the input values from there! Program aborted!') + csv_file_read_flag = True + + if not abort_parameter_study_flag: + num_columns = len(parameter_list[csv_row_counter]) + current_parameter_row = parameter_list[csv_row_counter] + if current_parameter_row[-1] == '': + number_of_total_steps += (num_columns - 2) + else: + number_of_total_steps += (num_columns - 1) + csv_row_counter += 1 + else: + abort_parameter_study_flag = True + print('Error: The input_selector of parameter ' + str(i) + ' in parmater_study_conf.xml ' + 'is not mode_0 or mode_1. Program aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: The input_selector of parameter ' + str(i) + ' in parmater_study_conf.xml ' + 'is not mode_0 or mode_1. Program aborted!') + + # Add + 1 to number of total steps for reference calculation + number_of_total_steps += 1 + + # check necessary disk space if the save results switch is set to 1 + if save_results == 1: + # result folder size is temporary set to 35 mb -> temporary hard coded + # -> should be dynamic in a future version + size_of_results_folder_in_mb = 50 + # check if only the aircraft exchange file and the final csv-file should be stored + if save_only_aircraft_exchange_files == 1: + # result folder size is temporary set to 0.5 mb -> temporary hard coded + # -> should be dynamic in a future version + size_of_results_folder_in_mb = 0.5 + total_necessary_disk_space_in_gb = float((number_of_total_steps * size_of_results_folder_in_mb)/1024) + if total_necessary_disk_space_in_gb <= maximum_allowed_folder_size: + print('For planned parameter study the necessary disk space in GB is: ' + + str(total_necessary_disk_space_in_gb)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'For planned parameter study the necessary disk space in GB is: ' + + str(total_necessary_disk_space_in_gb)) + else: + abort_parameter_study_flag = True + print('ERROR: For planned parameter study required disk space ( ' + + str(total_necessary_disk_space_in_gb) + 'GB) is greater than the maximum allowed of ' + + str(maximum_allowed_folder_size) + 'GB! \n' + ' * After finishing the reference aircraft estimation the parameter study will be aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'ERROR: For planned parameter study required disk space ( ' + + str(total_necessary_disk_space_in_gb) + + 'GB) is greater than the maximum allowed of ' + + str(maximum_allowed_folder_size) + 'GB! \n ' + '* After finishing the reference aircraft estimation the parameter study will be' + ' aborted!') + + # else condition: no results should be saved + # -> only one single csv-file with results and the reference data will be generated + else: + print('No results of parameter study will be saved! Only one single csv-file with results and the reference' + ' data will be generated!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'No results of parameter study will be saved! Only one single csv-file with results ' + 'and the reference data will be generated!') + + return abort_parameter_study_flag, number_of_total_steps, log_file_list diff --git a/UNICADOworkflow/src/parameter_study/perform_parameter_study.py b/UNICADOworkflow/src/parameter_study/perform_parameter_study.py new file mode 100644 index 0000000000000000000000000000000000000000..b1d765bc0532c6350ed7b6688c3f113f9d998355 --- /dev/null +++ b/UNICADOworkflow/src/parameter_study/perform_parameter_study.py @@ -0,0 +1,207 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def perform_parameter_study(install_path_directory, study_counter, outer_loop_counter, global_loop_counter, + perform_workflow_execution, current_workflow_name='UNICADOworkflow'): + """ Function to perform the parameter study mode. + + The input string "install_path_directory" contains the absolute path to the UNICADO install directory. + + The input integer "study_counter" contains the current number of parameter study of current input parameter. + + The input integer "outer_loop_counter" contains the maximum number of parameter studies to perform. + + The input integer "global_loop_counter" contains the current number of parameter study loop. + + The input integer "perform_workflow_execution" contains the status to perform the parameter study or not. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output integer "outer_loop_counter" contains the maximum number of parameter studies to perform. + + The output integer "study_counter" contains the current number of parameter study of current input parameter. + + The output string "parameter_name" contains the name of the current parameter study input. + + The output float 'new_value_of_input' contains the new parameter iteration value of current loop. + + :param: install_path_directory: input string + :param: study_counter: input integer + :param: outer_loop_counter: input integer + :param: global_loop_counter: input integer + :param: perform_workflow_execution: input integer + :param: current_workflow_name: input string + :return: outer_loop_counter: output integer, study_counter: output integer, parameter_name: output string, new_value_of_input: output float + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + from parameter_study.reset_parameter_study_files import reset_parameter_study_files + from parameter_study.set_input_parameter_settings import set_input_parameter_settings + from parameter_study.read_parameter_study_settings import read_parameter_study_settings + from parameter_study.read_input_parameter_settings import read_input_parameter_settings + from sub_function.write_to_log_file import write_to_log_file + + ''' initialize local parameter ''' + log_file_list = [''] + xml_path_status = False + parameter_name = str('no parameter') + new_value_of_input = float(0.0) + number_of_current_parameter = 0 + + ''' read parameter study parameter from configuration file ''' + # call function to read configuration file of parameter study + parameter_study_list, log_file_list = read_parameter_study_settings(install_path_directory, log_file_list, + current_workflow_name) + + ''' read configuration parameter for current input parameter ''' + path_to_current_study = \ + str(([item for item in parameter_study_list if 'path_to_current_study' in item])[-1][-1]) + number_of_input_parameter = \ + int(([item for item in parameter_study_list if 'number_of_input_parameter' in item])[-1][-1]) + start_every_run_with_ref_file = \ + int(([item for item in parameter_study_list if 'start_every_run_with_ref_file' in item])[-1][-1]) + + ''' check if the parameter study should be performed -> if true: -> perform parameter study ''' + if perform_workflow_execution == 1: + ''' reset project files to default ''' + if start_every_run_with_ref_file == 1: + # call function to reset project files if selected in parameter study configuration file + log_file_list = reset_parameter_study_files(install_path_directory, path_to_current_study, + perform_workflow_execution, log_file_list, + current_workflow_name) + else: + print('Switch to run every loop with reference files is set to 0! -> No files will be reset to default!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Switch to run every loop with reference files is set to 0! ' + '-> No files will be reset to default!') + + ''' preparation of input parameter settings of current loop execution ''' + # loop across the status of current xml-path -> if the status is equal to "False" + # -> current input parameter is skipped and the next one will be used + while not xml_path_status: + xml_path_status = True + if study_counter == 0: + # check for existing temp directory + if os.path.isdir(path_to_current_study + '/temp/'): + if os.path.isfile(path_to_current_study + '/temp/number_of_current_parameter.dat'): + parameter_file = open(path_to_current_study + '/temp/number_of_current_parameter.dat', 'r') + number_of_current_parameter = int(parameter_file.read()) + parameter_file.close() + + # delete old temporary directory + shutil.rmtree(path_to_current_study + '/temp/') + + # create new temporary directory for current input parameter of study + os.mkdir(path_to_current_study + '/temp/') + parameter_file = open(path_to_current_study + '/temp/number_of_current_parameter.dat', 'a') + parameter_file.write(str(number_of_current_parameter + 1)) + parameter_file.close() + log_file_list.append(' --- Parameter study of input parameter ' + str(number_of_current_parameter + 1) + + ' will performed. --- ') + print(' --- Parameter study of input parameter ' + str(number_of_current_parameter + 1) + + ' will performed. --- ') + number_of_current_parameter += 1 + + # check if number of current parameter is not greater than the total number of input parameter + # -> read and set study input parameter settings + if not number_of_current_parameter > number_of_input_parameter: + # call function to read configuration parameter of current study input parameter + study_counter += 1 + input_parameter_settings, log_file_list = read_input_parameter_settings(install_path_directory, + path_to_current_study, + study_counter, log_file_list, + current_workflow_name) + + parameter_name = \ + str(([item for item in input_parameter_settings if 'parameter_name' in item])[-1][-1]) + number_of_steps_up = \ + int(([item for item in input_parameter_settings if 'number_of_steps_up' in item])[-1][-1]) + number_of_steps_down = \ + int(([item for item in input_parameter_settings if 'number_of_steps_down' in item])[-1][-1]) + + if study_counter == 1: + print(path_to_current_study + '/' + parameter_name) + if os.path.isdir(path_to_current_study + '/' + parameter_name): + shutil.rmtree(path_to_current_study + '/' + parameter_name) + + # call function to set input study parameter to necessary xml-files + xml_path_status, new_value_of_input, number_of_runs_to_perform, log_file_list = \ + set_input_parameter_settings(install_path_directory, path_to_current_study, + input_parameter_settings, xml_path_status, log_file_list, + current_workflow_name) + + read_values_from_text_file = \ + int(([item for item in input_parameter_settings if 'read_values_from_text_file' in item])[-1][-1]) + + if not read_values_from_text_file == 1: + # check if number of max studies of current input parameter are be performed + # or the current parameter study will be skipped -> if true: -> reset study counter to zero + if (number_of_steps_up + number_of_steps_down) == study_counter or not xml_path_status: + # check if the current parameter study will be skipped + # -> if true: -> reduce outer loop counter by the summation of steps up and down of current + # study input parameter + if not xml_path_status: + outer_loop_counter = outer_loop_counter - (number_of_steps_up + number_of_steps_down) + + study_counter = 0 + + else: + # check if number of max studies of current input parameter are be performed + # or the current parameter study will be skipped -> if true: -> reset study counter to zero + if number_of_runs_to_perform == study_counter or not xml_path_status: + # check if the current parameter study will be skipped + # -> if true: -> reduce outer loop counter by the summation of steps up and down of current + # study input parameter + if not xml_path_status: + outer_loop_counter = outer_loop_counter - number_of_runs_to_perform + + study_counter = 0 + + # else condition: number of current parameter is greater than the total number of input parameter + # -> parameter study is finished -> terminate workflow after final run + else: + outer_loop_counter = 1 + + # else condition: parameter study is finished or should not be performed -> reset all files to initial status + else: + log_file_list = reset_parameter_study_files(install_path_directory, path_to_current_study, + perform_workflow_execution, log_file_list, current_workflow_name) + path_to_temp = install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/temp/' + if global_loop_counter == 2 and (os.path.isfile(path_to_temp + 'convergenceError.dat') + or os.path.isfile(path_to_temp + 'workflowExecutionError.dat')): + print('Error in the calculation of the reference case!') + print('No valid design!') + print('Parameter study is canceled and workflow is terminated!') + log_file_list.append('Error in the calculation of the reference case!') + log_file_list.append('No valid design!') + log_file_list.append('Parameter study is canceled and workflow is terminated!') + + if os.path.isdir(path_to_current_study + '/temp/'): + shutil.rmtree(path_to_current_study + '/temp/') + print('Temporary working directory of parameter study successfully deleted!') + + ''' write log-file to system ''' + write_to_log_file(install_path_directory + '/workingDirectoryRCE/', current_workflow_name, log_file_list) + + return outer_loop_counter, study_counter, parameter_name, new_value_of_input diff --git a/UNICADOworkflow/src/parameter_study/prepare_resume_of_parameter_study.py b/UNICADOworkflow/src/parameter_study/prepare_resume_of_parameter_study.py new file mode 100644 index 0000000000000000000000000000000000000000..fbe16c251a34d6d2e9772dd2fab47019443a1b66 --- /dev/null +++ b/UNICADOworkflow/src/parameter_study/prepare_resume_of_parameter_study.py @@ -0,0 +1,312 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def prepare_resume_of_parameter_study(paths_and_names, path_to_folder_old_reference, temporary_working_directory, + log_file_list): + """ Function to prepare resuming an old parameter study from existing old parameter study output folder. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input string "path_to_folder_old_reference" contains the absolute path to the reference aircraft from old parameter study. + + The input string "temporary_working_directory" contains the absolute path to the temporary working directory of current workflow execution. + + The input list "log_file_list" contains all system prints of function: set_configuration_parameter.py. + + The output list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The output bool "abort_parameter_study_flag" contains the status to abort the parameter study or not. + + The output list "log_file_list" contains all system prints of functions: set_configuration_parameter.py and initialize_parameter_study.py. + + :param: paths_and_names: input list of lists + :param: path_to_folder_old_reference: input string + :param: temporary_working_directory: input string + :param: log_file_list: input list + :return: paths_and_names: input list of lists, abort_parameter_study_flag: output bool, log_file_list: output list + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.path_check import path_check + from sub_function.read_xml_file import read_xml_file + + ''' read data for script execution ''' + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + ''' initialize local parameter ''' + root_of_workflow_tree = [] + abort_parameter_study_flag = False + function_name = getframeinfo(currentframe()).function + + ''' read aircraft project name from old workflow configuration file ''' + if os.path.isfile(path_to_folder_old_reference + 'unicado_workflow_conf_start.xml'): + frame_info = getframeinfo(currentframe()) + path = path_to_folder_old_reference + 'unicado_workflow_conf_start.xml' + root_of_workflow_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + 'UNICADOworkflow_start', function_name, + frame_info.lineno, log_file_list, + current_workflow_name) + + elif os.path.isfile(path_to_folder_old_reference + 'unicado_workflow_conf.xml'): + frame_info = getframeinfo(currentframe()) + path = path_to_folder_old_reference + 'unicado_workflow_conf.xml' + root_of_workflow_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + 'unicado_workflow_conf', function_name, + frame_info.lineno, log_file_list, + current_workflow_name) + + else: + abort_parameter_study_flag = True + + ''' copy reference files from old parameter study directory to current working directory ''' + if not abort_parameter_study_flag: + # delete existing aircraft project files from temporary working directory of current workflow execution + list_of_temporary_files = os.listdir(temporary_working_directory) + for list_element in list_of_temporary_files: + # check if current list element is a directory -> if true: -> delete directory and sub folder if exist + if os.path.isdir(temporary_working_directory + '/' + list_element): + shutil.rmtree(temporary_working_directory + '/' + list_element) + + # else condition: current list element is a file -> delete file + else: + # check if the current file is not the workflow log file -> if true: -> delete file + if not list_element == 'unicado_workflow.log': + os.remove(temporary_working_directory + '/' + list_element) + + # read name of aircraft project from old parameter study + aircraft_project = root_of_workflow_tree.find("./control_settings/aircraft_exchange_file_name/value").text + ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] = aircraft_project[:-4] + + # create new aircraft project folder in temporary working directory + if not os.path.isdir(temporary_working_directory + '/' + aircraft_project[:-4]): + os.makedirs(temporary_working_directory + '/' + aircraft_project[:-4] + '/cleanSheetDesign') + + # create new temporary result folder in temporary working directory + if not os.path.isdir(temporary_working_directory + '/temporaryResults'): + os.mkdir(temporary_working_directory + '/temporaryResults') + + # create new temporary folder in temporary working directory + if not os.path.isdir(temporary_working_directory + '/temp'): + os.mkdir(temporary_working_directory + '/temp') + + # read elements from old parameter study directory + list_of_elements = os.listdir(path_to_folder_old_reference) + if not 'parameter_study_conf.xml' in list_of_elements: + abort_parameter_study_flag = True + + for element in list_of_elements: + # check if current element is a directory -> if true: -> perform copy of directory entries + if os.path.isdir(path_to_folder_old_reference + element): + # reset all configuration files to files of old parameter study + if element == 'config_files': + if os.path.isdir(path_to_folder_old_reference + element + '/preExecution'): + list_of_cfg_folders = os.listdir(path_to_folder_old_reference + element + '/preExecution') + for sub_folder in list_of_cfg_folders: + list_of_cfg_files = os.listdir(path_to_folder_old_reference + element + '/preExecution/' + + sub_folder) + for cfg_file in list_of_cfg_files: + shutil.copyfile(path_to_folder_old_reference + element + '/preExecution/' + sub_folder + + '/' + cfg_file, temporary_working_directory + '/' + cfg_file) + + print(cfg_file + ' has been successfully restored from the old parameter study folder!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': ' + cfg_file + + ' has been successfully restored from the old parameter ' + 'study folder!') + + # set path of temporary working directory of current workflow execution to cfg-file + if not cfg_file == 'liftingLine_conf.xml': + frame_info = getframeinfo(currentframe()) + path = temporary_working_directory + '/' + cfg_file + root_of_cfg_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + cfg_file[:-4], function_name, + frame_info.lineno, log_file_list, + current_workflow_name) + + root_of_cfg_tree.find( + './control_settings/aircraft_exchange_file_directory/value').text = \ + temporary_working_directory + '/' + aircraft_project[:-4] + '/' + xml_tree.write(path, encoding='utf-8') + + else: + abort_parameter_study_flag = True + + # reset engine files to files of old parameter study + if element == 'engine_data': + shutil.copytree(path_to_folder_old_reference + element, + temporary_working_directory + '/' + aircraft_project[:-4] + '/engine_data') + + else: + abort_parameter_study_flag = True + + # reset all lean sheet design files to files of old parameter study + if element == 'results': + list_of_results = os.listdir(path_to_folder_old_reference + element) + for result in list_of_results: + if os.path.isdir(path_to_folder_old_reference + element + '/' + result): + shutil.copytree(path_to_folder_old_reference + element + '/' + result, + temporary_working_directory + '/' + aircraft_project[:-4] + + '/cleanSheetDesign/' + result) + else: + shutil.copyfile(path_to_folder_old_reference + element + '/' + result, + temporary_working_directory + '/' + aircraft_project[:-4] + + '/cleanSheetDesign/' + result) + + # else condition: current element is a file -> copy file to temporary working directory + else: + if not element == 'unicado_workflow_conf_start.xml': + # copy project xml-files to temporary working directory + if aircraft_project[:-4] in element: + # check if the current element contains the string 'CPACS' + # -> if true: -> copy cpacs file to project folder + if 'CPACS' in element: + shutil.copyfile(path_to_folder_old_reference + element, + temporary_working_directory + '/' + aircraft_project[:-4] + '/' + element) + + else: + abort_parameter_study_flag = True + + # check if the current element contains the string 'start' + # -> if true: -> copy aircraft exchange file to project folder + if 'start' in element: + # copy start version and rename it to working version of aircraft exchange file + shutil.copyfile(path_to_folder_old_reference + element, + temporary_working_directory + '/' + aircraft_project[:-4] + '/' + + aircraft_project) + + # copy start version of aircraft exchange file + shutil.copyfile(path_to_folder_old_reference + element, + temporary_working_directory + '/' + aircraft_project[:-4] + '/' + + aircraft_project[:-4] + '_start.xml') + else: + abort_parameter_study_flag = True + + if element == 'parameter_study_conf.xml': + frame_info = getframeinfo(currentframe()) + path = path_to_folder_old_reference + element + root_of_parameter_study_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + 'parameter_study', function_name, + frame_info.lineno, log_file_list, + current_workflow_name) + + number_of_input_parameter = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameters").text) + number_of_output_parameter = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameters").text) + path_to_current_study = str(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/PathToCurrentStudy").text) + _, path_to_current_study = path_check(path_to_current_study) + root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/ReproduceOutputFileFromOldStudy").text = str(1) + root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/PathToFolderOldStudy").text \ + = path_to_current_study + + # loop across all input parameter to set paths + i = 1 + while i <= number_of_input_parameter: + path_in_xml_file = str(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(i) + "'" + + "]PathInXmlFile").text) + + # check if the string "ConfigFile" in the given xml-path + # -> if true: -> set path to aircraft exchange file + if "AcftExchangeFile" in path_in_xml_file: + root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + + str(i) + "'" + "]RelDirectory").text \ + = str('../workingDirectoryRCE/' + current_workflow_name + '/' + + aircraft_project[:-4]) + + # check if the string "ConfigFile" in the given xml-path + # -> if true: -> set path to module configuration file + elif "ConfigFile" in path_in_xml_file: + root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + + str(i) + "'" + "]RelDirectory").text \ + = str('../workingDirectoryRCE/' + current_workflow_name) + i += 1 + + # loop across all output parameter to set paths + i = 1 + while i <= number_of_output_parameter: + path_in_xml_file = str(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameter[" + "@ID='" + str(i) + "'" + + "]PathInXmlFile").text) + + # check if the string "ConfigFile" in the given xml-path + # -> if true: -> set path to aircraft exchange file + if "AcftExchangeFile" in path_in_xml_file: + root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameter[" + "@ID='" + + str(i) + "'" + "]RelDirectory").text \ + = str('../workingDirectoryRCE/' + current_workflow_name + '/' + + aircraft_project[:-4]) + + # check if the string "ConfigFile" in the given xml-path + # -> if true: -> set path to module configuration file + elif "ConfigFile" in path_in_xml_file: + root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameter[" + "@ID='" + + str(i) + "'" + "]RelDirectory").text \ + = str('../workingDirectoryRCE/' + current_workflow_name) + i += 1 + + xml_tree.write(path, encoding='utf-8') + + # copy other necessary files from old study to temporary working directory + shutil.copyfile(path_to_folder_old_reference + element, + temporary_working_directory + '/' + element) + + return paths_and_names, abort_parameter_study_flag, log_file_list diff --git a/UNICADOworkflow/src/parameter_study/read_input_parameter_settings.py b/UNICADOworkflow/src/parameter_study/read_input_parameter_settings.py new file mode 100644 index 0000000000000000000000000000000000000000..596db395f6326e7413176afbe21be37d41775f97 --- /dev/null +++ b/UNICADOworkflow/src/parameter_study/read_input_parameter_settings.py @@ -0,0 +1,119 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def read_input_parameter_settings(install_path_directory, path_to_current_study, study_counter, log_file_list, + current_workflow_name='UNICADOworkflow'): + """ Function to read parameters from parameter study configuration file. + + The input string 'install_path_directory' contains the absolute path to the UNICADO install directory. + + The input string 'path_to_current_study' contains the absolute path to the working directory of current parameter study. + + The input integer 'study_counter' contains the current loop number of current study parameter. + + The input list "log_file_list" contains all system prints of function: perform_parameter_study.py. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default sting 'UNICADOworkflow' is used. + + The output list of lists "input_parameter_settings" contains ato following values: + * [0][0] string: 'parameter_name', [0][1] string: 'name of the current study input parameter' + * [1][0] string: 'input_directory_name', [1][1] string: 'name of the input directory of current study parameter' + * [2][0] string: 'input_file_name' [2][1] string: 'name of the input file of the current study parameter' + * [3][0] string: 'path_in_xml_file' [3][1] string: 'path to the study parameter in the input xml-file' + * [4][0] string: 'step_type' [4][1] string: 'mode for step value handling' + * [5][0] string: 'read_values_from_text_file', [5][1] int: 'switch to read iteration values from an external data file' + * [6][0] string: 'step_size', [8][1] float: 'value of step size of current study parameter' + * [7][0] string: 'number_of_steps_up', [9][1] int: 'value of maximum iteration steps upwards are to be performed' + * [8][0] string: 'number_of_steps_down', [10][1] int: 'value of maximum iteration steps downwards are to be performed' + * [9][0] string: 'study_counter' [11][1] int: 'number of iteration loop of current input parameter' + + The output list "log_file_list" contains all system prints of functions: perform_parameter_study.py and read_parameter_study_settings.py. + + :param: install_path_directory: input string + :param: path_to_current_study: input string + :param: study_counter: input integer + :param: log_file_list: input list + :param: current_workflow_name: input string + :return: input_parameter_settings: output list of lists, log_file_list: output list + """ + + ''' imports for python ''' + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + + ''' initialize local parameter ''' + function_name = getframeinfo(currentframe()).function + parameter_file = open(path_to_current_study + '/temp/number_of_current_parameter.dat', 'r') + number_of_current_parameter = int(parameter_file.read()) + parameter_file.close() + + ''' open and read parameter from parameter_study_conf.xml configuration file to element tree ''' + frame_info = getframeinfo(currentframe()) + path_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + path = path_of_working_directory_rce + current_workflow_name + '/parameter_study_conf.xml' + root_of_parameter_study_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'parameter_study', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + ''' read configuration settings of current study input parameter from root_of_parameter_study_tree ''' + parameter_name = root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(number_of_current_parameter) + "'" + + "]/ParameterName").text + input_directory_name = root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(number_of_current_parameter) + "'" + + "]/RelDirectory").text + input_file_name = root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(number_of_current_parameter) + "'" + + "]/FileName").text + path_in_xml_file = root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(number_of_current_parameter) + "'" + + "]/PathInXmlFile").text + step_type = root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(number_of_current_parameter) + "'" + + "]/ParametricStudy/step_type").text.lower() + read_values_from_text_file = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(number_of_current_parameter) + "'" + + "]/ParametricStudy/input_selector").text.lower() == 'mode_1') + step_size = float(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(number_of_current_parameter) + "'" + + "]/ParametricStudy/input_selector_specific_settings/mode_0/StepSize").text) + number_of_steps_up = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(number_of_current_parameter) + "'" + + "]/ParametricStudy/input_selector_specific_settings/mode_0/NumberOfStepsUp").text) + number_of_steps_down = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(number_of_current_parameter) + "'" + + "]/ParametricStudy/input_selector_specific_settings/mode_0/NumberOfStepsDown").text) + + input_parameter_settings = [['parameter_name', parameter_name], + ['input_directory_name', input_directory_name], + ['input_file_name', input_file_name], + ['path_in_xml_file', path_in_xml_file], + ['step_type', step_type], + ['read_values_from_text_file', read_values_from_text_file], + ['step_size', step_size], + ['number_of_steps_up', number_of_steps_up], + ['number_of_steps_down', number_of_steps_down], + ['study_counter', study_counter]] + + log_file_list.append(' --- Iteration number of current study input parameter is: ' + str(study_counter) + ' --- ') + print(' --- Iteration number of current study input parameter is: ' + str(study_counter) + ' --- ') + + return input_parameter_settings, log_file_list \ No newline at end of file diff --git a/UNICADOworkflow/src/parameter_study/read_parameter_study_settings.py b/UNICADOworkflow/src/parameter_study/read_parameter_study_settings.py new file mode 100644 index 0000000000000000000000000000000000000000..2c0d816ba7e03100e7ce86fd93a976ec92b7eb82 --- /dev/null +++ b/UNICADOworkflow/src/parameter_study/read_parameter_study_settings.py @@ -0,0 +1,132 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def read_parameter_study_settings(install_path_directory, log_file_list, current_workflow_name='UNICADOworkflow'): + """ Function to read parameter from parameter study configuration file. + + The input string 'install_path_directory' contains the absolute path to the UNICADO install directory. + + The input list "log_file_list" contains all system prints of function: perform_parameter_study.py. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default sting 'UNICADOworkflow' is used. + + The output list of lists "parameter_study_list" contains the following values: + * [0][0] string: 'exit_if_subprogram_exits', [0][1] integer: 'switch to handle tool error during execution' + * [1][0] string: 'start_every_run_with_ref_file', [1][1] integer: 'switch to to select if each run starts with reference files' + * [2][0] string: 'reset_variables_after_run', [2][1] integer: 'switch to reset variables after finishing the total parameter study' + * [3][0] string: 'write_failed_req_checks_results', [3][1] integer: 'switch to handle output writing after tool execution error' + * [4][0] string: 'parameter_study_methode', [4][1] integer: 'switch to select witch parameter study methode should be used' + * [5][0] string: 'path_to_input_parameter_values_file', [5][1] string: 'absolute system path to the input parameter value file' + * [6][0] string: 'save_results', [6][1] integer: 'switch to activate or deactivate output saving' + * [7][0] string: 'save_only_aircraft_exchange_file', [7][1] integer: 'switch to activate only storing of aircraft exchange files' + * [8][0] string: 'max_folder_size', [8][1] float: 'the maximum allowed size of parameter study directory in GB' + * [9][0] string: 'reproduce_output_file_from_old_study', [9][1] integer: 'switch to handle the use of old output files in current parameter study' + * [10][0] string: 'path_to_current_study', [10][1] string: 'absolute path to the working directory of current parameter study' + * [11][0] string: 'path_to_folder_old_study', [11][1] string: 'absolute path to folder of old study results + * [12][0] string: 'number_of_input_parameter', [12][1] integer: 'number of parameter study inputs to iterate' + * [13][0] string: 'number_of_output_parameter', [13][1] integer: 'number of output parameter to write after each finished run' + + The output list "log_file_list" contains all system prints of functions: perform_parameter_study.py and read_parameter_study_settings.py. + + :param: install_path_directory: input string + :param: log_file_list: input list + :param: current_workflow_name: input string + :return: parameter_study_list: output list of lists; log_file_list: output list + """ + + ''' imports for python ''' + import shutil + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + + ''' initialize local parameter ''' + function_name = getframeinfo(currentframe()).function + frame_info = getframeinfo(currentframe()) + path_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + path = path_of_working_directory_rce + current_workflow_name + '/parameter_study_conf.xml' + + # copy back-up parameter study configuration file to working directory of rce + # to avoid realtime workflow manipulation + root_of_parameter_study_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'parameter_study', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + path_to_current_study = str(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/PathToCurrentStudy").text) + shutil.copyfile(path_to_current_study + '/reference_aircraft/parameter_study_conf.xml', path) + + ''' open and read parameter from parameter_study_conf.xml configuration file to element tree ''' + frame_info = getframeinfo(currentframe()) + root_of_parameter_study_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'parameter_study', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + ''' read program-specific control settings from element tree ''' + exit_if_subprogram_exits = int(root_of_parameter_study_tree.find( + "./ProgramSpecific/ExitIfSubProgramExits").text) + start_every_run_with_ref_file = int(root_of_parameter_study_tree.find( + "./ProgramSpecific/StartEveryRunWithRefFile").text) + reset_variables_after_run = int(root_of_parameter_study_tree.find( + "./ProgramSpecific/ResetVariablesAfterRun").text) + write_failed_req_checks_results = int(root_of_parameter_study_tree.find( + "./ProgramSpecific/WriteFailedReqChecksResults").text) + + ''' read program settings from element tree ''' + parameter_study_methode = int(root_of_parameter_study_tree.find( + "./ProgramSettings/Mode").text) + path_to_input_parameter_values_file = str(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/PathToInputParameterValuesFile").text) + save_results = int(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/SaveResults").text) + save_only_aircraft_exchange_file = int(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/SaveResults").get('OnlyAiXFile')) + max_folder_size = int(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/MaxFolderSize").text) + reproduce_output_file_from_old_study = int(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/ReproduceOutputFileFromOldStudy").text) + path_to_current_study = str(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/PathToCurrentStudy").text) + path_to_folder_old_study = str(root_of_parameter_study_tree.find( + "./ProgramSettings/SensitivityStudySettings/PathToFolderOldStudy").text) + + ''' read parameter settings from element tree ''' + number_of_input_parameter = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameters").text) + number_of_output_parameter = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameters").text) + + ''' save configuration parameter to parameter_study_list ''' + parameter_study_list = [['exit_if_subprogram_exits', exit_if_subprogram_exits], + ['start_every_run_with_ref_file', start_every_run_with_ref_file], + ['reset_variables_after_run', reset_variables_after_run], + ['write_failed_req_checks_results', write_failed_req_checks_results], + ['parameter_study_methode', parameter_study_methode], + ['path_to_input_parameter_values_file', path_to_input_parameter_values_file], + ['save_results', save_results], + ['save_only_aircraft_exchange_file', save_only_aircraft_exchange_file], + ['max_folder_size', max_folder_size], + ['reproduce_output_file_from_old_study', reproduce_output_file_from_old_study], + ['path_to_current_study', path_to_current_study], + ['path_to_folder_old_study', path_to_folder_old_study], + ['number_of_input_parameter', number_of_input_parameter], + ['number_of_output_parameter', number_of_output_parameter]] + + return parameter_study_list, log_file_list diff --git a/UNICADOworkflow/src/parameter_study/reset_parameter_study_files.py b/UNICADOworkflow/src/parameter_study/reset_parameter_study_files.py new file mode 100644 index 0000000000000000000000000000000000000000..9b4816c547405fa1385152583a1e07e242d37b11 --- /dev/null +++ b/UNICADOworkflow/src/parameter_study/reset_parameter_study_files.py @@ -0,0 +1,174 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def reset_parameter_study_files(install_path_directory, path_to_current_study, perform_workflow_execution, + log_file_list, current_workflow_name='UNICADOworkflow'): + """ Function to reset all files after finishing each input parameter study. + + The input string "install_path_directory" contains the absolute path to the UNICADO install directory. + + The input string 'path_to_current_study' contains the absolute path to the working directory of current parameter study. + + The input integer "perform_workflow_execution" contains the status to perform the parameter study or not. + + The input list "log_file_list" contains all system prints of function: perform_parameter_study.py. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default sting 'UNICADOworkflow' is used. + + The output list "log_file_list" contains all system prints of function: set_configuration_parameter and reset_parameter_study_files.py. + + :param: install_path_directory: input string + :param: path_to_current_study: input integer + :param: perform_workflow_execution: input integer + :param: log_file_list: input list + :param: current_workflow_name: input string + :return: log_file_list: output list + """ + + ''' imports of python ''' + import os + import shutil + from datetime import datetime + + ''' initialize local parameter ''' + path_to_workflow_dir = install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/' + i = 0 + # find position of project and aircraft name in given path string + index = path_to_current_study.rfind('_parameter_study') + + index_cut = path_to_current_study[:index].rfind('_') + project_name = path_to_current_study[index_cut+1:index] + + ''' reset workflow configuration file to avoid outer workflow manipulation ''' + if perform_workflow_execution == 1: + if os.path.isfile(path_to_current_study + '/reference_aircraft/unicado_workflow_conf.xml'): + shutil.copyfile(path_to_current_study + '/reference_aircraft/unicado_workflow_conf.xml', + path_to_workflow_dir + 'unicado_workflow_conf.xml') + print('Workflow configuration file successfully reset!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Workflow configuration file successfully reset!') + + else: + if os.path.isfile(path_to_current_study + '/reference_aircraft/unicado_workflow_conf_start.xml'): + shutil.copyfile(path_to_current_study + '/reference_aircraft/unicado_workflow_conf_start.xml', + path_to_workflow_dir + 'unicado_workflow_conf.xml') + print('Workflow configuration file successfully reset!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Workflow configuration file successfully reset!') + + ''' reset range type specific factors xml-file to avoid outer workflow manipulation ''' + if os.path.isfile(path_to_current_study + '/reference_aircraft/range_type_specific_factors.xml'): + shutil.copyfile(path_to_current_study + '/reference_aircraft/range_type_specific_factors.xml', + path_to_workflow_dir + 'range_type_specific_factors.xml') + print('Range type specific factors xml-file successfully reset!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Range type specific factors xml-file successfully reset!') + + ''' reset aircraft exchange file to avoid outer workflow manipulation ''' + if os.path.isfile(path_to_current_study + '/reference_aircraft/' + project_name + '_start.xml'): + shutil.copyfile(path_to_current_study + '/reference_aircraft/' + project_name + '_start.xml', + path_to_workflow_dir + project_name + '/' + project_name + '.xml') + print('Aircraft exchange file successfully reset!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Aircraft exchange file successfully reset!') + + ''' reset CPACS file to avoid outer workflow manipulation ''' + if os.path.isfile(path_to_current_study + '/reference_aircraft/' + project_name + '_CPACS.xml'): + shutil.copyfile(path_to_current_study + '/reference_aircraft/' + project_name + '_CPACS.xml', + path_to_workflow_dir + project_name + '/' + project_name + '_CPACS.xml') + print('CPACS file successfully reset!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'CPACS file successfully reset!') + + ''' reset engine data if exist to avoid outer workflow manipulation ''' + if os.path.isdir(path_to_current_study + '/reference_aircraft/engine_data/'): + if os.path.isdir(path_to_workflow_dir + project_name + '/engine_data/'): + shutil.rmtree(path_to_workflow_dir + project_name + '/engine_data/') + shutil.copytree(path_to_current_study + '/reference_aircraft/engine_data/', + path_to_workflow_dir + project_name + '/engine_data/') + print('Engine data successfully reset!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Engine data successfully reset!') + + ''' reset aero data if exist to avoid outer workflow manipulation ''' + if os.path.isdir(path_to_current_study + '/reference_aircraft/aero_data/'): + if os.path.isdir(path_to_workflow_dir + project_name + '/aero_data/'): + shutil.rmtree(path_to_workflow_dir + project_name + '/aero_data/') + shutil.copytree(path_to_current_study + '/reference_aircraft/aero_data/', + path_to_workflow_dir + project_name + '/aero_data/') + print('Aero data successfully reset!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Aero data successfully reset!') + + ''' reset geometry data if exist to avoid outer workflow manipulation ''' + if os.path.isdir(path_to_current_study + '/reference_aircraft/geometry_data/'): + if os.path.isdir(path_to_workflow_dir + project_name + '/geometry_data/'): + shutil.rmtree(path_to_workflow_dir + project_name + '/geometry_data/') + shutil.copytree(path_to_current_study + '/reference_aircraft/geometry_data/', + path_to_workflow_dir + project_name + '/geometry_data/') + print('Geometry data successfully reset!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Geometry data successfully reset!') + + ''' reset mission data if exist to avoid outer workflow manipulation ''' + if os.path.isdir(path_to_current_study + '/reference_aircraft/mission_data/'): + if os.path.isdir(path_to_workflow_dir + project_name + '/mission_data/'): + shutil.rmtree(path_to_workflow_dir + project_name + '/mission_data/') + shutil.copytree(path_to_current_study + '/reference_aircraft/mission_data/', + path_to_workflow_dir + project_name + '/mission_data/') + print('Mission data successfully reset!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Mission data successfully reset!') + + ''' reset all module configuration files to avoid outer workflow manipulation ''' + if os.path.isdir(path_to_current_study + '/reference_aircraft/config_files/'): + list_of_working_directory_content = os.listdir(install_path_directory) + path_to_config = path_to_current_study + '/reference_aircraft/config_files/' + list_of_directory_content = os.listdir(path_to_config) + for element in list_of_directory_content: + if os.path.isdir(path_to_config + element): + list_of_sub_folder_content = os.listdir(path_to_config + element) + for sub_element in list_of_sub_folder_content: + # extract the tool name from current sub_element string -> toolName_conf.xml[:-9] returns toolName + tool_name_list = os.listdir(path_to_config + element + '/' + sub_element) + for config_file in tool_name_list: + tool_name = config_file[:-9] + for content in list_of_working_directory_content: + if content == tool_name: + if os.path.isdir(install_path_directory + content): + if content == 'aerodynamic_assessment': + if os.path.isfile(path_to_config + element + '/' + sub_element + + '/liftingLine_conf.xml'): + shutil.copyfile(path_to_config + element + '/' + sub_element + + '/liftingLine_conf.xml', + path_to_workflow_dir + 'liftingLine_conf.xml') + print('Reset of liftingLine configuration file successfully done!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Reset of liftingLine configuration file ' + 'successfully done!') + shutil.copyfile(path_to_config + element + '/' + sub_element + '/' + config_file, + path_to_workflow_dir + config_file) + print('Reset of ' + tool_name + ' configuration file successfully done!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Reset of ' + tool_name + ' configuration file ' + 'successfully done!') + + return log_file_list diff --git a/UNICADOworkflow/src/parameter_study/set_input_parameter_settings.py b/UNICADOworkflow/src/parameter_study/set_input_parameter_settings.py new file mode 100644 index 0000000000000000000000000000000000000000..353c6d2ea6e72bb91067d5e62a9b5f971dbbcac1 --- /dev/null +++ b/UNICADOworkflow/src/parameter_study/set_input_parameter_settings.py @@ -0,0 +1,149 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def set_input_parameter_settings(install_path_directory, path_to_current_study, input_parameter_settings, + xml_path_status, log_file_list, current_workflow_name='UNICADOworkflow'): + """ Function to set study parameter to necessary xml-file. + + The input string 'install_path_directory' contains the absolute path to the UNICADO install directory. + + The input string 'path_to_current_study' contains the absolute path to the working directory of current parameter study. + + The input list of lists "input_parameter_settings" contains ato following values: + * [0][0] string: 'parameter_name', [0][1] string: 'name of the current study input parameter' + * [1][0] string: 'input_directory_name', [1][1] string: 'name of the input directory of current study parameter' + * [2][0] string: 'input_file_name' [2][1] string: 'name of the input file of the current study parameter' + * [3][0] string: 'path_in_xml_file' [3][1] string: 'path to the study parameter in the input xml-file' + * [4][0] string: 'step_type' [4][1] string: 'mode for step value handling' + * [5][0] string: 'read_values_from_text_file', [5][1] int: 'switch to read iteration values from an external data file' + * [6][0] string: 'step_size', [8][1] float: 'value of step size of current study parameter' + * [7][0] string: 'number_of_steps_up', [9][1] int: 'value of maximum iteration steps upwards are to be performed' + * [8][0] string: 'number_of_steps_down', [10][1] int: 'value of maximum iteration steps downwards are to be performed' + * [9][0] string: 'study_counter' [11][1] int: 'number of iteration loop of current input parameter' + + The input bool 'xml_path_status' contains the status "True" of current xml-path. + + The input list "log_file_list" contains all system prints of function: perform_parameter_study.py. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output bool 'xml_path_status' contains the current status "True" or "False" of current xml-path. + + The output float 'new_value_of_input' contains the new parameter iteration value of current loop. + + The output list "log_file_list" contains all system prints of functions: perform_parameter_study.py and read_parameter_study_settings.py. + + :param: install_path_directory: input string + :param: path_to_current_study: input string + :param: input_parameter_settings: input list of lists + :param: xml_path_status: input bool + :param: log_file_list: input list + :param: current_workflow_name: input string + :return: xml_path_status: output bool, new_value_of_input: output float, log_file_list: output list + """ + + ''' imports for python ''' + from inspect import currentframe, getframeinfo + from datetime import datetime + from sub_function.path_check import path_check + from sub_function.read_xml_file import read_xml_file + from sub_function.xml_path_check import xml_path_check + from parameter_study.estimate_input_value_from_configuration_file \ + import estimate_input_value_from_configuration_file + + ''' read data for script execution ''' + input_file_name = ([item for item in input_parameter_settings if 'input_file_name' in item])[-1][-1] + path_in_xml_file = ([item for item in input_parameter_settings if 'path_in_xml_file' in item])[-1][-1] + input_directory_name = ([item for item in input_parameter_settings if 'input_directory_name' in item])[-1][-1] + parameter_name = ([item for item in input_parameter_settings if 'parameter_name' in item])[-1][-1] + + ''' initialize local parameter ''' + new_value_of_input = float(0.0) + number_of_runs_to_perform = 1 + function_name = getframeinfo(currentframe()).function + path_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + + # call function to check if the given path in relative style otherwise correct the path + corrected_path_is_absolute, corrected_path = path_check(input_directory_name) + + # call function to check path in xml-file and correct to unix path + corrected_xml_path = xml_path_check(path_in_xml_file) + + # set absolute path of study xml-file + #if corrected_path_is_absolute: + # path_to_study_xml_file = corrected_path + input_file_name + #else: + # path_to_study_xml_file = path_of_working_directory_rce + current_workflow_name + input_file_name + if "projects" in corrected_path: + corrected_path = corrected_path[corrected_path.rfind('/', 0, -1):] + else: + corrected_path = '/' + path_to_study_xml_file = path_of_working_directory_rce + current_workflow_name + corrected_path + input_file_name + print("Input variable path: " + path_to_study_xml_file) + + # read study input xml-file as element tree + frame_info = getframeinfo(currentframe()) + root_of_study_xml_file, xml_tree = read_xml_file(path_to_study_xml_file, path_of_working_directory_rce, + input_file_name, function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + ''' set iteration value to study parameter xml-file ''' + # check if the corrected xml-path is inside the current study element tree + # -> if true: -> set study parameter in xml-file + if not root_of_study_xml_file.find(corrected_xml_path) is None: + # call function to set input parameter from parameter study configuration file + new_value_of_input, xml_path_status, number_of_runs_to_perform, log_file_list = \ + estimate_input_value_from_configuration_file(root_of_study_xml_file, input_parameter_settings, + path_to_current_study, corrected_xml_path, log_file_list) + + # check if the estimation of new input value failed + # -> if true: -> raise an error and skipp current input parameter + if not xml_path_status: + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: No steps up and no steps down are set in the parameter study ' + 'configuration file! \n ' + ' Current study input parameter will be skipped!') + print('Error: No steps up and no steps down for parameter "' + parameter_name + + '" are set in the parameter study configuration file! \n' + ' Current study input parameter will be skipped!') + + # else condition: new value of current input parameter could be estimated + # -> write value to current study xml-file + else: + print('New value of current parameter study input is : ' + str(new_value_of_input)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'New value of current parameter study input is: ' + str(new_value_of_input)) + xml_tree.find(corrected_xml_path).text = str(new_value_of_input) + xml_tree.write(path_to_study_xml_file, encoding='utf-8') + + # else condition: corrected xml-path is not inside the current study element tree + # -> raise an error and skip current parameter study + else: + xml_path_status = False + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: The given xml-path in the parameter study configuration file of current input ' + 'parameter is not existing! \n ' + ' Current study input parameter will be skipped!') + print('Error: The given xml-path in the parameter study configuration file of current input parameter ' + 'is not existing! \n' + ' Current study input parameter will be skipped!') + + return xml_path_status, new_value_of_input, number_of_runs_to_perform, log_file_list diff --git a/UNICADOworkflow/src/parameter_study/set_parameter_for_resume_parameter_study.py b/UNICADOworkflow/src/parameter_study/set_parameter_for_resume_parameter_study.py new file mode 100644 index 0000000000000000000000000000000000000000..96793ee9516c33ad370ea4b71d9cb754c2707f5f --- /dev/null +++ b/UNICADOworkflow/src/parameter_study/set_parameter_for_resume_parameter_study.py @@ -0,0 +1,168 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def set_parameter_for_resume_parameter_study(paths_and_names, path_to_folder_old_study, log_file_list): + """ Function to check which parameter to analyze next and create a file to perform the parameter study. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input string "path_to_folder_old_study" contains the absolute path to the results of old parameter study to resume. + + The input list "log_file_list" contains all system prints of function: set_configuration_parameter.py. + + The output bool "abort_parameter_study_flag" contains the status to abort the parameter study or not. + + The output integer "number_of_total_steps" contains the number of parameter study steps still to be performed. + + The output list "log_file_list" contains all system prints of functions: set_configuration_parameter.py and initialize_parameter_study.py. + + :param: paths_and_names: list of lists + :param: path_to_folder_old_study: input string + :param: log_file_list: input list + :return: abort_parameter_study_flag: output bool, number_of_total_steps: output integer, log_file_list: output list + """ + + ''' imports of python ''' + import os + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.path_check import path_check + from sub_function.read_xml_file import read_xml_file + + ''' read data for script execution ''' + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + ''' initialize local parameter ''' + index_list = [] + output_list = [] + count_of_line = 0 + number_of_total_steps = 0 + number_of_parameter_to_run = 1 + abort_parameter_study_flag = False + function_name = getframeinfo(currentframe()).function + + ''' try to open output csv-file from old study ''' + # check path of old parameter study + _, path_to_folder_old_study = path_check(path_to_folder_old_study) + + # check if the output csv-file of old parameter study exist + if os.path.isfile(path_to_folder_old_study + '/output_csv/parameter_study_output.csv'): + # try to open the output csv-file from old parameter study + try: + output_csv_file = open(path_to_folder_old_study + '/output_csv/parameter_study_output.csv', 'r') + # loop to count the header strings of parameter to estimate last parameter of old parameter study + for line in output_csv_file: + count_of_line += 1 + output_list.append(line) + if '# ID' in line: + index_list.append(count_of_line) + output_csv_file.close() + + # check if not only the reference case exists in the old parameter study results -> if true: + # -> perform parameter study from the last parameter + if len(index_list) > 1: + # -2 eliminates the reference case and the last parameter of study from counting list + number_of_parameter_to_run = len(index_list) - 2 + + # check if the temp directory exist in the directory of old study + # -> if true: -> delete the folder and create a new one + if os.path.isdir(path_to_folder_old_study + 'temp'): + shutil.rmtree(path_to_folder_old_study + 'temp') + os.mkdir(path_to_folder_old_study + 'temp') + + parameter_file = open(path_to_folder_old_study + '/temp/number_of_current_parameter.dat', 'a') + parameter_file.write(str(number_of_parameter_to_run)) + parameter_file.close() + + # remove old entries of last parameter from old output csv-file + if os.path.isfile(path_to_folder_old_study + '/output_csv/parameter_study_output.csv'): + os.remove(path_to_folder_old_study + '/output_csv/parameter_study_output.csv') + + output_csv_file = open(path_to_folder_old_study + '/output_csv/parameter_study_output.csv', 'a') + i = 0 + for line in output_list: + if i < index_list[-1]-1: + output_csv_file.write(line) + i += 1 + else: + break + output_csv_file.close() + + ''' open and read parameter from parameter_study_conf.xml configuration file to element tree ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/parameter_study_conf.xml' + root_of_parameter_study_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + 'parameter_study', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + number_of_input_parameter = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameters").text) + + # loop across the number of input parameters to estimate total number of necessary workflow loops + i = number_of_parameter_to_run + 1 + while i <= number_of_input_parameter: + number_of_steps_up = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(i) + "'" + + "]ParametricStudy/input_selector_specific_settings/mode_0/NumberOfStepsUp").text) + number_of_steps_down = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/InputParameter[" + "@ID='" + str(i) + "'" + + "]ParametricStudy/input_selector_specific_settings/mode_0/NumberOfStepsDown").text) + number_of_total_steps = number_of_total_steps + number_of_steps_up + number_of_steps_down + i += 1 + + # Add + 1 to number of total steps for reference calculation + number_of_total_steps += 1 + + # exception handling if the old output csv-file could not be opened + except OSError: + abort_parameter_study_flag = True + print('Error: The existing output.csv file from old parameter study could not be opened! \n' + 'After finishing the reference aircraft estimation the parameter study will be aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Error: The existing output.csv file from old parameter study could not be opened!' + '\n' + 'After finishing the reference aircraft estimation the parameter study will be' + ' aborted!') + + # else condition: output csv-file of old parameter study does not exist -> set abort parameter study flag to 'True' + else: + abort_parameter_study_flag = True + + print('number_of_total_steps is: ' + str(number_of_total_steps)) + + return abort_parameter_study_flag, number_of_total_steps, log_file_list diff --git a/UNICADOworkflow/src/parameter_study/write_parameter_study_csv_output.py b/UNICADOworkflow/src/parameter_study/write_parameter_study_csv_output.py new file mode 100644 index 0000000000000000000000000000000000000000..e6cc5fc2facb059b62e117af2b8dfe757e10f153 --- /dev/null +++ b/UNICADOworkflow/src/parameter_study/write_parameter_study_csv_output.py @@ -0,0 +1,291 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def write_parameter_study_csv_output(path_of_working_directory_rce, path_of_working_directory, copy_target_path, + parameter_for_design_case, log_file_list, current_workflow_name='UNICADOworkflow'): + """ Function to write the parameter study outputs to the output csv-file. + + The input string "path_of_working_directory_rce" contains the absolute path to the rce working directory. + + The input string "path_of_working_directory" contains the absolute system path of unicado working directory. + + The input string "copy_target_path" contains the absolute path to the current parameter study output directory. + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + The input list "log_file_list" contains all system prints of function: post_operations_of_workflow.py. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + :param: path_of_working_directory_rce: input string + :param: path_of_working_directory: input string + :param: copy_target_path: input string + :param: parameter_for_design_case: input list of lists + :param: log_file_list: input list + :param: current_workflow_name: input string + """ + + ''' imports for python ''' + import os + from inspect import currentframe, getframeinfo + from datetime import datetime + from sub_function.path_check import path_check + from sub_function.read_xml_file import read_xml_file + from sub_function.xml_path_check import xml_path_check + + ''' read data for script execution ''' + study_counter = int(([item for item in parameter_for_design_case if 'study_counter' in item])[-1][-1]) + parameter_name = str(([item for item in parameter_for_design_case if 'parameter_name' in item])[-1][-1]) + new_value_of_input = str(([item for item in parameter_for_design_case if 'new_value_of_input' in item])[-1][-1]) + global_loop_counter = int(([item for item in parameter_for_design_case if 'global_loop_counter' in item])[-1][-1]) + + ''' initialize local parameter ''' + lines = [] + value_list = [] + parameter_list = [] + header_string = str() + status_csv_output = False + convergence_error_flag = os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/temp/convergenceError.dat') + function_name = getframeinfo(currentframe()).function + + ''' read output parameter from parameter study configuration file as elementTree ''' + if global_loop_counter == 1: + index = copy_target_path.find('reference_aircraft') + else: + index = copy_target_path.find(parameter_name) + path = copy_target_path[:index] + 'reference_aircraft/parameter_study_conf.xml' + + # call function to read the parameter study configuration file + frame_info = getframeinfo(currentframe()) + root_of_parameter_study_tree, _ = read_xml_file(path, path_of_working_directory_rce, 'parameter_study', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + number_of_outputs_to_write = int(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameters").text) + + ''' write header to output csv-file of current parameter ''' + if global_loop_counter == 1 or study_counter == 1: + if global_loop_counter == 1: + header_string = '# ID;' + 'reference aircraft;' + print('Header string of reference case successfully writen to parameter study output csv-file!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Header string of reference case successfully writen to parameter study ' + 'output csv-file!') + + if study_counter == 1: + header_string = '# ID;' + parameter_name + ';' + print('Header string of current input parameter successfully writen to parameter study output csv-file.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Working copy of gnuplot has been successfully created!') + + # list comprehension to generate header string for output csv-file + parameter_list.append(header_string + ';'.join([str(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameter[" + "@ID='" + str(i) + "'" + "]/ParameterName").text) + for i in range(1, number_of_outputs_to_write + 1)])) + + ''' write reference case of current input parameter to output csv-file ''' + if os.path.isfile(copy_target_path[:index] + 'temp/reference_value_of_current_input.dat') \ + and not os.path.isfile(copy_target_path[:index] + 'temp/output_status.dat'): + # read current input parameter reference value from temporary file + with open(copy_target_path[:index] + 'temp/reference_value_of_current_input.dat', 'r') as file: + first_line = file.readlines()[0] + if first_line.isnumeric(): + first_line = float(first_line) + file.close() + # check if the current input parameter value is lower than the current input parameter reference value + # -> if true: -> generate status flag file and add reference case to current output csv-file string + if new_value_of_input.isnumeric() and float(new_value_of_input) < float(first_line): + output_status_dat = open(copy_target_path[:index] + 'temp/output_status.dat', 'a+') + output_status_dat.close() + # read reference value string from output csv-file + with open(copy_target_path[:index] + 'output_csv/parameter_study_output.csv', 'r') as file: + reference_line = file.readlines()[1] + file.close() + # id_ref_x are string positions of the first to ";" + # -> the positions are necessary to manipulate the reference string into the correct csv-output string + id_ref_1 = reference_line.find(';') + id_ref_2 = reference_line[id_ref_1+1:].find(';') + reference_string = 'refCase;' + str(first_line) + reference_line[id_ref_1+id_ref_2+1:] + parameter_list.append(reference_string.rstrip()) + + ''' write output values of current run to output csv-file ''' + # read all output parameter directories from elementTree + output_parameter_directory_list = [] + for i in range(1, number_of_outputs_to_write + 1): + _, relative_path_of_output_parameter = path_check( + str(root_of_parameter_study_tree.find( + f"./ProgramSettings/ParameterSettings/OutputParameter[@ID='{i}']/RelDirectory" + ).text) + ) + + if "projects" in relative_path_of_output_parameter: + # Find the starting position of "projects" + projects_index = relative_path_of_output_parameter.find("projects") + len("projects") + + # Skip the next directory (e.g., /CSMR/) + next_slash_index = relative_path_of_output_parameter.find("/", projects_index + 1) + + # Extract the path starting after the next directory + relative_path_of_output_parameter = relative_path_of_output_parameter[next_slash_index + 1:] + else: + relative_path_of_output_parameter = '/' + + # Normalize paths to ensure proper structure + if not path_of_working_directory_rce.endswith('/'): + path_of_working_directory_rce += '/' + if current_workflow_name.startswith('/'): + current_workflow_name = current_workflow_name[1:] + if not current_workflow_name.endswith('/'): + current_workflow_name += '/' + if relative_path_of_output_parameter.startswith('/'): + relative_path_of_output_parameter = relative_path_of_output_parameter[1:] + + # Combine paths with correct separators + full_output_path = ( + path_of_working_directory_rce + current_workflow_name + relative_path_of_output_parameter + ) + output_parameter_directory_list.append(full_output_path) + + # read all output parameter file names from elementTree + file_name_list = [str(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameter[" + "@ID='" + str(i) + "'" + "]/FileName").text) + for i in range(1, number_of_outputs_to_write + 1)] + + # read all output parameter xml-file paths from elementTree + xml_path_list = [str(root_of_parameter_study_tree.find( + "./ProgramSettings/ParameterSettings/OutputParameter[" + "@ID='" + str(i) + "'" + "]/PathInXmlFile").text) + for i in range(1, number_of_outputs_to_write + 1)] + + # generate the first two entries of output string + if global_loop_counter == 1: + value_string = 'run_' + str(global_loop_counter) + ';' + 'refCase;' + else: + value_string = 'run_' + str(study_counter) + ';' + str(new_value_of_input) + ';' + + # file_name_list[0][:-4] cuts the postfix ".xml" from given string + frame_info = getframeinfo(currentframe()) + root_of_output_parameter_tree, _ = read_xml_file(output_parameter_directory_list[0] + file_name_list[0], + path_of_working_directory_rce, file_name_list[0][:-4], + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # add first output parameter value to list + current_value = root_of_output_parameter_tree.find(xml_path_check(xml_path_list[0])) + if current_value is None: + value_list.append('N/A') + else: + value_list.append(str(current_value.text)) + + # call function to read the output parameter xml-file + for i in range(1, number_of_outputs_to_write): + # check if the current entry of file name and output parameter directory are not equal to the last one + # -> if true: -> read new elementTree + if not ((output_parameter_directory_list[i] == output_parameter_directory_list[i-1]) + or file_name_list[i] == file_name_list[i-1]): + frame_info = getframeinfo(currentframe()) + root_of_output_parameter_tree, _ = read_xml_file(output_parameter_directory_list[i] + file_name_list[i], + path_of_working_directory_rce, file_name_list[i][:-4], + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + xml_string = xml_path_check(xml_path_list[i]) + # check if the current xml path includes an '@' -> if true: -> generate dynamic python xml path + if '@' in xml_string: + idx = xml_string.find('@') + idx_2 = xml_string[idx:].find('/') + python_xml_string = xml_string[:idx] + '[' + "@ID='" + xml_string[idx + 1:idx + 1 + idx_2 - 1] + "'" + "]" \ + + xml_string[idx + idx_2:] + + # else condition: the current xml path includes no '@' -> use current string from list as python xml path + else: + python_xml_string = xml_string + + # check if convergence of current loop is reached -> if true: -> add current output value to list + if not convergence_error_flag \ + and not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/pre_sizing_error.dat') \ + and not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/temp/design_sizing_error.dat'): + current_value = root_of_output_parameter_tree.find(python_xml_string) + if current_value is None: + value_list.append('N/A') + else: + value_list.append(str(current_value.text)) + # else condition: convergence of current loop is not reached -> add N/A to value list + else: + value_list.append('N/A') + + # exception handling if the current study counter is equal to zero + # -> if true: read number of last run from csv-file and add +1 for current loop + if study_counter == 0 and global_loop_counter > 1: + # read all lines from output csv-file to extract last two lines + with open(copy_target_path[:index] + 'output_csv/parameter_study_output.csv', 'r') as file: + for line in file: + lines.append(line) + file.close() + # id_ref_x are string positions of "_" and ";" in the last line of csv-file + # -> the positions are necessary to manipulate the reference string into the correct csv-output string + idx_3 = lines[-1].find('_') + idx_4 = lines[-1].find(';') + # check if the last line of output csv-file starts with 'run_' -> if true: -> extract number of previous run + if lines[-1][:idx_3+1] == 'run_': + value_string = 'run_' + str(int(lines[-1][idx_3+1:idx_4]) + 1) + ';' + str(new_value_of_input) + ';' + # check if the last line of output csv-file starts with 'refCase' + # -> if true: -> extract number of previous run from pre last line of output csv-file + elif lines[-1][:idx_4] == 'refCase': + value_string = 'run_' + str(int(lines[-2][idx_3+1:idx_4]) + 1) + ';' + str(new_value_of_input) + ';' + # check if the last line of output csv-file is empty + # -> if true: -> set current run counter to study counter + 1 + elif lines[-1] == '': + value_string = 'run_' + str(study_counter + 1) + ';' + str(new_value_of_input) + ';' + + # generate output string of current run + parameter_list.append(value_string + ';'.join(value_list)) + + # add blank line after the last loop of each input parameter + if global_loop_counter == 1 or study_counter == 0: + parameter_list.append('') + + output_file = open(copy_target_path[:index] + 'output_csv/parameter_study_output.csv', 'a') + for row in parameter_list: + output_file.write(row + '\n') + output_file.close() + + print('Output parameter value string of current run successfully writen to parameter study output csv-file!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Output parameter value string of current run successfully writen to parameter study ' + 'output csv-file!') + + return status_csv_output, log_file_list diff --git a/UNICADOworkflow/src/post_operations/check_tlars_and_gradients.py b/UNICADOworkflow/src/post_operations/check_tlars_and_gradients.py new file mode 100644 index 0000000000000000000000000000000000000000..cb10847cefe51cf31ee26418196120f2188ca12e --- /dev/null +++ b/UNICADOworkflow/src/post_operations/check_tlars_and_gradients.py @@ -0,0 +1,407 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def check_tlars_and_gradients(paths_and_names, parameter_for_design_case): + """ check_tlars_and_gradients checks whether the tlars and gradients have been observed. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'design_mode', [0][1] int: 'value to check which design mode is selected' + * [1][0] string: 'automatic_trim', [1][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [2][0] string: 'convergence_criteria', [2][1] float: 'value of convergence criteria of ome and mtom iteration' + * [3][0] string: 'number_of_max_iteration', [3][1] int: 'value to set maximum number of design sizing iteration steps' + * [4][0] string: 'bridge_constraint_analyzer', [4][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [5][0] string: 'damp_mtom_iteration' [5][1] bool: 'switch to activate damping of mtom iteration loop' + * [6][0] String: 'damp_ome_iteration' [6][1] bool: 'switch to activate damping of ome iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + * [10][0] string: 'parameter_name', [10][1] string: 'name of the current input parameter if parameter study will be performed' + * [11][0] string: 'global_loop_counter', [11][1] int: 'global loop counter for parameter study mode' + * [12][0] string: 'study_counter', [12][1] int: 'study counter of current input parameter if parameter study will be performed' + * [13][0] string: 'new_value_of_input', [13][1] float: 'value of current parameter study input parameter' + + :param: paths_and_names: input list of lists + :param: parameter_for_design_case: input list of lists + :return: none + """ + + ''' imports for python ''' + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.get_mission_energy_specific_segment import get_mission_energy_specific_segment + from sub_function.write_to_log_file import write_to_log_file + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + function_name = getframeinfo(currentframe()).function + + ''' create list for log-file string ''' + log_file_list = ['', + '***************************************** check tlars and climb gradients ' + '*****************************************'] + + ''' open and read aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + aircraft_exchange_file + root_of_aircraft_exchange_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + ''' check TLARs for fulfilled ''' + # TOFL + tofl_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/design_takeoff_distance/' + 'checked/value') + if tofl_checked is not None: + tofl_checked = tofl_checked.text.lower() in ['true', 'True', '1', 't'] + else: + tofl_checked = False + tofl_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/design_takeoff_distance/' + 'maintainable/value') + if tofl_fulfilled is not None: + tofl_fulfilled = tofl_fulfilled.text.lower() in ['true', 'True', '1', 't'] + else: + tofl_fulfilled = False + # LDN + ldn_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/design_landing_field_length/' + 'checked/value') + if ldn_checked is not None: + ldn_checked = ldn_checked.text.lower() in ['true', 'True', '1', 't'] + else: + ldn_checked = False + ldn_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/design_landing_field_length/' + 'maintainable/value') + if ldn_fulfilled is not None: + ldn_fulfilled = ldn_fulfilled.text.lower() in ['true', 'True', '1', 't'] + else: + ldn_fulfilled = False + # v_approach + v_approach_speed_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/design_approach_speed/' + 'checked/value') + if v_approach_speed_checked is not None: + v_approach_speed_checked = v_approach_speed_checked.text.lower() in ['true', 'True', '1', 't'] + else: + v_approach_speed_checked = False + v_approach_speed_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/design_approach_speed/' + 'maintainable/value') + if v_approach_speed_fulfilled is not None: + v_approach_speed_fulfilled = v_approach_speed_fulfilled.text.lower() in ['true', 'True', '1', 't'] + else: + v_approach_speed_fulfilled = False + # intial cruise altitude + h_initial_cruise_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/initial_cruise_altitude/' + 'checked/value') + if h_initial_cruise_checked is not None: + h_initial_cruise_checked = h_initial_cruise_checked.text.lower() in ['true', 'True', '1', 't'] + else: + h_initial_cruise_checked = False + h_initial_cruise_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/initial_cruise_altitude/' + 'maintainable/value') + if h_initial_cruise_fulfilled is not None: + h_initial_cruise_fulfilled = h_initial_cruise_fulfilled.text.lower() in ['true', 'True', '1', 't'] + else: + h_initial_cruise_fulfilled = False + # maximum operating altitude (all engines operating) + h_max_operating_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/maximum_operating_altitude/' + 'checked/value') + if h_max_operating_checked is not None: + h_max_operating_checked = h_max_operating_checked.text.lower() in ['true', 'True', '1', 't'] + else: + h_max_operating_checked = False + h_max_operating_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/maximum_operating_altitude/' + 'maintainable/value') + if h_max_operating_fulfilled is not None: + h_max_operating_fulfilled = h_max_operating_fulfilled.text.lower() in ['true', 'True', '1', 't'] + else: + h_max_operating_fulfilled = False + # maximum operating altitude (one engine inoperative) + h_max_oei_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/maximum_altitude_one_engine_inoperative/' + 'checked/value') + if h_max_oei_checked is not None: + h_max_oei_checked = h_max_oei_checked.text.lower() in ['true', 'True', '1', 't'] + else: + h_max_oei_checked = False + h_max_oei_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/maximum_altitude_one_engine_inoperative/' + 'maintainable/value') + if h_max_oei_fulfilled is not None: + h_max_oei_fulfilled = h_max_oei_fulfilled.text.lower() in ['true', 'True', '1', 't'] + else: + h_max_oei_fulfilled = False + # Initial cruise Mach number + mach_initial_cruise_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/initial_cruise_mach_number/' + 'checked/value') + if mach_initial_cruise_checked is not None: + mach_initial_cruise_checked = mach_initial_cruise_checked.text.lower() in ['true', 'True', '1', 't'] + else: + mach_initial_cruise_checked = False + mach_initial_cruise_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/initial_cruise_mach_number/' + 'maintainable/value') + if mach_initial_cruise_fulfilled is not None: + mach_initial_cruise_fulfilled = mach_initial_cruise_fulfilled.text.lower() in ['true', 'True', '1', 't'] + else: + mach_initial_cruise_fulfilled = False + # TTC + ttc_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/design_time_to_climb/' + 'checked/value') + if ttc_checked is not None: + ttc_checked = ttc_checked.text.lower() in ['true', 'True', '1', 't'] + else: + ttc_checked = False + ttc_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/design_time_to_climb/' + 'maintainable/value') + if ttc_fulfilled is not None: + ttc_fulfilled = ttc_fulfilled.text.lower() in ['true', 'True', '1', 't'] + else: + ttc_fulfilled = False + # Span limit + span_limit_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/span_limit/' + 'checked/value') + if span_limit_checked is not None: + span_limit_checked = span_limit_checked.text.lower() in ['true', 'True', '1', 't'] + else: + span_limit_checked = False + span_limit_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/top_level_aircraft_requirements/span_limit/' + 'maintainable/value') + if span_limit_fulfilled is not None: + span_limit_fulfilled = span_limit_fulfilled.text.lower() in ['true', 'True', '1', 't'] + else: + span_limit_fulfilled = False + + ''' check climb gradients for fulfilled ''' + # second T/O climb segment + climb_gradient_second_to_segment_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/certification/climb_gradient_of_second_takeoff_segment/' + 'checked/value') + if climb_gradient_second_to_segment_checked is not None: + climb_gradient_second_to_segment_checked = climb_gradient_second_to_segment_checked.text.lower() in [ + 'true', 'True', '1', 't'] + else: + climb_gradient_second_to_segment_checked = False + climb_gradient_second_to_segment_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/certification/climb_gradient_of_second_takeoff_segment/' + 'maintainable/value') + if climb_gradient_second_to_segment_fulfilled is not None: + climb_gradient_second_to_segment_fulfilled = climb_gradient_second_to_segment_fulfilled.text.lower() in [ + 'true', 'True', '1', 't'] + else: + climb_gradient_second_to_segment_fulfilled = False + # final T/O climb segment + climb_gradient_final_to_segment_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/certification/climb_gradient_of_final_takeoff_segment/' + 'checked/value') + if climb_gradient_final_to_segment_checked is not None: + climb_gradient_final_to_segment_checked = climb_gradient_final_to_segment_checked.text.lower() in [ + 'true', 'True', '1', 't'] + else: + climb_gradient_final_to_segment_checked = False + climb_gradient_final_to_segment_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/certification/climb_gradient_of_final_takeoff_segment/' + 'maintainable/value') + if climb_gradient_final_to_segment_fulfilled is not None: + climb_gradient_final_to_segment_fulfilled = climb_gradient_final_to_segment_fulfilled.text.lower() in [ + 'true', 'True', '1', 't'] + else: + climb_gradient_final_to_segment_fulfilled = False + # approach segment (one engine inoperative) + climb_gradient_approach_oei_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/certification/climb_gradient_approach_one_engine_inoperative/' + 'checked/value') + if climb_gradient_approach_oei_checked is not None: + climb_gradient_approach_oei_checked = climb_gradient_approach_oei_checked.text.lower() in [ + 'true', 'True', '1', 't'] + else: + climb_gradient_approach_oei_checked = False + climb_gradient_approach_oei_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/certification/climb_gradient_approach_one_engine_inoperative/' + 'maintainable/value') + if climb_gradient_approach_oei_fulfilled is not None: + climb_gradient_approach_oei_fulfilled = climb_gradient_approach_oei_fulfilled.text.lower() in [ + 'true', 'True', '1', 't'] + else: + climb_gradient_approach_oei_fulfilled = False + # approach segment (all engines operating) + climb_gradient_approach_aeo_checked = root_of_aircraft_exchange_tree.find( + './requirement_compliance/certification/climb_gradient_all_engines_operative/' + 'checked/value') + if climb_gradient_approach_aeo_checked is not None: + climb_gradient_approach_aeo_checked = climb_gradient_approach_aeo_checked.text.lower() in [ + 'true', 'True', '1', 't'] + else: + climb_gradient_approach_aeo_checked = False + climb_gradient_approach_aeo_fulfilled = root_of_aircraft_exchange_tree.find( + './requirement_compliance/certification/climb_gradient_all_engines_operative/' + 'maintainable/value') + if climb_gradient_approach_aeo_fulfilled is not None: + climb_gradient_approach_aeo_fulfilled = climb_gradient_approach_aeo_fulfilled.text.lower() in [ + 'true', 'True', '1', 't'] + else: + climb_gradient_approach_aeo_fulfilled = False + + ''' store TLARs to check to table checkTLARs ''' + check_tlars = [['TOFL_Design', int(tofl_checked), int(tofl_fulfilled)], + ['TTC_Design', int(ttc_checked), int(ttc_fulfilled)], + ['h_initialCruise_Design', int(h_initial_cruise_checked), int(h_initial_cruise_fulfilled)], + ['M_initialCruise_Design', int(mach_initial_cruise_checked), int(mach_initial_cruise_fulfilled)], + ['V_ApproachSpeed_Design', int(v_approach_speed_checked), int(v_approach_speed_fulfilled)], + ['LDN_Design', int(ldn_checked), int(ldn_fulfilled)], + ['h_maxOperating', int(h_max_operating_checked), int(h_max_operating_fulfilled)], + ['h_maxOEI', int(h_max_oei_checked), int(h_max_oei_fulfilled)], + ['SpanLimit', int(span_limit_checked), int(span_limit_fulfilled)], + ['climbGradientSecondTOSegment', int(climb_gradient_second_to_segment_checked), + int(climb_gradient_second_to_segment_fulfilled)], + ['climbGradientFinalTOSegment', int(climb_gradient_final_to_segment_checked), + int(climb_gradient_final_to_segment_fulfilled)], + ['climbGradientApproachOEI', int(climb_gradient_approach_oei_checked), + int(climb_gradient_approach_oei_fulfilled)], + ['climbGradientApproachAEO', int(climb_gradient_approach_aeo_checked), + int(climb_gradient_approach_aeo_fulfilled)]] + + ''' check TLARs for fulfilled ''' + one_tlar_checked = 0 + all_tlars_checked = 1 + req_check_failed = 0 + req_err_code = int(600) + + for TLAR in check_tlars: + if TLAR[1]: + one_tlar_checked = 1 + if not (TLAR[2]): + print('Error: Requirement check failed for: ' + TLAR[0]) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: Requirement check failed for: ' + TLAR[0]) + req_check_failed = 1 + # generate error code of requirement check + if TLAR[0] == 'TOFL_Design': + req_err_code += 1 + if TLAR[0] == 'LDN_Design': + req_err_code += 2 + if TLAR[0] == 'V_ApproachSpeed_Design': + req_err_code += 4 + if TLAR[0] == 'TTC_Design': + req_err_code += 8 + + else: + print('Requirement check successful for: ' + TLAR[0]) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Requirement check successful for: ' + TLAR[0]) + else: + all_tlars_checked = 0 + print('Error: Requirement check not possible for: ' + TLAR[0]) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: Requirement check not possible for: ' + TLAR[0]) + + # report of requirement check + if req_check_failed: + print('Warning: TLARs check failed with error code ' + str(req_err_code) + ' due to failed requirement checks.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'WARNING: TLARs check failed with error code ' + str(req_err_code) + + ' due to failed requirement checks.') + + else: + if one_tlar_checked: + print('No tested TLAR was violated.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': No tested TLAR was violated.') + + if all_tlars_checked: + print('All existing TLARs were checked and complied with. Good design!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'All existing TLARs were checked and complied with. Good design!') + + ''' check reserve energy for design mission ''' + reserve_energy_mission_design = get_mission_energy_specific_segment(root_of_aircraft_exchange_tree, + "design_mission", + "loaded_mission_energy/mission_energy") \ + - get_mission_energy_specific_segment(root_of_aircraft_exchange_tree, + "design_mission", "in_flight_energy/trip_energy") \ + - get_mission_energy_specific_segment(root_of_aircraft_exchange_tree, + "design_mission", "taxi_energy/taxi_out_energy") + + if reserve_energy_mission_design < 0: + print('Error: Loaded mission energy on design mission smaller than consumed energy (neg. reserve energy).') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'ERROR: Loaded mission energy on design mission smaller than consumed energy ' + '(neg. reserve energy).') + + ''' check take-off mass of study mission ''' + # maximum take off mass + m_take_off_max = root_of_aircraft_exchange_tree.find( + './analysis/masses_cg_inertia/maximum_takeoff_mass/mass_properties/mass/value') + if m_take_off_max is not None: + m_take_off_max = float(m_take_off_max.text) + else: + m_take_off_max = 0.0 + # study mission take off mass + m_take_off_mission_study = root_of_aircraft_exchange_tree.find( + './analysis/mission/study_mission/takeoff_mass/value') + if m_take_off_mission_study is not None: + m_take_off_mission_study = float(m_take_off_mission_study.text) + else: + m_take_off_mission_study = 0.0 + + if m_take_off_max < m_take_off_mission_study: + print('Error: Calculated TOM on Study Mission (' + str(m_take_off_mission_study) + 'kg) exceeded MTOM (' + + str(m_take_off_max) + ' kg)!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'ERROR: Calculated TOM on Study Mission (' + str(m_take_off_mission_study) + + 'kg) exceeded MTOM (' + str(m_take_off_max) + ' kg)!') + + ''' write log-file to system ''' + log_file_list.append('*************************************** end check tlars and climb gradients ' + '***************************************') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) diff --git a/UNICADOworkflow/src/pre_condition/check_design_logic.py b/UNICADOworkflow/src/pre_condition/check_design_logic.py new file mode 100644 index 0000000000000000000000000000000000000000..c2b9cb466a9a4d491d4e19c203eb4968327e3a4a --- /dev/null +++ b/UNICADOworkflow/src/pre_condition/check_design_logic.py @@ -0,0 +1,493 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +# imports for python +import os +import sys +import shutil +from inspect import currentframe, getframeinfo +from datetime import datetime +from sub_function.read_xml_file import read_xml_file +from sub_function.check_for_existing_geometry import check_for_existing_geometry +from sub_function.prepare_single_mission_analysis import prepare_single_mission_analysis +from sub_function.write_to_log_file import write_to_log_file +from parameter_study.initialize_parameter_study import initialize_parameter_study + + +def check_design_logic(paths_and_names, parameter_for_design_case, control_settings, global_loop_counter, + outer_loop_counter): + """ check_design_logic checks the switches in aircraft exchange- and config files of selected design mode + -> if check fails -> switches will set to correct value. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + + The input list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'use_range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + The input integer 'global_loop_counter' contains the current outer loop number. + + The input integer 'outer_loop_counter' contains the maximum number of parameter study loops to perform. + + The output list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + + The output integer 'outer_loop_counter' contains the maximum number of parameter study loops to perform. + + :param: paths_and_names: input list of lists + :param: parameter_for_design_case: input list of lists + :param: control_settings: input list of lists + :param: global_loop_counter: input integer + :param: outer_loop_counter: input integer + :return: parameter_for_design_case: output list of list, outer_loop_counter: output integer + """ + + ''' create list for log-file string ''' + log_file_list = ['', + '************************************************ check design logic ' + '************************************************'] + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + aircraft_type = ([item for item in paths_and_names if 'aircraft_type' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory = ([item for item in paths_and_names if 'path_of_working_directory' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + path_to_aircraft_projects = ([item for item in paths_and_names if 'path_to_aircraft_projects' in item])[-1][-1] + path_to_aircraft_design_tools = \ + ([item for item in paths_and_names if 'path_to_aircraft_design_tools' in item])[-1][-1] + path_to_software_tools = ([item for item in paths_and_names if 'path_to_software_tools' in item])[-1][-1] + path_to_project = ([item for item in paths_and_names if 'path_to_project' in item])[-1][-1] + + design_mode = ([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1] + parameter_study_mode = (([item for item in parameter_for_design_case if 'program_mode' in item])[-1][-1] + == "parameter_study") + optimization_mode = (([item for item in parameter_for_design_case if 'program_mode' in item])[-1][-1] + == "optimization") + + ''' initialize local parameter ''' + function_name = getframeinfo(currentframe()).function + file_name = str() + program_switch = str() + design_type = str() + path_to_repository = str() + path_to_repository_file = str() + perform_workflow_execution = int(1) + overwrite_fuselage_geometry = int() + check_flag_for_start_file = bool() + + ''' create list of files in working directory to check if all tools exist ''' + files_in_origin_tool_directory = os.listdir(path_to_aircraft_design_tools + 'UNICADOworkflow/jsonFiles') + + # loop for all elements in list of files + for file_name in files_in_origin_tool_directory: + if not file_name == '.git': + # check if file_name a directory + check_for_origin_tool_directory = os.path.isdir(path_to_aircraft_design_tools + file_name) + check_for_origin_software_tool_directory = os.path.isdir(path_to_software_tools + file_name) + check_for_working_tool_directory = os.path.isdir(path_of_working_directory + file_name) + + # check if working copy of each module exist -> otherwise copy to working directory + if check_for_origin_tool_directory and not check_for_working_tool_directory: + shutil.copytree(path_to_aircraft_design_tools + file_name, path_of_working_directory + file_name) + print('Working copy of ' + file_name + ' has been successfully created!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Working copy of ' + file_name + ' has been successfully created!') + + # check if working copy of software tool exist -> otherwise copy to working directory + if check_for_origin_software_tool_directory and not check_for_working_tool_directory: + shutil.copytree(path_to_software_tools + file_name, path_of_working_directory + file_name) + print('Working copy of ' + file_name + ' has been successfully created!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Working copy of ' + file_name + ' has been successfully created!') + + # check if the parameter study mode is selected and the global loop counter is greater than 1 + # -> if true: -> perform parameter study loop + if parameter_study_mode == 1 and global_loop_counter > 1: + print('Parameter study is running! Current study loop is: ' + str(global_loop_counter - 1) + ' of ' + + str(outer_loop_counter - 1)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Parameter study is running! Current study loop is: ' + str(global_loop_counter - 1) + + ' of ' + str(outer_loop_counter - 1)) + + # check if the parameter study mode is selected and the global loop counter is greater than 1 + # -> if true: -> perform parameter study loop + if optimization_mode == 1 and global_loop_counter > 1: + print('Optimization is running! Current optimization loop is: ' + str(global_loop_counter - 1)) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Optimization is running! Current optimization loop is: ' + str(global_loop_counter - 1)) + + # check if the parameter study mode is not selected or reference case should be estimated + # -> if true: -> set design mode settings for single workflow execution + if global_loop_counter == 1: + ''' check witch mode is selected''' + # design mode 0 is selected -> standard mode + if design_mode == 0: + print('Standard execution will be performed! ' + 'No parameter checks will be performed and parameter will be reset!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ':' + ' Standard execution will be performed! ' + 'No parameter checks will be performed and no parameter will be reset!') + + # design mode 1 is selected -> clean sheet design with mission analysis will be performed + if design_mode == 1: + print('Clean sheet design will be performed!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Clean sheet design will be performed!') + + # design mode 2 is selected -> sizing with an existing geometry will be performed + if design_mode == 2: + print('Design with existing geometry will be performed!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Design with existing geometry will be performed!') + + # mission study analysis without design sizing loop + if design_mode == 3: + print('Mission study analysis without design sizing loop will be performed! ' + 'Attention, a converged aircraft exchange file and the associated engine ' + 'and aerodynamic data are required!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Mission study analysis without design sizing loop will be performed! Attention, ' + 'a converged aircraft exchange file and the associated engine and aerodynamic ' + 'data are required!') + + # mission study analysis without design sizing loop + if design_mode == 4: + print('Design sizing loop as a clean sheet design without mission analysis loop will be performed!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Design sizing loop as a clean sheet design without mission analysis loop will be ' + 'performed! ') + + # wrong mode selection -> clean sheet design will be performed + if (design_mode < 0) or (design_mode > 4): + print('WARNING: Wrong design mode selection! Only design mode 0, 1, 2, 3 or 4 is allowed! ' + 'Execution mode will be set to clean sheet design!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'WARNING: Wrong design mode selection! Only design mode 0, 1, 2, 3 or 4 is allowed! ' + 'Execution mode will be set to clean sheet design!') + design_mode = 1 + ([item for item in parameter_for_design_case if 'design_mode' in item])[-1][-1] = design_mode + + ''' set design mode specific settings and perform initializing steps ''' + if design_mode == 1 or design_mode == 2 or design_mode == 4: + ''' set design mode specific settings ''' + # design mode 1 or 4 is selected -> set mode to clean_sheet_design + if design_mode == 1 or design_mode == 4: + program_switch = "mode_0" + design_type = 'clean_sheet_design' + + # design mode 2 is selected -> set mode to sizing with an existing geometry + if design_mode == 2: + program_switch = "mode_1" + design_type = 'retrofit_design/without_calibration' + + ''' check existance of start file ''' + file_name = aircraft_project + '_start.xml' + check_flag_for_start_file = os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/' + file_name) + + ''' perform initializing steps ''' + # append final file separator to path_to_aircraft_project if not exiting + if not path_to_aircraft_projects[-1] == '/': + path_to_aircraft_projects = path_to_aircraft_projects + '/' + + if 'originUnicadoProjects' in path_to_aircraft_projects: + path_to_aircraft_projects = path_to_aircraft_projects + 'projects/' + + path_to_repository = path_to_aircraft_projects + aircraft_type + '/' + aircraft_project \ + + '/' + design_type + '/' + path_to_repository_file = path_to_repository + file_name + + # Check if the sizing loop starting file exist inside the project folder + # -> if true: -> rename to project file + if check_flag_for_start_file: + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + + file_name, + path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + + aircraft_exchange_file) + + # Else condition: starting file not exist inside the project folder + # -> copy starting file from repository and rename to project file + else: + if os.path.isfile(path_to_repository_file): + shutil.copy(path_to_repository_file, path_to_project + file_name) + shutil.copy(path_to_project + file_name, + path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/' + aircraft_exchange_file) + else: + print('Error: ' + file_name + ' could not be copied, no ' + file_name + + ' in repository folder found! \n Program aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: ' + file_name + ' could not be copied, no ' + file_name + + ' in repository folder found! \n Program aborted!') + + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + sys.exit(1) + + if design_mode == 2: + # check if the necessary geometry data files exist in the current project folder + # -> otherwise try to copy from repository + log_file_list = check_for_existing_geometry(path_of_working_directory_rce, aircraft_project, file_name, + path_to_repository, log_file_list, current_workflow_name) + + ''' convert switches in config files of modules according to design mode if requested: ''' + adapt_module_configs_to_design_case =\ + int(([item for item in control_settings if 'check_settings_for_design_logic' in item])[-1][-1]) + + if adapt_module_configs_to_design_case: + # set switch in wing_design_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/wing_design_conf.xml' + root_of_wing_design_conf, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'wing_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # change sizing mode of wing design to initial sizing + path_in_config = './program_settings/modes/design_mode/value' + root_of_wing_design_conf.find(path_in_config).text = program_switch + xml_tree.write(path_of_working_directory_rce + current_workflow_name + '/wing_design_conf.xml', + encoding='utf-8') + print('Sizing mode switch \'' + path_in_config + '\' in the wing_design_conf.xml file is set to ' + + program_switch + '!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Sizing mode switch \'' + path_in_config + '\' in the wing_design_conf.xml file ' + + 'is set to ' + program_switch + '!') + + # set switch in empennage_design_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/empennage_design_conf.xml' + root_of_empennage_sizing_conf, xml_tree = read_xml_file(path, path_of_working_directory_rce, + 'empennage_design', function_name, + frame_info.lineno, log_file_list, + current_workflow_name) + + # change sizing mode of empennage sizing to initial sizing + path_in_config = './program_settings/modes/design_mode/value' + root_of_empennage_sizing_conf.find(path_in_config).text = program_switch + xml_tree.write(path_of_working_directory_rce + current_workflow_name + '/empennage_design_conf.xml', + encoding='utf-8') + print('Sizing mode switch \'' + path_in_config + '\' in the empennage_design_conf.xml file ' + + 'is set to ' + program_switch + '!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Sizing mode switch \'' + path_in_config + '\' in the empennage_design_conf.xml ' + + 'file is set to ' + program_switch + '!') + + # set switch in propulsion_design_conf.xml + #frame_info = getframeinfo(currentframe()) + #path = path_of_working_directory_rce + current_workflow_name + '/propulsion_design_conf.xml' + #root_of_propulsion_integration_conf, xml_tree = read_xml_file(path, path_of_working_directory_rce, + # 'propulsion_design', function_name, + # frame_info.lineno, log_file_list, + # current_workflow_name) + + # change sizing mode of propulsion integration to initial sizing + #path_in_config = './ProgramSettings/SizingMode' + #root_of_propulsion_integration_conf.find(path_in_config).text = str(int(1)) + #xml_tree.write(path_of_working_directory_rce + current_workflow_name + # + '/propulsion_design_conf.xml', encoding='utf-8') + #print('Sizing mode switch \'' + path_in_config + '\' in the propulsion_design_conf.xml file ' + # + 'is set to mode ' + str(program_switch) + '!') + #log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + # 'Sizing mode switch \'' + path_in_config + '\' in the ' + # + 'propulsion_design_conf.xml file is set to mode ' + str(program_switch) + # + '!') + + # set switch in fuselage_design_conf.xml + #frame_info = getframeinfo(currentframe()) + #path = path_of_working_directory_rce + current_workflow_name + '/fuselage_design_conf.xml' + #root_of_fuselage_design_conf, xml_tree = read_xml_file(path, path_of_working_directory_rce, + # 'fuselage_design', function_name, + # frame_info.lineno, log_file_list, + # current_workflow_name) + + # change mode of fuselage design to allow or prohibit overwrite an existing fuselage geometry + #path_in_config = './ControlSettings/ProgramSpecific/OverwriteFuselageGeometry' + #root_of_fuselage_design_conf.find(path_in_config).text = \ + # str(int(overwrite_fuselage_geometry)) + #xml_tree.write(path_of_working_directory_rce + current_workflow_name + '/fuselage_design_conf.xml', + # encoding='utf-8') + #print('Overwrite fuselage geometry switch \'' + path_in_config + '\' in the fuselage_design_conf.xml ' + # + 'file is set to mode ' + str(overwrite_fuselage_geometry) + '!') + #log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + # 'Overwrite fuselage geometry switch \'' + path_in_config + '\' in the ' + # + 'fuselage_design_conf.xml file is set to mode ' + str(overwrite_fuselage_geometry) + # + '!') + + ''' check existance of aircraft project file ''' + if not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/' + aircraft_exchange_file): + print('Error: ' + aircraft_exchange_file + ' is not existing in working directory ' + + path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + + '\n Program aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: ' + aircraft_exchange_file + ' is not existing in working directory ' + + path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/' + '\n Program aborted!') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + sys.exit(1) + + ''' Convert switches in config file to design mode ''' + if design_mode == 3: + mission_type = "study" + else: + mission_type = "design" + # set switches in create_mission_xml_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/create_mission_xml_conf.xml' + create_mission_conf_xml_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'create_mission_xml', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # Change switch to design mission in order to create a design mission + create_mission_conf_xml_root.find('./program_settings/mission_selector/value').text = mission_type + "_mission" + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + #Print change to output + print('Set mode switch in the create_mission_conf.xml to create ' + mission_type + '_mission!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Set mode switch in the create_mission_conf.xml to create ' + mission_type + '_mission!') + + + # set switches in systems_design_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/systems_design_conf.xml' + systems_design_conf_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'systems_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # Change switch from design mission to study mission, + # in order to calculate systems characteristics for a study mission + systems_design_conf_root.find('./program_settings/mission_mode/value').text = mission_type + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + #Print change to output + print('Set mode switch in the systems_design_conf.xml to ' + mission_type + ' systems accordingly!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Set mode switch in the systems_design_conf.xml to ' + mission_type + + ' systems accordingly!') + + # set switches in mission_analysis_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/mission_analysis_conf.xml' + mission_analysis_conf_xml_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'mission_analysis', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # for a study mission - switch off the MTOM estimation + mission_analysis_conf_xml_root.find('./program_settings/mode/mission_methods/mission_type/value').text = \ + mission_type + "_mission" + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + #Print change to output + print('Set mode switch in the mission_analysis_conf.xml to fly the ' + mission_type + '_mission!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Set mode switch in the mission_analysis_conf.xml to fly the ' + mission_type + '_mission!') + + if design_mode == 3: + file_name = aircraft_project + '.xml' + prepare_single_mission_analysis(path_of_working_directory_rce, aircraft_project, file_name, log_file_list, + current_workflow_name) + + ''' initialize parameter study if selected in workflow configuration file ''' + if parameter_study_mode == 1 and global_loop_counter == 1: + back_up_outer_loop_counter = outer_loop_counter + print(' * ------ initialize parameter study ------') + log_file_list.append(' * ------ initialize parameter study ------') + # call function to initialize parameter study + abort_parameter_study_flag, outer_loop_counter, log_file_list = initialize_parameter_study(paths_and_names, + log_file_list) + print(' * ------ end initialize parameter study ------') + log_file_list.append(' * ------ end initialize parameter study ------') + + # check if the abort_parameter_study_flag is equal to True -> if true: -> set parameter_study_mode switch to 0 + if abort_parameter_study_flag: + outer_loop_counter = back_up_outer_loop_counter + perform_workflow_execution = int(0) + + ''' write log-file to system ''' + log_file_list.append('********************************************** end check design logic ' + '**********************************************') + + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + return parameter_for_design_case, outer_loop_counter, perform_workflow_execution diff --git a/UNICADOworkflow/src/pre_condition/generate_identifier.py b/UNICADOworkflow/src/pre_condition/generate_identifier.py new file mode 100644 index 0000000000000000000000000000000000000000..0004ac9156e41c7e309a4d7b038447648344d117 --- /dev/null +++ b/UNICADOworkflow/src/pre_condition/generate_identifier.py @@ -0,0 +1,69 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def generate_identifier(install_path_directory, current_workflow_name): + """ generate_identifier generates the identifier *.dat-file of current workflow execution, + which specifies the number of workflow executions running in parallel. + + The input string "install_path_directory" contains absolute path of UNICADO install directory: + + The input string "current_workflow_name" contains the name of the current executed workflow. + + :param: install_path_directory: input string + :param: current_workflow_name: input string + :return: identifier: output integer + """ + ''' imports for python ''' + import os + + ''' initialize local parameter ''' + count = 0 + identifier = 0 + + # check if the identifier directory currently exist -> if not -> create the directory + if not os.path.isdir(install_path_directory + 'workingDirectoryRCE/identifier'): + os.mkdir(install_path_directory + 'workingDirectoryRCE/identifier') + + # read the directory content as list + list_of_identifier_files = os.listdir(install_path_directory + 'workingDirectoryRCE/identifier') + + ''' generate identifier for current workflow execution ''' + # check if the identifier directory is not empty -> if true: -> check for next available identifier number + if len(list_of_identifier_files) > 0: + for file in list_of_identifier_files: + file_number = file[:-4] + # check if current count number usable as an identifier number + if int(file_number) > count: + identifier = count + break + + # add + 1 to file counter + count += 1 + + # check if no empty identifier is left -> if true: -> add new file to identifier directory + if count == len(list_of_identifier_files): + identifier = len(list_of_identifier_files) + + # write current workflow name into the identifier *.dat-file of current workflow execution + identifier_file = open(install_path_directory + 'workingDirectoryRCE/identifier/' + str(identifier) + '.dat', 'w') + identifier_file.write(current_workflow_name) + identifier_file.close() + + return identifier diff --git a/UNICADOworkflow/src/pre_condition/generate_paths.py b/UNICADOworkflow/src/pre_condition/generate_paths.py new file mode 100644 index 0000000000000000000000000000000000000000..3af0e2f1537d6717461db00e6c7a42ed326edeb7 --- /dev/null +++ b/UNICADOworkflow/src/pre_condition/generate_paths.py @@ -0,0 +1,180 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def generate_paths(paths_and_names, current_workflow_name): + """ generate_paths imports and generates all paths are needed to following workflow steps. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + + The input string "current_workflow_name" contains the name of the current executed workflow. + + The output list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + + :param: paths_and_names: input list of lists + :param: current_workflow_name: input String + :return: paths_and_names: output list of lists + """ + + ''' import for python ''' + import configparser + import os + import sys + import shutil + from datetime import datetime + from sub_function.write_to_log_file import write_to_log_file + + ''' create list for log-file string ''' + log_file_list = [] + + ''' read user path of local user ''' + user_path_string = os.path.expanduser("~") + # convert path of current working directory to a python path -> \ to / + user_path_string = user_path_string.replace(os.sep, '/') + + ''' generate paths from file in .rce-directory ''' + # path to UNICADO repository + if os.path.isfile(user_path_string + + '/.rce/default/integration/tools/common/absolutPathToUNICADOrepositoryDirectory.txt'): + absolut_path_to_unicado_git = open(user_path_string + + '/.rce/default/integration/tools/common/' + 'absolutPathToUNICADOrepositoryDirectory.txt', 'r') + root_directory_of_unicado = str(absolut_path_to_unicado_git.read()) + root_directory_of_unicado = root_directory_of_unicado.replace(os.sep, '/') + elif os.path.isfile(user_path_string + '/.rce/default/integration/tools/common/standAloneInstallationFlag.dat'): + root_directory_of_unicado = user_path_string + '/.rce/default/integration/tools/common/' + + else: + print('UNICADO workflow is not installed correctly. Please reinstall UNICADOworkflow! Program aborted!') + sys.exit(1) + + # path to UNICADO working directory + absolut_path_to_working_dir = open( + user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt', 'r') + root_directory_of_working_dir = str(absolut_path_to_working_dir.read()) + root_directory_of_working_dir = root_directory_of_working_dir.replace(os.sep, '/') + + # path of origin tool directory + path_of_origin_tool_directory = root_directory_of_unicado + print(path_of_origin_tool_directory) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Aircraft Design Repository: ' + path_of_origin_tool_directory) + + # path of UNICADO working directory + path_of_working_directory = root_directory_of_working_dir + print(path_of_working_directory) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Install / Working Directory: ' + path_of_working_directory) + + # check if workingDirectory exist + check_flag_working_directory = os.path.isdir(path_of_working_directory) + if not check_flag_working_directory: + os.makedirs(path_of_working_directory) + + # path of RCE working directory + path_of_working_directory_rce = path_of_working_directory + 'workingDirectoryRCE/' + print(path_of_working_directory_rce) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'RCE Working Directory: ' + path_of_working_directory_rce) + + # check if workingDirectoryRCE exist + check_flag_working_directory_rce = os.path.isdir(path_of_working_directory_rce) + if not check_flag_working_directory_rce: + os.makedirs(path_of_working_directory_rce) + + ''' paths to origin unicado modules, software tools and aircraft projects ''' + # set repository directories to copy files + path_to_software_tools = 'emptyPath' + path_to_aircraft_design_tools = 'emptyPath' + path_to_aircraft_projects = 'emptyPath' + if os.path.isfile(user_path_string + + '/.rce/default/integration/tools/common/absolutPathToUNICADOrepositoryDirectory.txt'): + files = os.listdir(path_of_origin_tool_directory) + for fileName in files: + check_if_file_is_directory = os.path.isdir(path_of_origin_tool_directory + fileName) + if check_if_file_is_directory: + check_git_folder = os.path.isdir(path_of_origin_tool_directory + fileName + '/.git') + if check_git_folder: + check_config_file = os.path.isfile(path_of_origin_tool_directory + fileName + '/.git/config') + if check_config_file: + config = configparser.ConfigParser() + config.read(path_of_origin_tool_directory + fileName + '/.git/config') + url = config['remote "origin"']['url'] + if url == 'ssh://git@unicado.ilr.rwth-aachen.de:2222/source/rADDITIONALSOFTWARE.git': + path_to_software_tools = path_of_origin_tool_directory + fileName + '/' + + if url == 'ssh://git@unicado.ilr.rwth-aachen.de:2222/source/rAircraftDesign.git': + path_to_aircraft_design_tools = path_of_origin_tool_directory + fileName + '/' + + if url == 'ssh://git@unicado.ilr.rwth-aachen.de:2222/source/rAIRCRAFTREFERENCES.git': + path_to_aircraft_projects = path_of_origin_tool_directory + fileName + '/' + + # check if the standalone version of unicado is installed + elif os.path.isfile(user_path_string + '/.rce/default/integration/tools/common/standAloneInstallationFlag.dat'): + path_to_software_tools = root_directory_of_unicado + 'originUnicadoSoftwareTools/' + path_to_aircraft_projects = root_directory_of_unicado + 'originUnicadoProjects/' + path_to_aircraft_design_tools = root_directory_of_unicado + 'originUnicadoDesignTools/' + + # else condition: unicado is not installed correctly + else: + print('UNICADO workflow is not installed correctly. Please reinstall UNICADOworkflow! Program aborted!') + sys.exit(1) + + # check if workflow directory exist + if not os.path.isdir(path_of_working_directory_rce + 'UNICADOworkflow'): + shutil.copytree(path_of_origin_tool_directory + path_to_aircraft_design_tools + 'UNICADOworkflow', + path_of_working_directory_rce + 'UNICADOworkflow') + + ''' remove old workflow data from temporary workflow results ''' + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/temporaryResults'): + os.makedirs(path_of_working_directory_rce + current_workflow_name + '/temporaryResults') + + ''' generate list of lists for data exchange ''' + paths_and_names = paths_and_names + [['path_of_working_directory', path_of_working_directory], + ['path_of_working_directory_rce', path_of_working_directory_rce], + ['path_of_origin_tool_directory', path_of_origin_tool_directory], + ['current_workflow_name', current_workflow_name], + ['path_to_aircraft_projects', path_to_aircraft_projects], + ['path_to_aircraft_design_tools', path_to_aircraft_design_tools], + ['path_to_software_tools', path_to_software_tools], + ['path_to_json_files', + user_path_string + '/.rce/default/integration/tools/common/']] + + # path of temporary workflow working directory + print(path_of_working_directory_rce + current_workflow_name) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Temporary workflow working directory: ' + + path_of_working_directory_rce + current_workflow_name) + + ''' write log-file to system ''' + log_file_list.append( + '************************************************ end generate paths ' + '************************************************') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + return paths_and_names diff --git a/UNICADOworkflow/src/pre_condition/prepare_optimization.py b/UNICADOworkflow/src/pre_condition/prepare_optimization.py new file mode 100644 index 0000000000000000000000000000000000000000..7e2732b8ae5f9cc26a9019dc00d383e2c3ff85a0 --- /dev/null +++ b/UNICADOworkflow/src/pre_condition/prepare_optimization.py @@ -0,0 +1,214 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def prepare_optimization(install_path_directory, current_workflow_name, global_loop_counter): + """ set_configuration_parameter read workflow configuration parameter from workflow configuration file. + Set values to output lists for following workflow components. + + The input string "install_path_directory" contains the absolute path to the installation directory of UNICADO. + + The input string "current_workflow_name" contains the name of current workflow execution. + + The output integer "global_loop_counter" contains the number of current outer workflow loop. + + The output integer "preparation_status" contains the status of preparation. + + :param: install_path_directory: input string + :param: current_workflow_name: input string + :param: global_loop_counter: input integer + :return: preparation_status: output integer + """ + + ''' imports for python ''' + import os + import shutil + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.xml_path_check import xml_path_check + + ''' initialize local parameter ''' + log_file_list = [] + preparation_status = 1 + path_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + path_to_temporary_working_directory = install_path_directory + 'workingDirectoryRCE/' + current_workflow_name + '/' + + function_name = getframeinfo(currentframe()).function + + ''' open and read parameter from unicado_workflow_conf.xml configuration file ''' + frame_info = getframeinfo(currentframe()) + path = path_to_temporary_working_directory + 'unicado_workflow_conf.xml' + root_of_workflow_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'unicado_workflow', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + aircraft_project = root_of_workflow_tree.find('./control_settings/aircraft_exchange_file_name/value').text[:-4] + path_to_reference_project_directory = install_path_directory + 'workflowResults/' + current_workflow_name + '_' \ + + aircraft_project + '_optimization/referenceCase/' + + # check if the current outer loop counter is equal to 2 + # -> if true: -> prepare UNICADOworkflow configuration file to perform optimization + # -> disable all update and copy modes to use the same files even during optimization + if global_loop_counter == 2: + # delete old default file if it is existing + if os.path.isfile(path_to_temporary_working_directory + aircraft_project + '/' + aircraft_project + + '_Default.xml'): + os.remove(path_to_temporary_working_directory + aircraft_project + '/' + aircraft_project + '_Default.xml') + + try: + shutil.copyfile(path_to_reference_project_directory + aircraft_project + '.xml', + path_to_temporary_working_directory + aircraft_project + '/' + aircraft_project + + '_Default.xml') + + # set clean up parameter to zero and activate retrofit mode in UNICADOworkflow configuration file + root_of_workflow_tree.find( + './control_settings/program_specific_settings/' + 'pre_workflow_operation_settings/set_project_folder_to_default/value').text = str(bool(0)).lower() + root_of_workflow_tree.find( + './control_settings/program_specific_settings/' + 'pre_workflow_operation_settings/delete_engines_before_run/value').text = str(bool(0)).lower() + root_of_workflow_tree.find( + './control_settings/program_specific_settings/' + 'iteration_settings/use_configs_from_existing_project/config_copy_mode/value').text = "mode_0" + root_of_workflow_tree.find( + './control_settings/program_specific_settings/' + 'iteration_settings/use_engine_from_existing_project/engine_copy_mode/value').text = "mode_0" + root_of_workflow_tree.find( + './program_settings/design_case_settings/design_mode/value').text = "mode_2" + xml_tree.write(path_to_temporary_working_directory + 'unicado_workflow_conf.xml', encoding='utf-8') + + except OSError: + print('Error: clean up parameter could not be set to zero in unicado_workflow_conf.xml!\n' + 'Optimization framework will be aborted!') + preparation_status = 0 + + # check if the optimization configuration file exist -> if true: -> check the xml paths of all parameter + if os.path.isfile(path_to_temporary_working_directory + 'optimization_conf.xml'): + frame_info = getframeinfo(currentframe()) + path = path_to_temporary_working_directory + 'optimization_conf.xml' + root_of_optimization_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'optimization', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + try: + # set system path of temporary working directory of current workflow execution + # to optimization configuration file + root_of_optimization_tree.find( + './ProgramSettings/SensitivityStudySettings/PathToCurrentWorkingDir').text = \ + path_to_temporary_working_directory + # read and check xml paths of design variables and set system path to xml file + number_of_design_variables = int(root_of_optimization_tree.find( + './ProgramSettings/designParameter/designVariables').text) + for i in range(0, number_of_design_variables): + xml_path_to_check = root_of_optimization_tree.find( + "./ProgramSettings/designParameter/designVariable[" + "@ID='" + str(i) + "'" + "]" + "PathInXmlFile").text + corrected_xml_path = xml_path_check(xml_path_to_check) + root_of_optimization_tree.find( + "./ProgramSettings/designParameter/designVariable[" + "@ID='" + str(i) + "'" + "]" + "PathInXmlFile").text = corrected_xml_path + xml_file_name = root_of_optimization_tree.find( + "./ProgramSettings/designParameter/designVariable[" + "@ID='" + str(i) + "'" + "]" + "FileName").text + if '_conf' in xml_file_name: + path_to_file = path_to_temporary_working_directory + xml_file_name + else: + path_to_file = path_to_temporary_working_directory + aircraft_project + '/' + xml_file_name + root_of_optimization_tree.find( + "./ProgramSettings/designParameter/designVariable[" + "@ID='" + str(i) + "'" + "]" + "PathToFile").text = path_to_file + + # read and check xml paths of cost functions and set system path to xml file + number_of_cost_function_parameter = int(root_of_optimization_tree.find( + './ProgramSettings/costFunctions/costFunctionsParameters').text) + for i in range(0, number_of_cost_function_parameter): + xml_path_to_check = root_of_optimization_tree.find( + "./ProgramSettings/costFunctions/costFunctionsParameter[" + "@ID='" + str(i) + "'" + "]" + "PathInXmlFile").text + corrected_xml_path = xml_path_check(xml_path_to_check) + root_of_optimization_tree.find( + "./ProgramSettings/costFunctions/costFunctionsParameter[" + "@ID='" + str(i) + "'" + "]" + "PathInXmlFile").text = corrected_xml_path + xml_file_name = root_of_optimization_tree.find( + "./ProgramSettings/costFunctions/costFunctionsParameter[" + "@ID='" + str(i) + "'" + "]" + "FileName").text + if '_conf' in xml_file_name: + path_to_file = path_to_temporary_working_directory + xml_file_name + else: + path_to_file = path_to_temporary_working_directory + aircraft_project + '/' + xml_file_name + root_of_optimization_tree.find( + "./ProgramSettings/costFunctions/costFunctionsParameter[" + "@ID='" + str(i) + "'" + "]" + "PathToFile").text = path_to_file + + # read and check xml paths of requirement parameter and set system path to xml file + number_of_design_requirements = int(root_of_optimization_tree.find( + './ProgramSettings/designRequirementParameter/designRequirements').text) + for i in range(0, number_of_design_requirements): + xml_path_to_check = root_of_optimization_tree.find( + "./ProgramSettings/designRequirementParameter/designRequirement[" + "@ID='" + str(i) + "'" + "]" + "PathInXmlFile").text + corrected_xml_path = xml_path_check(xml_path_to_check) + root_of_optimization_tree.find( + "./ProgramSettings/designRequirementParameter/designRequirement[" + "@ID='" + str(i) + "'" + "]" + "PathInXmlFile").text = corrected_xml_path + xml_file_name = root_of_optimization_tree.find( + "./ProgramSettings/designRequirementParameter/designRequirement[" + "@ID='" + str(i) + "'" + "]" + "FileName").text + if '_conf' in xml_file_name: + path_to_file = path_to_temporary_working_directory + xml_file_name + else: + path_to_file = path_to_temporary_working_directory + aircraft_project + '/' + xml_file_name + root_of_optimization_tree.find( + "./ProgramSettings/designRequirementParameter/designRequirement[" + "@ID='" + str(i) + "'" + "]" + "PathToFile").text = path_to_file + + xml_tree.write(path, encoding='utf-8') + + except OSError: + print('Error: Optimization configuration file could not opened or is corrupt!\n' + 'Optimization framework will be aborted!') + preparation_status = 0 + + else: + print('Error: Optimization configuration file could not find in the temporary working directory of current ' + 'workflow execution!\n' + 'Optimization framework will be aborted!') + preparation_status = 0 + + ''' reset module configuration files ''' + if os.path.isdir(path_to_reference_project_directory + 'config_files/preExecution'): + list_of_directory_content = os.listdir(path_to_reference_project_directory + 'config_files/preExecution') + + for directory in list_of_directory_content: + path_to_config_files = path_to_reference_project_directory + 'config_files/preExecution/' + directory + list_of_sub_folder_content = os.listdir(path_to_config_files) + for config_file in list_of_sub_folder_content: + try: + shutil.copyfile(path_to_config_files + '/' + config_file, + path_to_temporary_working_directory + config_file) + print('Reset of ' + config_file[:-9] + ' configuration file successful.') + except OSError: + print('Reset of ' + config_file[:-9] + ' configuration file failed.') + preparation_status = 0 + + else: + print('Error: Could not find ' + path_to_reference_project_directory + 'config_files/preExecution\n' + 'Optimization framework will be aborted!') + preparation_status = 0 + + return preparation_status diff --git a/UNICADOworkflow/src/pre_condition/reset_of_important_values.py b/UNICADOworkflow/src/pre_condition/reset_of_important_values.py new file mode 100644 index 0000000000000000000000000000000000000000..32877cf2b89ec9a513347120de96203d1567a58c --- /dev/null +++ b/UNICADOworkflow/src/pre_condition/reset_of_important_values.py @@ -0,0 +1,188 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def reset_of_important_values(paths_and_names, control_settings, program_mode): + """ reset_of_important_values resets all important switches in the aircraft exchange file to perform design sizing loop. + Attention: If the selected design mode is not "clean sheet design", switches will not reset. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'use_range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + * [22][0] string: 'program_mode', [22][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + + :param: paths_and_names: input list of lists + :param: control_settings: input list of lists + :return: none + """ + + ''' imports for python ''' + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + from sub_function.write_to_log_file import write_to_log_file + from pre_condition.set_range_type_specific_factors import set_range_type_specific_factors + + '''create list for log-file string ''' + log_file_list = ['', + '******************************************** reset Of important values ' + '********************************************'] + + ''' read data for script execution ''' + aircraft_exchange_file = ([item for item in paths_and_names if 'aircraft_exchange_file' in item])[-1][-1] + aircraft_project = ([item for item in paths_and_names if 'aircraft_project' in item])[-1][-1] + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + use_range_type_specific_factors = \ + int(([item for item in control_settings if 'use_range_type_specific_factors' in item])[-1][-1]) + + ''' initialize local parameter''' + function_name = getframeinfo(currentframe()).function + + ''' open and reset requirement switches to zero aircraft exchange file ''' + # try to open configuration file as element tree + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' \ + + aircraft_exchange_file + root_of_aircraft_exchange_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, + aircraft_exchange_file, function_name, + frame_info.lineno, log_file_list, current_workflow_name) + + ''' open and read range dependent parameter from range_type_specific_factors.xml file ''' + if not use_range_type_specific_factors == 0: + ''' initialize public parameter ''' + scenario_range = str('no range specified') + design_range = float(-1.0) + frame_info = getframeinfo(currentframe()) + path_2 = path_of_working_directory_rce + current_workflow_name + '/range_type_specific_factors.xml' + + ''' read range type specific factors from xml-file ''' + range_type_specific_factors, _ = read_xml_file(path_2, path_of_working_directory_rce, + 'range_type_specific_factors', function_name, + frame_info.lineno, log_file_list, current_workflow_name) + + ''' read and set range scenario''' + if use_range_type_specific_factors == 1: + design_range = float(root_of_aircraft_exchange_tree.find( + './requirements_and_specifications/requirements/top_level_aircraft_requirements/' + 'design_mission/range/value').text) + + if use_range_type_specific_factors == 2 or (0 < design_range < 5556000.): # given here in [m]; for ranges below 3000 NM + scenario_range = 'short-range' + + if use_range_type_specific_factors == 3 or (3000 <= design_range < 10186000.): # given here in [m]; for ranges between 3000 NM and 5500 NM + scenario_range = 'medium-range' + + if use_range_type_specific_factors == 4 or design_range >= 10186000.: + scenario_range = 'long-range' + + ''' call function to set range type specific factors to module configuration files''' + log_file_list = set_range_type_specific_factors(paths_and_names, range_type_specific_factors, + scenario_range, log_file_list) + + if not use_range_type_specific_factors == 0 or program_mode == 'optimization': + ''' convert switches in config files of modules to perform sizing loop: ''' + # set switches in create_mission_xml_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/create_mission_xml_conf.xml' + create_mission_conf_xml_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'create_mission_xml', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # Change switch to design mission in order to create a design mission + create_mission_conf_xml_root.find('./program_settings/mission_selector/value').text = "design_mission" + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + # set switches in systems_design_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/systems_design_conf.xml' + systems_design_conf_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'systems_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # change design case data + systems_design_conf_root.find('./program_settings/mission_mode/value').text = "design" + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + # set switches in mission_analysis_conf.xml + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/mission_analysis_conf.xml' + mission_analysis_conf_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'mission_analysis', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # change mTOM estimation method + mission_analysis_conf_root.find('./program_settings/mode/mission_methods/mission_type/value').text = \ + "design_mission" + # change attribute "Mode" of polar switch + # mission_analysis_conf_root.find('./ProgramSettings/General/PolarSwitchMissionPoint').set('Mode', '1') + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + print('Important values set to default to perform design sizing loop!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Important values set to default to perform design sizing loop!') + + ''' write log-file to system ''' + log_file_list.append('****************************************** end reset Of important values ' + '******************************************') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + return diff --git a/UNICADOworkflow/src/pre_condition/set_configuration_parameter.py b/UNICADOworkflow/src/pre_condition/set_configuration_parameter.py new file mode 100644 index 0000000000000000000000000000000000000000..a765e31b6feecb12a6515ed9184ce07046c0ea0f --- /dev/null +++ b/UNICADOworkflow/src/pre_condition/set_configuration_parameter.py @@ -0,0 +1,895 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def set_configuration_parameter(paths_and_names, global_loop_counter): + """ set_configuration_parameter read workflow configuration parameter from workflow configuration file. + Set values to output lists for following workflow components. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + + The input integer "global_loop_counter" contains the number of current outer workflow loop. + + The output list of lists "accuracy_list" contains the following values: + * [0][0] string: 'accuracy_low', [0][1] float: 'value of low accuracy condition' + * [1][0] string: 'accuracy_medium', [1][1] float: 'value of medium accuracy condition' + * [2][0] string: 'accuracy_high', [2][1] float: 'value of high accuracy condition' + + The output list of lists "control_settings" contains the following values: + * [0][0] string: 'delete_plots_before_run', [0][1] int: 'switch to delete old plots before running' + * [1][0] string: 'delete_engines_before_run', [1][1] int: 'switch to delete old engine data before running' + * [2][0] string: 'clear_old_log_files_at_start', [2][1] int: 'switch to delete old log-files before running' + * [3][0] string: 'plot_output_on', [3][1] int: 'switch to enable or disable plot generation' + * [4][0] string: 'switch_off_plots', [4][1] int: 'switch to enable generation of plots of each iteration step' + * [5][0] string: 'report_output_on' [5][1] int: 'switch to enable or disable report generation' + * [6][0] string: 'switch_off_reports', [6][1] int: 'switch to enable generation of reports of each iteration step' + * [7][0] string: 'tex_report_on' [7][1] int: 'switch to enable or disable tex-report generation' + * [8][0] string: 'switch_off_tex', [8][1] int: 'switch to enable generation of tex-reports of each iteration step' + * [9][0] string: 'status_flag_to_skip_design_sizing' [9][1] int: 'status flag for plot generation of design sizing loop - iniitalized with 0' + * [10][0] string: 'status_flag_to_skip_study_mission', [10][1] int: 'status flag for plot generation of study mission loop - iniitalized with 0' + * [11][0] string: 'check_settings_for_design_logic', [11][1] int: 'value to switch off and on the checks of the design logic' + * [12][0] string: 'use_control_settings_for_sub_programs', [12][1] int: 'value for switching off and on the override control settings of subroutines' + * [13][0] string: 'use_range_type_specific_factors', [13][1] int: 'value for switch of range scenario to set range dependent parameters' + * [14][0] string: 'use_configs_from_existing_project', [14][1] int: 'value to activate copy of configuration files from existing project before running' + * [15][0] string: 'use_engine_from_existing_project', [15][1] int: 'value to activate copy of engine data from existing project before running' + * [16][0] string: 'save_configs_to_result_folder', [16][1] int: 'value to switch off and on the saving of configuration files in the result folder' + * [17][0] string: 'save_log_files_to_result_folder', [17][1] int: 'value to switch off and on the saving of log files in the result folder' + * [18][0] string: 'save_acft_xml_to_result_folder', [18][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder' + * [19][0] string: 'save_acft_xml_after_each_iteration', [19][1] int: 'value to switch off and on the saving of aircraft exchange file in the result folder after each step of iteration' + * [20][0] string: 'write_info_files', [20][1] int: 'switch to activate the writing of info files after each tool execution' + * [21][0] string: 'write_info_files_only_at_last_step_of_iteration', [21][1] int: 'switch to activate the writing of info files only after last step of sizing loop' + + The output list of lists "parameter_for_design_case" contains the following values: + * [0][0] string: 'program_mode', [0][1] string: 'Value of program execution mode - either standard_aircraft_design, or parameter_study, or optimization' + * [1][0] string: 'design_mode', [1][1] int: 'value to check which design mode is selected' + * [2][0] string: 'automatic_trim', [2][1] int: 'value to switch off and on the automatic trim function of the workflow' + * [3][0] string: 'convergence_criteria', [3][1] float: 'value of convergence criteria of ome and mtom iteration' + * [4][0] string: 'number_of_max_iteration', [4][1] int: 'value to set maximum number of design sizing iteration steps' + * [5][0] string: 'bridge_constraint_analyzer', [5][1] int: 'value to switch off and on the execution of constraint_analysis module in workflow for each iteration step' + * [6][0] string: 'damp_mtom_iteration' [6][1] bool: 'switch to activate damping of mtom iteration loop' + * [7][0] string: 'parallel_execution' [7][1] int: 'switch to activate the parallel execution mode' + * [8][0] string: 'count_of_iteration', [8][1] int: 'current number of iteration of design sizing loop' + * [9][0] string: 'count_of_mission_study_loop', [9][1] int: 'current number of iteration of mission study loop' + + The output list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The output list of lists "calibration_settings" contains the following values: + * [0][0] string: 'free_variable_OME_calibration', [0][1] int: 'switch for free variable OME calibration' + * [1][0] string: 'free_variable_MTOM_calibration', [1][1] int: 'switch for free variable MTOM calibration' + * [2][0] string: 'calibration_target_OME', [2][1] float: 'target value for OME calibration' + * [3][0] string: 'calibration_target_mtom', [3][1] float: 'target value for MTOM calibration' + * [4][0] string: 'reset_fuselage_mass_at_start', [4][1] int: 'switch to reset free OME calibration values at start' + * [5][0] string: 'reset_viscous_drag_counts_at_start', [5][1] int: 'switch to reset aerodynamic MTOM calibration value at start' + * [6][0] string: 'reset_engine_fuel_flow_factor_at_start', [6][1] int: 'switch to reset engine MTOM calibration value at start' + * [7][0] string: 'number_of_iterations_before_mtom_calibration', [7][1] int: 'maximum number of OME calibration steps before performing a MTOM calibration' + * [8][0] string: 'max_iterations_before_exit_OME_calibration', [8][1] int: 'maximum number of OME calibration steps before exit the calibration' + * [9][0] string: 'trunc_Error_factor', [9][1] int: 'value for termination criterion -> as factor regarding convergence criteria' + * [10][0] string: 'damp_MTOM_calibration_lever', [10][1] int: 'switch for damping MTOM calibration lever arm' + * [11][0] string: 'x_rel_max_for_MTOM_damp', [11][1] float: 'value of relative MTOM calibration lever arm' + * [12][0] string: 'damp_OME_calibration_lever', [12][1] int: 'Switch for damping OME calibration lever arm' + * [13][0] string: 'x_rel_max_for_OME_damp', [13][1] float: 'value of relative OME calibration lever arm' + + The output list of lists "module_list_of_sizing_loop" is a dynamic list of used sizing loop modules of current workflow execution: + * [:][0] string: 'sizing_loop_module', [0][:] string: 'name of the used sizing loop module of current workflow execution' + + :param: paths_and_names: input list of lists + :param: global_loop_counter: input integer + :return: accuracy_list: output list of lists, control_settings: output list of lists, parameter_for_design_case: output list of lists, + paths_and_names: output list of lists, calibration_settings: output list of lists, module_list_of_sizing_loop: list of lists + """ + + ''' imports for python ''' + import json + import os + import sys + import shutil + import time + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.path_check import path_check + from sub_function.read_xml_file import read_xml_file + from sub_function.recursive_data_remove import recursive_data_remove + from calibration.read_calibration_parameter import read_calibration_parameter + from sub_function.select_engine_from_existing_project import select_engine_from_existing_project + from sub_function.select_configuration_files_from_existing_project \ + import select_configuration_files_from_existing_project + from sub_function.write_to_log_file import write_to_log_file + + ''' create list for log-file string ''' + log_file_list = ['', + '******************************************** set configuration parameter ' + '********************************************'] + + ''' read data for script execution ''' + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory = ([item for item in paths_and_names if 'path_of_working_directory' in item])[-1][-1] + path_of_working_directory_rce = \ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + path_to_aircraft_projects = ([item for item in paths_and_names if 'path_to_aircraft_projects' in item])[-1][-1] + path_to_software_tools = ([item for item in paths_and_names if 'path_to_software_tools' in item])[-1][-1] + path_to_json_files = ([item for item in paths_and_names if 'path_to_json_files' in item])[-1][-1] + + ''' initialize local parameter ''' + function_name = getframeinfo(currentframe()).function + + ''' set accuracy condition ''' + accuracy_low = round(float(0.0001), 4) + accuracy_medium = round(float(0.0000001), 7) + accuracy_high = round(float(0.0000000001), 10) + + accuracy_list = [['accuracy_low', accuracy_low], + ['accuracy_medium', accuracy_medium], + ['accuracy_high', accuracy_high]] + + ''' open and read parameter from unicado_workflow_conf.xml configuration file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/unicado_workflow_conf.xml' + root_of_workflow_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'unicado_workflow', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # try to read configuration parameter from imported element tree + try: + frame_info = getframeinfo(currentframe()) + aircraft_exchange_file = root_of_workflow_tree.find("./control_settings/aircraft_exchange_file_name/value").text + aircraft_project = aircraft_exchange_file[0:len(aircraft_exchange_file) - 4] + aircraft_exchange_directory = root_of_workflow_tree.find( + "./control_settings/aircraft_exchange_file_directory/value").text + aircraft_exchange_directory = aircraft_exchange_directory.replace(os.sep, '/') + path_to_project = aircraft_exchange_directory + aircraft_type = path_to_project + # check if the given aircraft type string have a "/" on his end + # -> if true: -> cut the last character from string + if aircraft_type[-1] == '/': + aircraft_type = aircraft_type[:-1] + # find the positions of the last "/" and "-" in given string + ind = aircraft_type.rfind('/') + ind2 = aircraft_type.rfind('-') + # extract aircraft type of current project from given string + aircraft_type = aircraft_type[ind+1:ind2] + # check if the given project path starts with '..' + # -> if true: -> cut the first to characters and set the correct path to project + corrected_path_is_absolute, corrected_path = path_check(aircraft_exchange_directory) + if corrected_path_is_absolute: + path_to_project = corrected_path + else: + path_to_project = path_of_working_directory + corrected_path + + convert_mode_to_int_dict = { + 'mode_0' : int(0), + 'mode_1' : int(1), + 'mode_2' : int(2), + 'mode_3' : int(3), + 'mode_4' : int(4), + 'mode_5' : int(5) + } + + ''' read global control settings ''' + plot_output_on = int(root_of_workflow_tree.find( + "./control_settings/plot_output/enable/value").text.lower() in ['true', 'True', '1', 't']) + switch_off_plots = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/iteration_settings/" + "switch_off_plots/value").text.lower() in ['true', 'True', '1', 't']) + report_output_on = int(root_of_workflow_tree.find( + "./control_settings/report_output/value").text.lower() in ['true', 'True', '1', 't']) + switch_off_reports = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/iteration_settings/" + "switch_off_html_report/value").text.lower() in ['true', 'True', '1', 't']) + tex_report_on = int(root_of_workflow_tree.find( + "./control_settings/tex_report/value").text.lower() in ['true', 'True', '1', 't']) + switch_off_tex = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/iteration_settings/" + "switch_off_tex_report/value").text.lower() in ['true', 'True', '1', 't']) + console_output_on = convert_mode_to_int_dict[root_of_workflow_tree.find( + "./control_settings/console_output/value").text] + logfile_output_on = convert_mode_to_int_dict[root_of_workflow_tree.find( + "./control_settings/log_file_output/value").text] + write_info_files = int(root_of_workflow_tree.find( + "./control_settings/write_info_files/value").text.lower() in ['true', 'True', '1', 't']) + write_info_files_only_at_last_step_of_iteration = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/iteration_settings/" + "switch_off_info_files/value").text.lower() in ['true', 'True', '1', 't']) + inkscape_path = root_of_workflow_tree.find( + "./control_settings/inkscape_path/value").text + gnuplot_path = root_of_workflow_tree.find( + "./control_settings/gnuplot_path/value").text + + ''' read program-specific control settings ''' + # program specific pre_workflow_operation_settings + set_to_default_before_run = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/pre_workflow_operation_settings/" + "set_project_folder_to_default/value").text.lower() in ['true', 'True', '1', 't']) + delete_plots_before_run = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/pre_workflow_operation_settings/" + "delete_plots_before_run/value").text.lower() in ['true', 'True', '1', 't']) + delete_engines_before_run = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/pre_workflow_operation_settings/" + "delete_engines_before_run/value").text.lower() in ['true', 'True', '1', 't']) + clear_old_log_files_at_start = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/pre_workflow_operation_settings/" + "clear_old_log_files_before_run/value").text.lower() in ['true', 'True', '1', 't']) + + # program specific iteration_settings + check_settings_for_design_logic = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/iteration_settings/" + "check_settings_for_design_logic/value").text.lower() in ['true', 'True', '1', 't']) + use_control_settings_for_sub_programs = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/iteration_settings/" + "use_control_settings_for_subprograms/value").text.lower() in ['true', 'True', '1', 't']) + use_range_type_specific_factors = convert_mode_to_int_dict[root_of_workflow_tree.find( + "./control_settings/program_specific_settings/iteration_settings/" + "use_range_type_specific_factors/value").text] + use_configs_from_existing_project = convert_mode_to_int_dict[root_of_workflow_tree.find( + "./control_settings/program_specific_settings/iteration_settings/" + "use_configs_from_existing_project/config_copy_mode/value").text] + use_engine_from_existing_project = convert_mode_to_int_dict[root_of_workflow_tree.find( + "./control_settings/program_specific_settings/iteration_settings/" + "use_engine_from_existing_project/engine_copy_mode/value").text] + save_acft_xml_after_each_iteration = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/iteration_settings/" + "save_aircraft_exchange_files_to_result_folder/value").text.lower() in ['true', 'True', '1', 't']) + + # program specific post_workflow_operation_settings + save_configs_to_result_folder = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/post_workflow_operation_settings/" + "save_configs_to_result_folder/value").text.lower() in ['true', 'True', '1', 't']) + save_log_files_to_result_folder = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/post_workflow_operation_settings/" + "save_log_files_to_result_folder/value").text.lower() in ['true', 'True', '1', 't']) + save_acft_xml_to_result_folder = int(root_of_workflow_tree.find( + "./control_settings/program_specific_settings/post_workflow_operation_settings/" + "save_final_aircraft_exchange_file_to_result_folder/value").text.lower() in ['true', 'True', '1', 't']) + + ''' create table for control settings ''' + control_settings = [['delete_plots_before_run', delete_plots_before_run], + ['delete_engines_before_run', delete_engines_before_run], + ['clear_old_log_files_at_start', clear_old_log_files_at_start], + ['plot_output_on', plot_output_on], + ['switch_off_plots', switch_off_plots], + ['report_output_on', report_output_on], + ['switch_off_reports', switch_off_reports], + ['tex_report_on', tex_report_on], + ['switch_off_tex', switch_off_tex], + ['status_flag_to_skip_design_sizing', int(0)], + ['status_flag_to_skip_study_mission', int(0)], + ['check_settings_for_design_logic', check_settings_for_design_logic], + ['use_control_settings_for_sub_programs', use_control_settings_for_sub_programs], + ['use_range_type_specific_factors', use_range_type_specific_factors], + ['use_configs_from_existing_project', use_configs_from_existing_project], + ['use_engine_from_existing_project', use_engine_from_existing_project], + ['save_configs_to_result_folder', save_configs_to_result_folder], + ['save_log_files_to_result_folder', save_log_files_to_result_folder], + ['save_acft_xml_to_result_folder', save_acft_xml_to_result_folder], + ['save_acft_xml_after_each_iteration', save_acft_xml_after_each_iteration], + ['write_info_files', write_info_files], + ['write_info_files_only_at_last_step_of_iteration', + write_info_files_only_at_last_step_of_iteration]] + + ''' read program specific settings - program execution mode ''' + # Read global program mode (either standard design / parameter_study / optimization) + program_mode = convert_mode_to_int_dict[root_of_workflow_tree.find( + "./program_settings/program_mode/value").text] + if program_mode == 0: + program_mode = "standard_aircraft_design" + elif program_mode == 1: + program_mode = "parameter_study" + else: + program_mode = "optimization" + + ''' read program specific settings - parameter for design case ''' + design_mode = convert_mode_to_int_dict[root_of_workflow_tree.find( + "./program_settings/design_case_settings/design_mode/value").text] + automatic_trim = int(0) + convergence_criteria = float(root_of_workflow_tree.find( + "./program_settings/design_case_settings/iteration_settings/" + "convergence_criteria/value").text) + number_of_max_iteration = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/iteration_settings/" + "max_number_of_iterations_before_exit/value").text) + bridge_constraint_analyzer = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/iteration_settings/" + "bridge_constraint_analyzer/value").text.lower() in ['true', 'True', '1', 't']) + damp_mtom_iteration = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/iteration_settings/" + "damp_MTOM_during_iteration/value").text.lower() in ['true', 'True', '1', 't']) + parallel_execution = int(root_of_workflow_tree.find( + "./program_settings/design_case_settings/parallel_execution").text.lower() in ['true', 'True', '1', 't']) + + ''' create table for design case parameter ''' + parameter_for_design_case = [['program_mode', program_mode], + ['design_mode', design_mode], + ['automatic_trim', automatic_trim], + ['convergence_criteria', convergence_criteria], + ['number_of_max_iteration', number_of_max_iteration], + ['bridge_constraint_analyzer', bridge_constraint_analyzer], + ['damp_mtom_iteration', damp_mtom_iteration], + ['parallel_execution', parallel_execution], + ['count_of_iteration', int(0)], + ['count_of_mission_study_loop', int(0)]] + + # design case calibration + calibration_settings = read_calibration_parameter(root_of_workflow_tree) + + # exception handling if read of configuration parameter failed -> raise an error and abort program + except OSError: + frame_info_end = getframeinfo(currentframe()) + print('Error in file: set_configuration_parameter.py \n In line: ' + str(frame_info.lineno) + ' to ' + + str(frame_info_end.lineno - 3) + ' \n Read configuration parameter from imported element tree failed!' + ' \n Program aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error in file: set_configuration_parameter.py \n In line: ' + str(frame_info.lineno) + + ' to ' + str(frame_info_end.lineno - 3) + + ' \n Read configuration parameter from imported element tree failed! \n Program aborted!') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + sys.exit(1) + + # execute operations for initial settings + ''' create project folder if not exist ''' + module_list_of_sizing_loop = [] + # project directory does not exist + if not os.path.isdir(path_to_project): + if os.path.isdir(path_to_aircraft_projects + aircraft_type + '/' + aircraft_project): + while_count = 0 + while True: + try: + shutil.copytree(path_to_aircraft_projects + aircraft_type + '/' + aircraft_project, path_to_project) + print('Working copy of aircraft project ' + aircraft_project + + ' has been successfully created in the working directory!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Working copy of aircraft project ' + aircraft_project + + ' has been successfully created in the working directory!') + break + except OSError: + if while_count == 10: + print('Warning: Working copy of aircraft project ' + aircraft_project + + ' could not be created in the working directory!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning: Working copy of aircraft project ' + aircraft_project + + ' could not be created in the working directory!') + break + while_count += 1 + print('Warning: Try to copy of aircraft project ' + aircraft_project + + ' to the temporary working directory, but no response from the system.') + print('Retry ' + str(while_count) + ' of 10!') + time.sleep(3) + + # repository folder not found -> project could not be created -> abort program + else: + print('Error: Working copy of aircraft project ' + aircraft_project + + ' could not be created, no repository folder found! \n Program aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: Working copy of aircraft project ' + aircraft_project + + ' could not be created, no repository folder found! \n Program aborted!') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + sys.exit(1) + + elif set_to_default_before_run: + content_list_of_project_folder = os.listdir(path_to_project) + starting_file = aircraft_project + '_start.xml' + cpacs_file = aircraft_project + '_CPACS.xml' + for element in content_list_of_project_folder: + # delete current file from project folder + element_flag = False + while_count = 0 + while True: + if os.path.isfile(path_to_project + element) and not element == starting_file \ + and not element == cpacs_file: + try: + os.remove(path_to_project + element) + element_flag = True + break + except OSError: + if while_count == 10: + print('Warning: Reset of old project files failed. Delete operation is skipped') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning: Reset of old project files failed. Delete operation ' + 'is skipped') + break + while_count += 1 + print('Warning: Try to reset old project files, but no response from the system!') + print('Retry ' + str(while_count) + ' of 10!') + time.sleep(3) + else: + break + + # delete current folder from project folder + while_count = 0 + while True: + if os.path.isdir(path_to_project + element) and not element == 'cleanSheetDesign' \ + and not element == 'retrofitDesign': + try: + shutil.rmtree(path_to_project + element) + element_flag = True + break + except OSError: + if while_count == 10: + print('Warning: Delete of old project directories failed. Delete operation is skipped') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning: Delete of old project directories failed. Delete operation ' + 'is skipped') + break + while_count += 1 + print('Warning: Try to delete old project directories, but no response from the system!') + print('Retry ' + str(while_count) + ' of 10!') + time.sleep(3) + else: + break + + if element_flag: + print(element + ' has been successfully deleted from project folder!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + element + + ' has been successfully deleted from project folder!') + + else: + print('Current aircraft design project is ' + aircraft_project + '!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Current aircraft design project is ' + aircraft_project + '!') + + ''' copy project file to temporary workflow working directory of current execution ''' + while_count = 0 + directory_of_file_to_copy = str() + while True: + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project): + try: + shutil.copytree(path_to_project, path_of_working_directory_rce + current_workflow_name + '/' + + aircraft_project) + if design_mode == 2: + directory_of_file_to_copy = '/retrofit_design/without_calibration/' + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/clean_sheet_design'): + shutil.rmtree(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/clean_sheet_design') + else: + directory_of_file_to_copy = '/clean_sheet_design/' + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/retrofit_design'): + shutil.rmtree(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/retrofit_design') + ''' check if the the geometry_data directory inside of current workflow folder ''' + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + + aircraft_project + '/geometry_data/existing_component_geometries'): + print('Warning: The existing_component_geometries directory could not be found inside of the geometry_data folder of current project! \n' + ' The use_exisiting_geometry mode of the component sizing tools cannot be executed. Affected modules will raise an error.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning: The existing_component_geometries directory could not be found inside of the geometry_data folder of current project! \n' + ' The use_exisiting_geometry mode of the component sizing tools cannot be executed. Affected modules will raise an error.') + + print('Copy project file to temporary working directory successfully done!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Copy project file to temporary working directory successfully done!') + break + except OSError: + if while_count == 10: + print('Warning: Copy operation of project files to temporary working directory. ' + 'Copy operation is skipped.') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning: Copy operation of project files to temporary working directory.' + ' Copy operation is skipped.') + break + while_count += 1 + print('Warning: Try to copy project files to temporary working directory') + print('Retry ' + str(while_count) + ' of 10!') + time.sleep(3) + else: + break + + # Copy operating company xml file to temporary working directory. + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + directory_of_file_to_copy + 'operating_company.xml'): + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + directory_of_file_to_copy + 'operating_company.xml', + path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/operating_company.xml') + else: + print('Warning: The file operating_company.xml could not be found, ' + 'it is created by the Emissions module itself.') + + # Copy scenario xml file to temporary working directory. + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + directory_of_file_to_copy + 'scenario.xml'): + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + directory_of_file_to_copy + 'scenario.xml', + path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/scenario.xml') + else: + print('Warning: The file scenario.xml could not be found, ' + 'it is created by the Emissions module itself.') + + ''' path to temporary aircraft exchange files of sizing loop ''' + path_of_aircraft_exchange_files = path_of_working_directory_rce + current_workflow_name \ + + '/temporaryResults/config_files/preExecution/' + if not os.path.isdir(path_of_aircraft_exchange_files): + os.makedirs(path_of_aircraft_exchange_files) + # create results folder for configuration files + if not os.path.isdir(path_of_aircraft_exchange_files + 'setup/'): + os.mkdir(path_of_aircraft_exchange_files + 'setup/') + if not os.path.isdir(path_of_aircraft_exchange_files + 'sizingLoop/'): + os.mkdir(path_of_aircraft_exchange_files + 'sizingLoop/') + if not os.path.isdir(path_of_aircraft_exchange_files + 'postProcessing/'): + os.mkdir(path_of_aircraft_exchange_files + 'postProcessing/') + + # read tool list of used design modules + status_flag = False + list_of_json_tools = os.listdir(path_to_json_files) + + ''' check if configuration files from clean sheet folder or from calibrated engine folder are to be used ''' + # configuration files from clean sheet folder are to be used + if not use_configs_from_existing_project == 0: + # call function to use engine from existing project + status_flag, log_file_list = select_configuration_files_from_existing_project(path_of_working_directory_rce, + path_of_working_directory, + path_to_aircraft_projects, + aircraft_project, + aircraft_type, + use_configs_from_existing_project, + log_file_list, + current_workflow_name) + + ''' create list of files in working directory ''' + files_in_working_directory = os.listdir(path_of_working_directory) + # loop for all elements in list of files + for file_name in files_in_working_directory: + # set skipping flag of initial_sizing to false -> if retrofit mode is selected, + # the flag is set to true in the following lines of code to skip initial_sizing + skip_initial_sizing_flag = False + # check if current list element not 'workingDirectoryRCE' or 'workflowResults', then save configuration xml + if not (file_name == 'workingDirectoryRCE') and not (file_name == 'workflowResults') \ + and not (file_name == 'projects'): + # check if current list element is a directory + if os.path.isdir(path_of_working_directory + file_name): + xml_file_name = file_name + '/' + file_name + '_conf.xml' + # check whether a configuration xml file exists within the current list element + if os.path.isfile(path_of_working_directory + xml_file_name): + # copy tool configuration file to temporary working workflow directory of current execution + if not status_flag and global_loop_counter == 1: + while_count = 0 + while True: + try: + shutil.copyfile(path_of_working_directory + xml_file_name, + path_of_working_directory_rce + current_workflow_name + '/' + file_name + + '_conf.xml') + if file_name == 'fuselage_design': + shutil.copytree(path_of_working_directory + '/' + file_name + '/fuselage_design_lib', + path_of_working_directory_rce + current_workflow_name + + '/fuselage_design_lib') + if file_name == 'landing_gear_design': + shutil.copytree(path_of_working_directory + '/' + file_name + '/landing_gear_lib', + path_of_working_directory_rce + current_workflow_name + + '/landing_gear_lib') + if file_name == 'aerodynamic_analysis': + shutil.copyfile(path_of_working_directory + '/' + file_name + '/' + + 'LiftingLine/liftingLine_conf.xml', + path_of_working_directory_rce + + current_workflow_name + + '/' + 'liftingLine_conf.xml') + if file_name == 'cpacs_interface': + shutil.copyfile(path_of_working_directory + '/' + file_name + '/' + + 'convertUNICADO2CPACS/convertUNICADO2CPACS_conf.xml', + path_of_working_directory_rce + + current_workflow_name + + '/' + 'convertUNICADO2CPACS_conf.xml') + break + + # exception handling or copy of module configuration files + except OSError: + if while_count == 10: + print('Warning: Copy of ' + file_name + ' configuration file to temporary working ' + 'failed. Copy operation is skipped') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning: Copy of ' + file_name + ' configuration file to ' + 'temporary working failed. Copy operation is skipped') + break + while_count += 1 + print('Warning: Try to copy ' + file_name + ' configuration file to temporary working ' + 'directory') + print('Retry ' + str(while_count) + ' of 10!') + time.sleep(3) + + # copy tool configuration file to config files/preExecution folder in temporary working workflow directory of current execution + module_list_of_sizing_loop.append(['sizing_loop_module', file_name]) + # read group name of module from json file + for json_tool in list_of_json_tools: + if json_tool == file_name: + frame_info = getframeinfo(currentframe()) + while_count = 0 + while True: + if os.path.isfile(path_to_json_files + file_name + '/configuration.json'): + try: + with open(path_to_json_files + file_name + '/configuration.json', 'r') as file: + json_tree = json.loads(file.read()) + group_name = json_tree['groupName'] + file.close() + # copy current configuration file of list element to temporary working results + if group_name == 'preSizing': + if not design_mode == 2: + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/' + + file_name + '_conf.xml', + path_of_aircraft_exchange_files + 'setup/' + + file_name + '_conf.xml') + else: + if not file_name == 'initial_sizing': + shutil.copy(path_of_working_directory_rce + current_workflow_name + + '/' + file_name + '_conf.xml', + path_of_aircraft_exchange_files + 'setup/' + + file_name + '_conf.xml') + else: + # the flag is set to true to skip initial_sizing + skip_initial_sizing_flag = True + + elif group_name == 'sizingLoop' or group_name == 'visualization': + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/' + + file_name + '_conf.xml', + path_of_aircraft_exchange_files + 'sizingLoop/' + + file_name + '_conf.xml') + if file_name == 'aerodynamic_analysis': + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/liftingLine_conf.xml'): + shutil.copy(path_of_working_directory_rce + current_workflow_name + + '/liftingLine_conf.xml', + path_of_aircraft_exchange_files + 'sizingLoop/' + + 'liftingLine_conf.xml') + if file_name == 'cpacs_interface': + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/convertUNICADO2CPACS_conf.xml'): + shutil.copy(path_of_working_directory_rce + current_workflow_name + + '/convertUNICADO2CPACS_conf.xml', + path_of_aircraft_exchange_files + 'sizingLoop/' + + 'convertUNICADO2CPACS_conf.xml') + + elif group_name == 'postProcessing': + shutil.copy(path_of_working_directory_rce + current_workflow_name + '/' + + file_name + '_conf.xml', + path_of_aircraft_exchange_files + 'postProcessing/' + + file_name + '_conf.xml') + break + # exception handling or copy of module configuration files + except OSError: + if while_count == 10: + print('Warning: Copy of ' + file_name + ' configuration file to temporary ' + 'working failed. Copy operation is skipped') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Warning: Copy of ' + file_name + + ' configuration file to temporary working failed.' + ' Copy operation is skipped') + break + while_count += 1 + print('Warning: Try to copy ' + file_name + ' configuration file to temporary ' + 'working directory') + print('Retry ' + str(while_count) + ' of 10!') + time.sleep(3) + + # Else condition: -> json file does not exist + # -> raise an error and skip copy of current module configuration file + else: + frame_info_end = getframeinfo(currentframe()) + print('Error in file: set_configuration_parameter.py \n In line: ' + + str(frame_info.lineno) + 'to ' + str(frame_info_end.lineno - 3) + + ' \n Read configuration.json file of module: ' + file_name + ' failed! \n ' + + file_name + 'configuration file could not be copied to results!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Error in file: set_configuration_parameter.py ' + '\n In line: ' + str(frame_info.lineno) + 'to ' + + str(frame_info_end.lineno - 3) + + ' \n Read configuration.json file of module: ' + file_name + + ' failed! \n ' + file_name + + 'configuration file could not be copied to results!') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, + log_file_list) + break + + # check if retrofit design is selected + # -> if true: -> skipp set parameter to initial_sizing configuration file + file_name_list = [] + if not skip_initial_sizing_flag and not file_name == "cpacs_interface": + file_name_list.append(file_name) + if file_name == 'cpacs_interface': + file_name_list.append('convertUNICADO2CPACS') + for f_name in file_name_list: + # try to open module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + f_name + '_conf.xml' + file_name_tree_root, xml_tree = read_xml_file(path, path_of_working_directory_rce, f_name, + function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + # set aircraftExchangeFile to aircraft_exchange_file_name/value and aircraftExchangeDirectory + # to aircraft_exchange_file_directory/value of configuration file of current list element + file_name_tree_root.find('./control_settings/aircraft_exchange_file_name/value').text = \ + aircraft_exchange_file + file_name_tree_root.find('./control_settings/aircraft_exchange_file_directory/value').text = \ + path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + + # set paths for log files and plt files to module configuration files + file_name_tree_root.find('./control_settings/log_file/value').text = path_of_working_directory_rce \ + + current_workflow_name + '/' + f_name + '.log' + + # check if control settings for sub programs is true + if use_control_settings_for_sub_programs == 1: + convert_mode_to_int_dict = { + "0" : 'mode_0', + "1" : 'mode_1', + "2" : 'mode_2', + "3" : 'mode_3', + "4" : 'mode_4', + "5" : 'mode_5' + } + + # set switches for report and plot generation for modules of sizing loops + file_name_tree_root.find('./control_settings/console_output/value').text = \ + str(convert_mode_to_int_dict[str(console_output_on)]) + file_name_tree_root.find('./control_settings/log_file_output/value').text = \ + str(convert_mode_to_int_dict[str(logfile_output_on)]) + file_name_tree_root.find('./control_settings/plot_output/enable/value').text = \ + str(bool(plot_output_on)).lower() + file_name_tree_root.find('./control_settings/report_output/value').text = \ + str(bool(report_output_on)).lower() + file_name_tree_root.find('./control_settings/tex_report/value').text = \ + str(bool(tex_report_on)).lower() + + # check if write info files is enabled + # -> if true: -> enable write info files in all submodules + if write_info_files == 1 and write_info_files_only_at_last_step_of_iteration == 0: + file_name_tree_root.find('./control_settings/write_info_files/value').text = \ + str(bool(1)).lower() + elif write_info_files == 1 and write_info_files_only_at_last_step_of_iteration == 1: + file_name_tree_root.find('./control_settings/write_info_files/value').text = \ + str(bool(0)).lower() + if f_name == 'initial_sizing' \ + and write_info_files_only_at_last_step_of_iteration == 1: + file_name_tree_root.find('./control_settings/write_info_files/value').text = \ + str(bool(1)).lower() + print('Switch of WriteInfoFile only for last step of iteration in ' + + f_name + '_conf.xml successfully set to active!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Switch of WriteInfoFile only for last step of' + ' iteration in ' + f_name + '_conf.xml successfully set' + ' to active!') + elif write_info_files == 0: + file_name_tree_root.find('./control_settings/write_info_files/value').text = \ + str(bool(0)).lower() + file_name_tree_root.find('./control_settings/inkscape_path/value').text = inkscape_path + file_name_tree_root.find('./control_settings/gnuplot_path/value').text = gnuplot_path + + if f_name == 'cpacs_interface': + cpacs_file_name = aircraft_exchange_file[:-4] + '_CPACS.xml' + file_name_tree_root.find( + './control_settings/program_specific/cpacs_filename').text = cpacs_file_name + file_name_tree_root.find( + './control_settings/program_specific/cpacs_dir').text = path_of_working_directory_rce \ + + current_workflow_name + '/' + aircraft_project + '/' + + # write settings to configuration xml file + xml_tree.write(path, encoding='utf-8') + + # check if old log-files should be cleared + if clear_old_log_files_at_start == 1: + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + file_name + '.log'): + os.remove(path_of_working_directory_rce + current_workflow_name + '/' + file_name + '.log') + + ''' check if old plots and reports should be deleted ''' + if delete_plots_before_run == 1: + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/reporting'): + recursive_data_remove(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/reporting') + print('Old reporting data has been successfully deleted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Old reporting data has been successfully deleted!') + + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/plots'): + recursive_data_remove(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/plots') + print('Old plots has been successfully deleted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Old plots has been successfully deleted!') + + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/report_html'): + recursive_data_remove(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/report_html') + print('Old html reports has been successfully deleted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Old html reports has been successfully deleted!') + + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/report_tex'): + recursive_data_remove(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/report_tex') + print('Old TeX reports has been successfully deleted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Old TeX reports has been successfully deleted!') + + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/csvFilesForPlots'): + recursive_data_remove(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/csvFilesForPlots') + print('Old csv files for plots has been successfully deleted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Old csv files for plots has been successfully deleted!') + + ''' check if old engines should be deleted; this should not be done for design_mode 3''' + if delete_engines_before_run == 1 and not design_mode == 3: + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/engine_data'): + recursive_data_remove(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/engine_data') + print('Old engine data has been successfully deleted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Old engine data has been successfully deleted!') + + ''' check if engine from existing project should be used ''' + if not use_engine_from_existing_project == 0: + # call function to use engine from existing project + _, sparse_checkout_flag, folder_name, log_file_list = \ + select_engine_from_existing_project(path_of_working_directory_rce, + path_to_aircraft_projects, + aircraft_exchange_file, + aircraft_type, + aircraft_project, + use_engine_from_existing_project, + log_file_list, + current_workflow_name) + + # set parameter of used engine to propulsion_design configuration file + if not sparse_checkout_flag: + print('Warning: Engine data could not found in ' + folder_name + + ' folder! \n Current engine data will be used!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + 'Warning: Engine data could not found in ' + folder_name + + ' folder! \n Current engine data will be used!') + + ''' extend table for paths and names ''' + paths_and_names.append(['aircraft_exchange_directory', aircraft_exchange_directory]) + paths_and_names.append(['aircraft_exchange_file', aircraft_exchange_file]) + paths_and_names.append(['aircraft_project', aircraft_project]) + paths_and_names.append(['path_to_project', path_to_project]) + paths_and_names.append(['aircraft_type', aircraft_type]) + + print('All configuration parameters for the aircraft design process successfully set!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'All configuration parameters for the aircraft design process successfully set!') + + ''' write log-file to system ''' + log_file_list.append('****************************************** end set configuration parameter ' + '******************************************') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + + return accuracy_list, control_settings, parameter_for_design_case, paths_and_names, calibration_settings,\ + module_list_of_sizing_loop diff --git a/UNICADOworkflow/src/pre_condition/set_range_type_specific_factors.py b/UNICADOworkflow/src/pre_condition/set_range_type_specific_factors.py new file mode 100644 index 0000000000000000000000000000000000000000..c1dce3398156463e62bb9f2ae57225eb94817d7d --- /dev/null +++ b/UNICADOworkflow/src/pre_condition/set_range_type_specific_factors.py @@ -0,0 +1,142 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def set_range_type_specific_factors(paths_and_names, range_type_specific_factors, scenario_range, log_file_list): + """ set_range_type_specific_factors sets scenario range dependent parameters to module configuration files. + + The input list of lists "paths_and_names" contains the following values: + * [0][0] string: 'path_to_python_scripts', [0][1] string: 'the system path to python scripts' + * [1][0] string: 'path_of_working_directory', [1][1] string: 'the system path of working directory' + * [2][0] string: 'path_of_working_directory_rce', [2][1] string: 'the system path of working directory for rce' + * [3][0] string: 'path_of_origin_tool_directory', [3][1] string: 'the system path to the root directory of UNICADO repositories' + * [4][0] string: 'current_workflow_name', [4][1] string: 'workflow name of the current workflow execution' + * [5][0] string: 'path_to_aircraft_projects', [5][1] string: 'the system path to the repository of aircraft design projects' + * [6][0] string: 'path_to_aircraft_design_tools', [6][1] string: 'the system path to the repository of aircraft design tools' + * [7][0] string: 'path_to_software_tools', [7][1] string: 'the system path to the repository of software tools' + * [8][0] string: 'path_to_json_files', [8][1] string: 'the path to module json files in .rce system folder' + * [9][0] string: 'aircraft_exchange_directory', [9][1] string: 'name of the directory, witch contains the current aircraft project' + * [10][0] string: 'aircraft_exchange_file', [10][1] string: 'name of the current used aircraft exchange file' + * [11][0] string: 'aircraft_project', [11][1] string: 'name of the aircraft project, which ist currently designed' + * [12][0] string: 'path_to_project', [12][1] string: 'the system path to current project folder' + * [13][0] string: 'aircraft_type', [13][1] string: 'name of aircraft type' + + The input elementTree "range_type_specific_factors" contains the data from range_type_specific_factors.xml file. + + The input string "scenario_range" contains the name of range scenario. + + The input list "log_file_list" contains the log file data from caller function + + :param: paths_and_names: input list of lists + :param: range_type_specific_factors: input elementTree + :param: scenario_range: input string + :param: log_file_list: input list + :return: status_flag: output bool, log_file_list: output list + """ + + ''' imports for python ''' + from datetime import datetime + from inspect import currentframe, getframeinfo + from sub_function.read_xml_file import read_xml_file + + ''' read data for script execution ''' + current_workflow_name = ([item for item in paths_and_names if 'current_workflow_name' in item])[-1][-1] + path_of_working_directory_rce =\ + ([item for item in paths_and_names if 'path_of_working_directory_rce' in item])[-1][-1] + + ''' initialize local parameter''' + function_name = getframeinfo(currentframe()).function + + ''' loop across all elements in range_type_specific_factors elementTree to read and set module config parameter ''' + for elements in range_type_specific_factors: + ''' initialize private loop parameter ''' + i = 1 + name_of_module = str(elements.tag) + number_of_factors = int(range_type_specific_factors.find('./' + name_of_module + '/number_of_factors').text) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Set ' + str(number_of_factors) + + ' range dependent parameter in module: ' + name_of_module) + print('Set ' + str(number_of_factors) + ' range dependent parameter in module: ' + name_of_module) + + ''' call function to read module configuration file as elementTree ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + name_of_module + '_conf.xml' + root_of_design_tool, xml_tree = read_xml_file(path, path_of_working_directory_rce, + name_of_module, function_name, frame_info.lineno, + log_file_list, current_workflow_name) + + ''' loop across all factors of current design module ''' + while i <= number_of_factors: + # read current path of parameter from range type specific factors xml-file + path_to_parameter = str(range_type_specific_factors.find("./" + name_of_module + "/factor[" + "@ID='" + + str(i) + "'" + "]/path").text) + + # check if the current path of parameter starts with a slash + index_of_slash = path_to_parameter.find('/') + if index_of_slash == 0: + path_to_parameter = path_to_parameter[1:] + + # check if the string 'module_configuration_file' exist in current path of parameter + index_of_cfg = path_to_parameter.find('module_configuration_file') + if index_of_cfg > -1: + path_to_parameter = path_to_parameter[index_of_cfg + 11:] + + # check if the string '@' exist in current path of parameter + index_of_at = path_to_parameter.find('@') + if index_of_at > -1: + path_part_one = path_to_parameter[:index_of_at] + path_part_two = path_to_parameter[index_of_at:] + + # check if the string '=' exist in current path of parameter + index_of_equal = path_part_two.find('=') + if index_of_equal > -1: + # check if the string '/' exist in the second part of path of parameter + index_of_new_slash = path_part_two.find('/') + if index_of_new_slash > -1: + value_of_id = path_part_two[index_of_equal+1:index_of_new_slash] + path_part_tree = path_part_two[index_of_new_slash:] + path_to_parameter = './' + path_part_one + '[' + path_part_two[:index_of_equal+1] + "'" \ + + str(value_of_id) + "'" + ']' + path_part_tree + + else: + value_of_id = path_part_two[index_of_equal+1:] + path_to_parameter = './' + path_part_one + '[' + path_part_two[:index_of_equal+1] + "'" \ + + str(value_of_id) + "'" + ']' + + log_file_list.append('Path to parameter: ' + path_to_parameter) + print('Path to parameter: ' + path_to_parameter) + + # read range type specific factor of current module from elementTree + value_of_cfg_file = str(range_type_specific_factors.find("./" + name_of_module + "/factor[" + "@ID='" + + str(i) + "'" + "]/value/" + scenario_range).text) + + # set range type specific factor to module configuration file + root_of_design_tool.find(path_to_parameter).text = str(value_of_cfg_file) + xml_tree.write(path_of_working_directory_rce + current_workflow_name + '/' + + name_of_module + '_conf.xml', encoding='utf-8') + + log_file_list.append('Set parameter value to: ' + str(value_of_cfg_file)) + print('Set parameter value to: ' + str(value_of_cfg_file)) + + ''' add +1 to iteration counter ''' + i += 1 + + log_file_list.append(' ') + print('') + + return log_file_list diff --git a/UNICADOworkflow/src/sub_function/auto_update_additional_software.py b/UNICADOworkflow/src/sub_function/auto_update_additional_software.py new file mode 100644 index 0000000000000000000000000000000000000000..0ca40e48389eb18f0b24b301dd1edd43925c3904 --- /dev/null +++ b/UNICADOworkflow/src/sub_function/auto_update_additional_software.py @@ -0,0 +1,122 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def auto_update_additional_software(path_of_working_directory, path_to_origin, file_name, config_back_up_flag, + log_file_list): + """ Function to auto update the additional software tools in the UNICADO working directory. + + The input string "path_of_working_directory" contains the absolute path to installed working directory of + UNICADO. + + The input string "path_to_origin" contains the absolute system path to the repository of additional software. + + The input string "fileName" contains the folder name of aircraft projects. + + The input bool "config_back_up_flag" contains the status whether the configuration files of the modules have to + be backup. + + The input list "log_file_list" contains all system prints of function "set_configuration_parameter.py". + + The output list "log_file_list" contains all system prints of function "set_configuration_parameter.py" and + "auto_update_additional_software.py". + + :param: path_of_working_directory: input string + :param: path_to_origin: input string + :param: file_name: input string + :param: config_back_up_flag: input bool + :param: log_file_list: input list + :return: log_file_list: output list + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + + # check for origin tool data and update only this files in working directory + if os.path.isdir(path_to_origin + file_name): + files_in_origin_tool_directory = os.listdir(path_to_origin + file_name) + + for data in files_in_origin_tool_directory: + # check if data a file, then replace with file from origin tool directory + if os.path.isfile(path_of_working_directory + file_name + '/' + data): + # check if current file the module configuration file and switch for back-up of configuration files + # is true, then create back-up copy in working directory of module + if data == file_name + '_conf.xml' and config_back_up_flag: + shutil.copyfile(path_of_working_directory + file_name + '/' + data, + path_of_working_directory + file_name + '/' + file_name + '_backUp_conf.xml') + + os.remove(path_of_working_directory + file_name + '/' + data) + shutil.copyfile(path_to_origin + file_name + '/' + data, + path_of_working_directory + file_name + '/' + data) + + # check if data a directory, then replace with directory from origin tool directory + if os.path.isdir(path_of_working_directory + file_name + '/' + data): + shutil.rmtree(path_of_working_directory + file_name + '/' + data) + # check if data is not equal to src or convertUNICADO2CPACS + # -> if true: -> copy data from origin to working directory + if not data == 'src' and not data == 'convertUNICADO2CPACS': + shutil.copytree(path_to_origin + file_name + '/' + data, + path_of_working_directory + file_name + '/' + data) + # check if data is equal to convertUNICADO2CPACS + # -> if true: -> copy all content inside the origin directory out of the src directory to working copy + if data == 'convertUNICADO2CPACS': + data_inside = os.listdir(path_to_origin + file_name + '/' + data) + os.mkdir(path_of_working_directory + file_name + '/' + data) + for element in data_inside: + if not element == 'src': + if os.path.isfile(path_to_origin + file_name + '/' + data + '/' + element): + shutil.copyfile(path_to_origin + file_name + '/' + data + '/' + element, + path_of_working_directory + file_name + '/' + data + '/' + element) + else: + shutil.copytree(path_to_origin + file_name + '/' + data + '/' + element, + path_of_working_directory + file_name + '/' + data + '/' + element) + + # check if data exist in working directory, if not, then copy data to working directory + if not os.path.exists(path_of_working_directory + file_name + '/' + data): + if os.path.isfile(path_to_origin + file_name + '/' + data): + shutil.copyfile(path_to_origin + file_name + '/' + data, + path_of_working_directory + file_name + '/' + data) + # check if data a directory, then replace with directory from origin tool directory + if os.path.isdir(path_to_origin + file_name + '/' + data): + # check if data is not equal to src or convertUNICADO2CPACS + # -> if true: -> copy data from origin to working directory + if not data == 'src' and not data == 'convertUNICADO2CPACS': + shutil.copytree(path_to_origin + file_name + '/' + data, + path_of_working_directory + file_name + '/' + data) + # check if data is equal to convertUNICADO2CPACS + # -> if true: -> copy all content inside the origin directory out of the src folder to working copy + if data == 'convertUNICADO2CPACS': + data_inside = os.listdir(path_to_origin + file_name + '/' + data) + os.mkdir(path_of_working_directory + file_name + '/' + data) + for element in data_inside: + if not element == 'src': + if os.path.isfile(path_to_origin + file_name + '/' + data + '/' + element): + shutil.copyfile(path_to_origin + file_name + '/' + data + '/' + element, + path_of_working_directory + file_name + '/' + data + '/' + element) + else: + shutil.copytree(path_to_origin + file_name + '/' + data + '/' + element, + path_of_working_directory + file_name + '/' + data + '/' + element) + + print('Working copy of ' + file_name + ' has been successfully updated!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Working copy of ' + file_name + ' has been successfully updated!') + + return log_file_list diff --git a/UNICADOworkflow/src/sub_function/auto_update_design_tools.py b/UNICADOworkflow/src/sub_function/auto_update_design_tools.py new file mode 100644 index 0000000000000000000000000000000000000000..758ffa865b72acf1a36c928da8216174d0a02930 --- /dev/null +++ b/UNICADOworkflow/src/sub_function/auto_update_design_tools.py @@ -0,0 +1,93 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def auto_update_design_tools(path_of_working_directory, path_to_origin, file_name, config_back_up_flag, log_file_list): + """ Function to auto update the aircraft design modules in the UNICADO working directory. + + The input string "path_of_working_directory" contains the absolute path to installed working directory of + UNICADO. + + The input string "path_to_origin" contains the absolute system path to the repository of additional software. + + The input string "fileName" contains the folder name of aircraft projects. + + The input bool "config_back_up_flag" contains the status whether the configuration files of the modules have to + be backup. + + The input list "log_file_list" contains all system prints of function "set_configuration_parameter.py". + + The output list "log_file_list" contains all system prints of function "set_configuration_parameter.py" and + "auto_update_design_tools.py". + + :param: path_of_working_directory: input string + :param: path_to_origin: input string + :param: file_name: input string + :param: config_back_up_flag: input bool + :param: log_file_list: input list + :return: log_file_list: output list + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + + # check for origin tool data and update only this files in working directory + if os.path.isdir(path_to_origin + file_name): + files_in_origin_tool_directory = os.listdir(path_to_origin + file_name) + + for data in files_in_origin_tool_directory: + # check if data a file, then replace with file from origin tool directory + if os.path.isfile(path_of_working_directory + file_name + '/' + data): + # check if current file the module configuration file and switch for back-up of configuration files + # is true, then create back-up copy in working directory of module + if data == file_name + '_conf.xml' and config_back_up_flag: + shutil.copyfile(path_of_working_directory + file_name + '/' + data, + path_of_working_directory + file_name + '/' + file_name + '_backUp_conf.xml') + + os.remove(path_of_working_directory + file_name + '/' + data) + shutil.copyfile(path_to_origin + file_name + '/' + data, + path_of_working_directory + file_name + '/' + data) + + # check if data a directory, then replace with directory from origin tool directory + if os.path.isdir(path_of_working_directory + file_name + '/' + data): + shutil.rmtree(path_of_working_directory + file_name + '/' + data) + # check if data is not equal to src -> if true: -> copy data from origin to working directory + if not data == 'src': + shutil.copytree(path_to_origin + file_name + '/' + data, + path_of_working_directory + file_name + '/' + data) + + # check if data exist in working directory, if not, then copy data to working directory + if not os.path.exists(path_of_working_directory + file_name + '/' + data): + if os.path.isfile(path_to_origin + file_name + '/' + data): + shutil.copyfile(path_to_origin + file_name + '/' + data, + path_of_working_directory + file_name + '/' + data) + + if os.path.isdir(path_to_origin + file_name + '/' + data): + # check if data is not equal to src -> if true: -> copy data from origin to working directory + if not data == 'src': + shutil.copytree(path_to_origin + file_name + '/' + data, + path_of_working_directory + file_name + '/' + data) + + print('Working copy of ' + file_name + ' has been successfully updated!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Working copy of ' + file_name + ' has been successfully updated!') + + return log_file_list diff --git a/UNICADOworkflow/src/sub_function/auto_update_projects_folder.py b/UNICADOworkflow/src/sub_function/auto_update_projects_folder.py new file mode 100644 index 0000000000000000000000000000000000000000..4e3c93b47089516b2b743442d0401f451e1d9e1e --- /dev/null +++ b/UNICADOworkflow/src/sub_function/auto_update_projects_folder.py @@ -0,0 +1,87 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def auto_update_projects_folder(path_of_working_directory, path_to_aircraft_projects, file_name, log_file_list): + """ Function to auto update the aircraft projects folder in UNICADO working directory. + + The input string "path_of_working_directory" contains the absolute path to installed working directory of + UNICADO. + + The input string "path_to_aircraft_projects" contains the absolute system path to the repository of aircraft + design projects. + + The input string "fileName" contains the folder name of aircraft projects. + + The input list "log_file_list" contains all system prints of function "set_configuration_parameter.py". + + The output list "log_file_list" contains all system prints of function "set_configuration_parameter.py" and + "auto_update_projects_folder.py". + + :param: path_of_working_directory: input string + :param: path_to_aircraft_projects: input string + :param: file_name: input string + :param: log_file_list: input list + :return: log_file_list: output list + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + + ''' loop across all existing aircraft projects in current project folder ''' + files_in_origin_reference_directory = os.listdir(path_to_aircraft_projects) + for project in files_in_origin_reference_directory: + if not (project == '.git'): + # check if aircraft reference project exist in projects working directory, + # if not, then copy aircraft reference project to working directory + if not os.path.exists(path_of_working_directory + file_name + '/' + project): + if os.path.isdir(path_to_aircraft_projects + project): + shutil.copytree(path_to_aircraft_projects + project, + path_of_working_directory + file_name + '/' + project) + else: + files_in_origin_reference_project_directory = os.listdir(path_to_aircraft_projects + project) + for data in files_in_origin_reference_project_directory: + # check if data a file, then replace with file from origin tool directory + if os.path.isfile(path_of_working_directory + file_name + '/' + project + '/' + data): + os.remove(path_of_working_directory + file_name + '/' + project + '/' + data) + shutil.copyfile(path_to_aircraft_projects + project + '/' + data, + path_of_working_directory + file_name + '/' + project + '/' + data) + + # check if data a directory, then replace with directory from origin tool directory + if os.path.isdir(path_of_working_directory + file_name + '/' + project + '/' + data): + shutil.rmtree(path_of_working_directory + file_name + '/' + project + '/' + data) + shutil.copytree(path_to_aircraft_projects + project + '/' + data, + path_of_working_directory + file_name + '/' + project + '/' + data) + + # check if data exist in working directory, if not, then copy data to working directory + if not os.path.exists(path_of_working_directory + file_name + '/' + project + '/' + data): + if os.path.isfile(path_to_aircraft_projects + project + '/' + data): + shutil.copyfile(path_to_aircraft_projects + project + '/' + data, + path_of_working_directory + file_name + '/' + project + '/' + data) + if os.path.isdir(path_to_aircraft_projects + project + '/' + data): + shutil.copytree(path_to_aircraft_projects + project + '/' + data, + path_of_working_directory + file_name + '/' + project + '/' + data) + + print('Working copy of ' + file_name + ' folder has been successfully updated!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Working copy of ' + file_name + ' folder has been successfully updated!') + + return log_file_list diff --git a/UNICADOworkflow/src/sub_function/check_for_existing_geometry.py b/UNICADOworkflow/src/sub_function/check_for_existing_geometry.py new file mode 100644 index 0000000000000000000000000000000000000000..e82f2f829a4beab0cb01fcef55a8ad523aeec267 --- /dev/null +++ b/UNICADOworkflow/src/sub_function/check_for_existing_geometry.py @@ -0,0 +1,141 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def check_for_existing_geometry(path_of_working_directory_rce, aircraft_project, file_name, path_to_repository_file, + log_file_list, current_workflow_name='UNICADOworkflow'): + """ checks if the necessary geometry data exist from the aircraft exchange file + + The input string path_of_working_directory_rce contains the system path to the working directory of rce. + + The input string aircraft_project contains the name of the current aircraft project. + + The input string file_name contains the name to the aircraft exchange file of current project. + + The input string path_to_repository_file contains the system path to the aircraft reference repository directory. + + The input list log_file_list contains the strings of workflow log-file from the caller function. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default sting 'UNICADOworkflow' is used. + + The output list log_file_list contains the strings of workflow log-file from the caller function and the added strings from this function. + + :param: path_of_working_directory_rce: input string + :param: aircraft_project: input string + :param: file_name: input string + :param: path_to_repository_file: input string + :param: log_file_list: input list + :param: current_workflow_name: input string + :return: log_file_list: output list + """ + + ''' imports for python ''' + import os + import sys + import shutil + from inspect import currentframe, getframeinfo + from datetime import datetime + from read_xml_file import read_xml_file + from read_geometry_elements import read_geometry_elements + from write_to_log_file import write_to_log_file + + log_file_flag = False + function_name = getframeinfo(currentframe()).function + + ''' check for existing geometry data ''' + # check if the geometry_data directory is inside the project folder + # -> if false: -> copy geometry data from repository folder + if not (os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/geometry_data')): + # check if the geometry_data directory exist in the repository directory + # -> if true: -> copy geometry data to project folder + try: + shutil.copytree(path_to_repository_file + 'geometry_data', + path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/geometry_data') + print('Geometry data successfully copied from repository folder!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Geometry data successfully copied from repository folder!') + log_file_flag = True + + # Exception handling: the geometry_data directory is not existing in the repository directory + # -> raise an error and abort program + except OSError: + print('Error: Geometry data could not be copied, no geometry_data folder found in repository directory! \n ' + 'Program aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: Geometry data could not be copied, no geometry_data folder found in ' + 'repository directory! \n Program aborted!') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + sys.exit(1) + + # Else condition: the geometry_data directory is inside the project folder + # -> check if all necessary geometry elements exist + else: + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + file_name + # call function to read the aircraft exchange file as element tree + root_of_aircraft_exchange_file, xml_tree = read_xml_file(path, path_of_working_directory_rce, file_name, + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # call function to read used geometry elements from given element tree + geometry_name = read_geometry_elements(root_of_aircraft_exchange_file) + + # loop across all used geometry elements to check if they exist inside the geometry data folder + for geometry_entry in geometry_name: + if not os.path.isfile(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/' + geometry_entry): + name_of_missing_file = geometry_entry[geometry_entry.rfind('/') + 1:] + # check if the geometry_data directory exist in the repository directory + # -> if true: -> copy missing geometry data file to project folder + if os.path.isdir(path_to_repository_file + 'geometry_data'): + try: + shutil.copy(path_to_repository_file + geometry_entry, + path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/' + geometry_entry) + print('Missing geometry data file ' + name_of_missing_file + + ' successfully copied from repository folder!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Missing geometry data file ' + name_of_missing_file + + ' successfully copied from repository folder!') + log_file_flag = True + + # Exception handling: the missing geometry data file is not existing in the repository directory + # -> raise an error and abort program + except OSError: + print('Error: Missing geometry data file ' + name_of_missing_file + + ' could not be copied, no such geometry file found in repository directory! \n ' + 'Program aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: Missing geometry data file ' + name_of_missing_file + + ' could not be copied, no such geometry file found in ' + 'repository directory! \n Program aborted!') + + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + sys.exit(1) + + if not log_file_flag: + print('All necessary geometry data files already exist in the geometry_data folder of current project!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'All necessary geometry data files already exist in the geometry_data folder of current ' + 'project!') + + return log_file_list diff --git a/UNICADOworkflow/src/sub_function/get_mission_energy_specific_segment.py b/UNICADOworkflow/src/sub_function/get_mission_energy_specific_segment.py new file mode 100644 index 0000000000000000000000000000000000000000..9fda7a6cddd5e45364fdba5dbb3b5c6586cecef5 --- /dev/null +++ b/UNICADOworkflow/src/sub_function/get_mission_energy_specific_segment.py @@ -0,0 +1,28 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def get_mission_energy_specific_segment(root_of_aircraft_exchange_tree, aMissionType, aMissionSegment): + mission_energy = 0.0 + consumed_mission_energy_components = root_of_aircraft_exchange_tree.findall( + './analysis/mission/' + aMissionType + '/' + aMissionSegment) + for energy_component in consumed_mission_energy_components: + consumed_mission_energy = energy_component.find('./consumed_energy/value') + mission_energy += float(consumed_mission_energy.text) + return mission_energy \ No newline at end of file diff --git a/UNICADOworkflow/src/sub_function/path_check.py b/UNICADOworkflow/src/sub_function/path_check.py new file mode 100644 index 0000000000000000000000000000000000000000..22fd181f168c03a7c953084ef5d1a1a53b0d80b2 --- /dev/null +++ b/UNICADOworkflow/src/sub_function/path_check.py @@ -0,0 +1,53 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def path_check(path_to_check): + """ Function to check if the given input path an absolute or relative path and correct the given path. + + The input string 'path_to_check' contains the string to check if it is an absolute or relative path. + + The output string 'corrected_path' contains the corrected path. + + :param: path_to_check: input string + :return: path_to_check_is_absolute: output bool, corrected_path: output string + """ + ''' imports for python ''' + import os + + # check if the given path starts with '..' + # -> if true: -> cut the first to characters and set the correct absolute path + if path_to_check[:2] == '..': + corrected_path = path_to_check[3:] + # else condition: input path is an absolut path + else: + corrected_path = path_to_check + + # replace all '\' character with '/' to operate on Windows and linux OS + corrected_path = corrected_path.replace(os.sep, '/') + + # check if corrected_path is an absolute path + path_to_check_is_absolute = os.path.isabs(path_to_check) + + # check if the last character of the corrected_path string is a '/' + # -> if not: -> add '/' to the end of corrected_path string + if not corrected_path[-1] == '/': + corrected_path = corrected_path + '/' + + return path_to_check_is_absolute, corrected_path diff --git a/UNICADOworkflow/src/sub_function/prepare_single_mission_analysis.py b/UNICADOworkflow/src/sub_function/prepare_single_mission_analysis.py new file mode 100644 index 0000000000000000000000000000000000000000..b3447eb37b7e963745915f81ff57e03cd2462bbc --- /dev/null +++ b/UNICADOworkflow/src/sub_function/prepare_single_mission_analysis.py @@ -0,0 +1,185 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def prepare_single_mission_analysis(path_of_working_directory_rce, aircraft_project, file_name, log_file_list, + current_workflow_name='UNICADOworkflow'): + """ prepare_single_mission_analysis checks if all necessary files exist to perform a study mission analysis without + design sizing loop. + + The input string path_of_working_directory_rce contains the system path to the working directory of rce. + + The input string aircraft_project contains the name of the current aircraft project. + + The input string file_name contains the name to the aircraft exchange file of current project. + + The input list log_file_list contains the strings of workflow log-file from the caller function. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default sting 'UNICADOworkflow' is used. + + The output list log_file_list contains the strings of workflow log-file from the caller function and the added + strings from this function. + + :param: path_of_working_directory_rce: input string + :param: aircraft_project: input string + :param: file_name: input string + :param: log_file_list: input list + :param: current_workflow_name: input string + :return: log_file_list: output list + """ + + ''' imports for python ''' + import os + import sys + import shutil + from inspect import currentframe, getframeinfo + from datetime import datetime + from sub_function.read_xml_file import read_xml_file + from sub_function.write_to_log_file import write_to_log_file + + ''' initialize local parameter ''' + error_flag = False + error_string = str() + function_name = getframeinfo(currentframe()).function + + ''' check if converged aircraft exchange file exist -> if false: -> raise an error and abort program ''' + if not os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/' + file_name): + if os.path.isfile(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/cleanSheetDesign/' + file_name): + shutil.copyfile(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/cleanSheetDesign/' + file_name, + path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/' + file_name) + + print('Warning: No converged ' + file_name + ' in temporary working directory found! \n ' + ' Converged ' + file_name + ' from clean sheet design folder is used!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning: No converged ' + + file_name + ' in temporary working directory found! \n ' + ' Converged ' + file_name + 'from clean sheet design folder is used!') + else: + error_string = 'Error: Converged ' + file_name \ + + ' file not available! Study mission analysis without design sizing ' \ + 'loop cannot be performed! \n Program aborted!' + error_flag = True + + # check if the necessary geometry data exist in the temporary working directory + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/geometry_data/'): + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/cleanSheetDesign/geometry_data/'): + shutil.copytree(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/cleanSheetDesign/geometry_data/', + path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/geometry_data/') + print('Warning: No geometry data in temporary working directory found! \n ' + ' Geometry data from clean sheet design folder is used!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning: No geometry data in temporary working directory found! \n ' + ' Geometry data from clean sheet design folder is used!') + else: + error_string = 'Error: No geometry data in temporary working directory found! ' \ + 'Study mission analysis without design sizing loop cannot be performed! \n Program aborted!' + error_flag = True + + # check if the necessary aero data exist in the temporary working directory + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/aero_data/'): + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/cleanSheetDesign/aero_data/'): + shutil.copytree(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/cleanSheetDesign/aero_data/', + path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/aero_data/') + print('Warning: No aero data in temporary working directory found! \n ' + ' Aero data from clean sheet design folder is used!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning: No aero data in temporary working directory found! \n ' + ' Aero data from clean sheet design folder is used!') + else: + error_string = 'Error: No aero data in temporary working directory found! ' \ + 'Study mission analysis without design sizing loop cannot be performed! \n Program aborted!' + error_flag = True + + # check if the necessary engine data exist in the temporary working directory + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/engine_data/'): + if os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/cleanSheetDesign/engine_data/'): + shutil.copytree(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/cleanSheetDesign/engine_data/', + path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/engine_data/') + print('Warning: No engine data in temporary working directory found! \n ' + ' Engine data from clean sheet design folder is used!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Warning: No engine data in temporary working directory found! \n ' + ' Engine data from clean sheet design folder is used!') + else: + error_string = 'Error: No engine data in temporary working directory found! ' \ + 'Study mission analysis without design sizing loop cannot be performed! \n Program aborted!' + error_flag = True + + if error_flag: + print(error_string) + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + error_string) + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + sys.exit(1) + + ''' read engine name from converged aircraft exchange file ''' + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + file_name + root_of_aircraft_exchange_file, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'wing_design', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # Assumption that all propulsion systems use the same engine model + engine_name = root_of_aircraft_exchange_file.find('./component_design/propulsion/specific/propulsion/engine/model' + '/value').text + + # check if engine data exist -> if false: + # -> try to copy engine data from cleanSheetDesign folder otherwise raise an error and abort program + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/' + 'engine_data/' + engine_name): + try: + if not os.path.isdir(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/' + 'engine_data'): + os.mkdir(path_of_working_directory_rce + current_workflow_name + + '/' + aircraft_project + '/' + 'engine_data') + shutil.copytree(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + + 'cleanSheetDesign/engine_data/' + engine_name, + path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + '/' + + 'engine_data/' + engine_name) + print('Necessary engine data for ' + engine_name + ' successfully copied from "cleanSheetDesign" folder!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + 'Necessary engine data for ' + + engine_name + ' successfully copied from "cleanSheetDesign" folder!') + + except OSError: + print('Error: Necessary engine data for ' + engine_name + ' not available! ' + 'Study mission analysis without design sizing loop cannot be performed! \n Program aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Error: Converged ' + engine_name + ' file not available! ' + 'Study mission analysis without design sizing loop cannot be performed! \n ' + 'Program aborted!') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + sys.exit(1) + + return log_file_list diff --git a/UNICADOworkflow/src/sub_function/read_geometry_elements.py b/UNICADOworkflow/src/sub_function/read_geometry_elements.py new file mode 100644 index 0000000000000000000000000000000000000000..ffc95c302be426cf72ac0b1157d6824b725adf55 --- /dev/null +++ b/UNICADOworkflow/src/sub_function/read_geometry_elements.py @@ -0,0 +1,74 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def read_geometry_elements(root_of_aircraft_exchange_file): + """ reads the used geometry elements from the aircraft exchange file + + The input dictionary contains the element tree of the aircraft exchange file of current project. + + The input list contains the geometry data file names of the used elements of current project. + + :param: root_of_aircraft_exchange_file: input dictionary + :return: geometry_name: output list + """ + + # initialize used geometry name list as empty list + geometry_name = set([]) + + ''' read horizontal lifting surfaces geometry data ''' + aerodynamic_surfaces = root_of_aircraft_exchange_file.findall( + "./component_design/wing/specific/geometry/aerodynamic_surface") + aerodynamic_surfaces.extend(root_of_aircraft_exchange_file.findall( + "./component_design/empennage/specific/geometry/aerodynamic_surface")) + # loop across all used aerodynamic surface elements + for aerodynamic_surface in aerodynamic_surfaces: + # loop across all half surface profiles for symmetrical and unsymmetrical lifting surfaces + for half_surface_segment_profile in aerodynamic_surface.findall("./parameters/sections/section/profile"): + geometry_name.add(str(half_surface_segment_profile.find("./value").text)) + + ''' read fuselage geometry data ''' + fuselage_shapes = root_of_aircraft_exchange_file.findall( + "./component_design/fuselage/specific/geometry/fuselage/sections/section/section_shape") + + # loop across all used fuselage shape elements surface elements + for fuselage_shape in fuselage_shapes: + # add element if it is a .dat file + shape_name = str(fuselage_shape.find("./value").text) + print (shape_name[-4:]) + if shape_name[-4:] in ".dat": + geometry_name.add(shape_name[:-4]) + + ''' read nacelle geometry data ''' + nacelle_profiles = root_of_aircraft_exchange_file.findall( + "./component_design/propulsion/specific/propulsion/nacelle/sections/section/profile") + + # loop across all used nacelle profile elements + for nacelle_profile in nacelle_profiles: + geometry_name.add(str(nacelle_profile.find("./value").text)) + + ''' read pylon geometry data ''' + pylon_profiles = root_of_aircraft_exchange_file.findall( + "./component_design/propulsion/specific/propulsion/pylon/sections/section/profile") + + # loop across all used pylon profile elements + for pylon_profile in pylon_profiles: + geometry_name.add(str(pylon_profile.find("./value").text)) + + return geometry_name diff --git a/UNICADOworkflow/src/sub_function/read_xml_file.py b/UNICADOworkflow/src/sub_function/read_xml_file.py new file mode 100644 index 0000000000000000000000000000000000000000..fde1eef2c4fa5a7b2b1bda216c19f2522f423d88 --- /dev/null +++ b/UNICADOworkflow/src/sub_function/read_xml_file.py @@ -0,0 +1,74 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def read_xml_file(path, path_of_working_directory_rce, xml_file_name, function_name, code_line, log_file_list, + current_workflow_name='UNICADOworkflow'): + """ function to read data from given xml-file as element tree. + + The input string "path" contains the absolute path to the given xml-file. + + The input string "path_of_working_directory_rce" contains the absolute path to the working directory of rce. + + The input string "xml_file_name" contains the name of the given xml-file to read. + + The input string "function_name" contains the name of the python function, witch has called the read_xml_file.py. + + The input integer "code_line" contains the code line number of the python function, witch has called the read_xml_file.py. + + The input list "log_file_list" contains the strings of workflow log-file from the caller function and the added strings from this function. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default sting 'UNICADOworkflow' is used. + + The output elementTree "root_of_tree" contains the data of the given xml-file as an elementTree. + + The output elementTree "xml_tree" contains the data of the given xml-file as an elementTree. + + :param: path: input string + :param: path_of_working_directory_rce: input string + :param: xml_file_name: input string + :param: function_name: input string + :param: code_line: input integer + :param: log_file_list: input list + :param: current_workflow_name: input string + :return: root_of_tree: output elementTree, xml_tree: output elementTree + """ + + """ imports for python """ + import sys + import xml.etree.ElementTree + from datetime import datetime + from sub_function.write_to_log_file import write_to_log_file + + ''' read xml-file as element tree ''' + try: + xml_tree = xml.etree.ElementTree.ElementTree(file=path) + root_of_tree = xml_tree.getroot() + + except OSError: + print('Error in file: ' + function_name + '.py \n In line: ' + str(code_line + 2) + ' \n ' + xml_file_name + + ' configuration file could not be opened! \n Program aborted!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': Error in file: ' + function_name + + '.py \n In line: ' + str(code_line + 2) + ' \n ' + xml_file_name + + ' configuration file could not be opened! \n Program aborted!') + write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list) + sys.exit(1) + + return root_of_tree, xml_tree diff --git a/UNICADOworkflow/src/sub_function/recursive_data_remove.py b/UNICADOworkflow/src/sub_function/recursive_data_remove.py new file mode 100644 index 0000000000000000000000000000000000000000..a0df4ade78fcc1ff6cb8cdb356c9965afba5d3d4 --- /dev/null +++ b/UNICADOworkflow/src/sub_function/recursive_data_remove.py @@ -0,0 +1,57 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def recursive_data_remove(path_to_data_to_remove): + """ recursive_data_delete Changes the access rights of all files inside the given directory to read, write and execute, afterwards the given directory is deleted. + + The input string "path_to_data_to_delete" contains the system path to directory to be recursive deleted. + + :param: path_to_data_to_remove: input string + :return: none + """ + + ''' imports for python ''' + import os + import shutil + import stat + import time + + ''' loop across all directories and files inside the given directory to change access rights ''' + for root, dirs, files in os.walk(path_to_data_to_remove): + for directory in dirs: + os.chmod(os.path.join(root, directory), stat.S_IRWXU) + for file in files: + os.chmod(os.path.join(root, file), stat.S_IRWXU) + + ''' recursive remove of given directory ''' + while_count = 0 + while True: + try: + shutil.rmtree(path_to_data_to_remove) + break + except OSError: + if while_count == 10: + print('Warning: Recursive directory remove failed. Delete operation is skipped.') + break + + while_count += 1 + print('Warning: Try to remove directory recursively.') + print('Retry ' + str(while_count) + ' of 10!') + time.sleep(3) diff --git a/UNICADOworkflow/src/sub_function/select_configuration_files_from_existing_project.py b/UNICADOworkflow/src/sub_function/select_configuration_files_from_existing_project.py new file mode 100644 index 0000000000000000000000000000000000000000..71f7754eb940cad9a03d9f6a9035231404a4f68f --- /dev/null +++ b/UNICADOworkflow/src/sub_function/select_configuration_files_from_existing_project.py @@ -0,0 +1,240 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def select_configuration_files_from_existing_project(path_of_working_directory_rce, path_of_working_directory, + path_to_aircraft_projects, aircraft_project, aircraft_type, + use_configs_from_existing_project, log_file_list, + current_workflow_name='UNICADOworkflow'): + """ select_configuration_files_from_existing_project prepare data to apply used configuration files from given project sources. + Returns an output flag for following script execution. + + The input string "path_of_working_directory_rce" contains the system path to working directory of rce. + + The input string "path_of_working_directory" contains the system path to working directory of UNICADO. + + The input string "path_to_aircraft_projects" contains the system path to aircraft reference repository. + + The input string "aircraft_project" contains the name of the aircraft exchange file. + + The input string "aircraft_type" contains the name of the aircraft type of current project. + + The input integer "use_configs_from_existing_project" contains the number of source-location of existing engine. + + The input list "log_file_list" contains all system prints of function: set_configuration_parameter.py. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default sting 'UNICADOworkflow' is used. + + The output list "log_file_list" contains all system prints of functions: set_configuration_parameter.py and select_engine_from_existing_project.py. + + :param: path_of_working_directory_rce: input string + :param: path_of_working_directory: input string + :param: path_to_aircraft_projects: input string + :param: aircraft_project: input string + :param: aircraft_type: input string + :param: use_configs_from_existing_project: input integer + :param: log_file_list: input list + :param: current_workflow_name: input string + :return: check_flag_xml_in_clean_sheet_folder: output bool, log_file_list: output list + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from read_xml_file import read_xml_file + from recursive_data_remove import recursive_data_remove + from sparse_checkout_from_git import sparse_checkout_from_git + + function_name = getframeinfo(currentframe()).function + + print_flag = True + sparse_checkout_flag = False + folder_name = str() + path_to_config = str() + + list_of_working_directory_content = os.listdir(path_of_working_directory) + check_flag_xml_in_clean_sheet_folder = str() + + ''' prepare data for selected config copy mode ''' + # Use configuration file from clean sheet design folder + if use_configs_from_existing_project == 1: + path_to_config = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project \ + + '/cleanSheetDesign/config_files/' + check_flag_xml_in_clean_sheet_folder =\ + os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/cleanSheetDesign/config_files/') + folder_name = 'cleanSheetDesign' + + # Use configuration file from engine calibrated design folder + if use_configs_from_existing_project == 2: + path_to_config = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project \ + + '/retrofitDesign/engineCalibration/config_files/' + check_flag_xml_in_clean_sheet_folder = \ + os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/retrofitDesign/engineCalibration/config_files/') + folder_name = 'engineCalibration' + + # Use configuration file from aero calibrated design folder + if use_configs_from_existing_project == 3: + path_to_config = path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project \ + + '/retrofitDesign/aerodynamicCalibration/config_files/' + check_flag_xml_in_clean_sheet_folder = \ + os.path.isdir(path_of_working_directory_rce + current_workflow_name + '/' + aircraft_project + + '/retrofitDesign/aerodynamicCalibration/config_files/') + folder_name = 'aerodynamicCalibration' + + # Use configuration file from repository folder + if use_configs_from_existing_project == 4: + # try to open module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/unicado_workflow_conf.xml' + root_of_workflow_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'unicado_workflow', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + name_of_checkout_dir_from_repository = str(root_of_workflow_tree.find( + './control_settings/program_specific_settings/iteration_settings/use_configs_from_existing_project/' + 'mode_specific_settings/mode_4/name_of_config_checkout_dir/value').text) + # Check if the given input directory not equal to 'cleanSheetDesign' -> if true: -> retrofit design will be used + if name_of_checkout_dir_from_repository == 'aerodynamicCalibration' \ + or name_of_checkout_dir_from_repository == 'engineCalibration' \ + or name_of_checkout_dir_from_repository == 'withoutCalibration': + path_to_config = path_to_aircraft_projects + aircraft_type + '/' + aircraft_project + '/retrofitDesign/' +\ + name_of_checkout_dir_from_repository + '/config_files/' + check_flag_xml_in_clean_sheet_folder = os.path.isdir(path_to_config) + else: + path_to_config = path_to_aircraft_projects + aircraft_type + '/' + aircraft_project + '/' \ + + name_of_checkout_dir_from_repository + '/config_files/' + check_flag_xml_in_clean_sheet_folder = os.path.isdir(path_to_config) + folder_name = 'local repository' + + # Use configuration file from repository folder + if use_configs_from_existing_project == 5: + # try to open module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/unicado_workflow_conf.xml' + root_of_workflow_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'unicado_workflow', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # set server information for sparse-checkout + if not os.path.isdir(path_of_working_directory_rce + '/' + current_workflow_name + '/' + aircraft_project + + '/temporaryData'): + os.mkdir(path_of_working_directory_rce + '/' + current_workflow_name + '/' + aircraft_project + + '/temporaryData') + path_to_local_repository = path_of_working_directory_rce + '/' + current_workflow_name + '/' + aircraft_project\ + + '/temporaryData' + repository_name = "rAIRCRAFTREFERENCES" + branch = str(root_of_workflow_tree.find( + './control_settings/program_specific_settings/iteration_settings/use_configs_from_existing_project/' + 'mode_specific_settings/mode_5/config_repository_branch/value').text) + name_of_checkout_dir_from_server = str(root_of_workflow_tree.find( + './control_settings/program_specific_settings/iteration_settings/use_configs_from_existing_project/' + 'mode_specific_settings/mode_4/name_of_config_checkout_dir/value').text) + ssh_url = 'ssh://git@unicado.ilr.rwth-aachen.de:2222/source/' + repository_name + '.git' + + if name_of_checkout_dir_from_server == 'cleanSheetDesign': + name_of_checkout_dir_from_server = aircraft_type + '/' + aircraft_project + '/cleanSheetDesign/config_files' + else: + name_of_checkout_dir_from_server = aircraft_type + '/' + aircraft_project + '/retrofitDesign/' \ + + name_of_checkout_dir_from_server + '/config_files' + + # call function for sparse-checkout from given ssh-git repository + sparse_checkout_flag = sparse_checkout_from_git(path_to_local_repository, ssh_url, branch, + name_of_checkout_dir_from_server) + + path_to_config = path_of_working_directory_rce + '/' + current_workflow_name + '/' + aircraft_project \ + + '/temporaryData/config_files/' + check_flag_xml_in_clean_sheet_folder = os.path.isdir(path_to_config) + folder_name = 'ssh-server' + + if not sparse_checkout_flag: + check_flag_xml_in_clean_sheet_folder = False + print_flag = False + print('Error: Configuration files could not checked out from ssh-server! \n ' + 'Be sure that you have necessary access rights to checkout from repository! \n ' + 'If you have, please check if the folder to checkout from git repository exist! \n ' + 'Current configuration files will be used!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Error: Configuration files could not checked out from ssh-server! \n ' + 'Be sure that you have necessary access rights to checkout from repository! \n ' + 'If you have, please check if the folder to checkout from git repository exist! \n ' + 'Current configuration files will be used!') + + # check if current selected folder of configuration files exist + # -> if true: -> copy configuration files to tool directories + if check_flag_xml_in_clean_sheet_folder: + list_of_directory_content = os.listdir(path_to_config) + for element in list_of_directory_content: + if os.path.isdir(path_to_config + element) and not element == 'studyLoop' \ + and not (element == 'preExecution'): + list_of_sub_folder_content = os.listdir(path_to_config + element) + for sub_element in list_of_sub_folder_content: + # extract the tool name from current sub_element string -> toolName_conf.xml[:-9] returns toolName + tool_name = sub_element[:-9] + for content in list_of_working_directory_content: + if content == tool_name: + if os.path.isdir(path_of_working_directory + content): + if content == 'aerodynamic_assessment': + print(path_to_config + element + '/liftingLine_conf.xml') + if os.path.isfile(path_to_config + element + '/liftingLine_conf.xml'): + shutil.copyfile(path_to_config + element + '/liftingLine_conf.xml', + path_of_working_directory_rce + '/' + current_workflow_name + + '/liftingLine_conf.xml') + print('Replacement of liftingLine configuration file from ' + + folder_name + ' folder successfully done!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Replacement of liftingLine configuration file from ' + + folder_name + ' folder successfully done!') + + if content == 'cpacsInterface': + print(path_to_config + element + '/convertUNICADO2CPACS_conf.xml') + if os.path.isfile(path_to_config + element + '/convertUNICADO2CPACS_conf.xml'): + shutil.copyfile(path_to_config + element + '/convertUNICADO2CPACS_conf.xml', + path_of_working_directory_rce + '/' + current_workflow_name + + '/convertUNICADO2CPACS_conf.xml') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Replacement of convertUNICADO2CPACS configuration ' + 'file from ' + folder_name + + ' folder successfully done!') + + shutil.copyfile(path_to_config + element + '/' + sub_element, + path_of_working_directory_rce + '/' + current_workflow_name + '/' + + sub_element) + print('Replacement of ' + tool_name + ' configuration file from ' + folder_name + + ' folder successfully done!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Replacement of ' + tool_name + ' configuration file from ' + + folder_name + ' folder successfully done!') + + elif not check_flag_xml_in_clean_sheet_folder and print_flag: + print('Warning: Module configuration files could not found in ' + folder_name + + ' folder! \n Current module configuration files will be used!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + 'Warning: ' + 'Module configuration files could not found in ' + folder_name + ' folder! \n ' + 'Current module configuration files will be used!') + + # remove temporary ssh-data + if sparse_checkout_flag: + recursive_data_remove(path_of_working_directory_rce + '/' + current_workflow_name + '/' + aircraft_project + + '/temporaryData') + + return check_flag_xml_in_clean_sheet_folder, log_file_list diff --git a/UNICADOworkflow/src/sub_function/select_engine_from_existing_project.py b/UNICADOworkflow/src/sub_function/select_engine_from_existing_project.py new file mode 100644 index 0000000000000000000000000000000000000000..a8d5aace823e7e50201435d26895ea7739f41cbd --- /dev/null +++ b/UNICADOworkflow/src/sub_function/select_engine_from_existing_project.py @@ -0,0 +1,201 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def select_engine_from_existing_project(path_of_working_directory_rce, path_to_aircraft_projects, + aircraft_exchange_file, aircraft_type, aircraft_project, + use_engine_from_existing_project, log_file_list, + current_workflow_name='UNICADOworkflow'): + """ select_engine_from_existing_project prepare data to apply used engines from given project sources. + Returns an output flag for following script execution. + + The input string "path_of_working_directory_rce" contains the system path to working directory of rce. + + The input string "path_to_aircraft_projects" contains the system path to aircraft reference repository. + + The input string "aircraft_exchange_file" contains the name of the aircraft exchange file. + + The input string "aircraft_type" contains the name of the aircraft type of current project. + + The input string "aircraft_project" contains the name of the aircraft exchange file. + + The input integer "use_engine_from_existing_project" contains the number of source-location of existing engine. + + The input list "log_file_list" contains all system prints of function: set_configuration_parameter.py. + + The input string "current_workflow_name" contains the name of the current workflow execution. + * If no input is given, default string 'UNICADOworkflow' is used. + + The output bool "engine_flag" contains the status of used engine copy. + + The output string "folder_name" contains the folder name of which engine where copied. + + The output list "log_file_list" contains all system prints of functions: set_configuration_parameter.py and select_engine_from_existing_project.py. + + :param: path_of_working_directory_rce: input string + :param: path_to_aircraft_projects: input string + :param: aircraft_exchange_file: input string + :param: aircraft_type: input string + :param: aircraft_project: input string + :param: use_engine_from_existing_project: input integer + :param: log_file_list: input list + :param: current_workflow_name: input string + :return: engine_flag: output bool, sparse_checkout_flag: output bool, folder_name: output string, log_file_list: output list + """ + + ''' imports for python ''' + import os + import shutil + from datetime import datetime + from inspect import currentframe, getframeinfo + from read_xml_file import read_xml_file + from recursive_data_remove import recursive_data_remove + from sparse_checkout_from_git import sparse_checkout_from_git + + function_name = getframeinfo(currentframe()).function + + engine_flag = False + check_flag_engine_in_folder = False + sparse_checkout_flag = False + folder_name = str() + source = str() + + ''' delete existing engine_data and all sub data ''' + if os.path.isdir(path_of_working_directory_rce + '/' + current_workflow_name + '/' + aircraft_project + + '/engine_data/'): + recursive_data_remove(path_of_working_directory_rce + '/' + current_workflow_name + '/' + aircraft_project + + '/engine_data/') + + # use engine from clean sheet design folder + if use_engine_from_existing_project == 1: + check_flag_engine_in_folder = os.path.isdir(path_of_working_directory_rce + '/' + current_workflow_name + '/' + + aircraft_project + '/cleanSheetDesign/engine_data/') + source = path_of_working_directory_rce + '/' + current_workflow_name + '/' + aircraft_project \ + + '/cleanSheetDesign/engine_data/' + folder_name = 'cleanSheetDesign' + + # use engine from engine calibrated design folder + if use_engine_from_existing_project == 2: + check_flag_engine_in_folder = os.path.isdir(path_of_working_directory_rce + '/' + current_workflow_name + '/' + + aircraft_project + + '/retrofitDesign/engineCalibration/engine_data/') + source = path_of_working_directory_rce + '/' + current_workflow_name + '/' + aircraft_project \ + + '/retrofitDesign/engineCalibration/engine_data/' + folder_name = 'engineCalibration' + + # Use engine from aero calibrated design folder + if use_engine_from_existing_project == 3: + check_flag_engine_in_folder = os.path.isdir(path_of_working_directory_rce + '/' + current_workflow_name + '/' + + aircraft_project + + '/retrofitDesign/aerodynamicCalibration/engine_data/') + source = path_of_working_directory_rce + '/' + current_workflow_name + '/' + aircraft_project \ + + '/retrofitDesign/aerodynamicCalibration/engine_data/' + folder_name = 'aerodynamicCalibration' + + # use engine from repository + if use_engine_from_existing_project == 4: + aircraft_project = aircraft_exchange_file[0:len(aircraft_exchange_file) - 4] + # try to open module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/unicado_workflow_conf.xml' + root_of_workflow_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'unicado_workflow', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + name_of_checkout_dir_from_repository = str(root_of_workflow_tree.find( + './control_settings/program_specific_settings/iteration_settings/use_engine_from_existing_project/' + 'mode_specific_settings/mode_4/name_of_engine_checkout_dir/value').text) + # Check if the given input directory not equal to 'cleanSheetDesign' -> if true: -> retrofit design will be used + if name_of_checkout_dir_from_repository == 'aerodynamicCalibration' \ + or name_of_checkout_dir_from_repository == 'engineCalibration' \ + or name_of_checkout_dir_from_repository == 'withoutCalibration': + source = path_to_aircraft_projects + aircraft_type + '/' + aircraft_project + '/retrofitDesign/' \ + + name_of_checkout_dir_from_repository + '/engine_data' + check_flag_engine_in_folder = os.path.isdir(source) + else: + source = path_to_aircraft_projects + aircraft_type + '/' + aircraft_project + '/' \ + + name_of_checkout_dir_from_repository + '/engine_data' + check_flag_engine_in_folder = os.path.isdir(source) + folder_name = 'local repository' + + if check_flag_engine_in_folder: + destination = path_of_working_directory_rce + '/' + current_workflow_name + '/' + aircraft_project \ + + '/engine_data/' + shutil.copytree(source, destination) + engine_flag = True + + # use engine from ssh server branch + if use_engine_from_existing_project == 5: + # try to open module configuration file + frame_info = getframeinfo(currentframe()) + path = path_of_working_directory_rce + current_workflow_name + '/unicado_workflow_conf.xml' + root_of_workflow_tree, xml_tree = read_xml_file(path, path_of_working_directory_rce, 'unicado_workflow', + function_name, frame_info.lineno, log_file_list, + current_workflow_name) + + # set server information for sparse-checkout + path_to_local_repository = path_of_working_directory_rce + '/' + current_workflow_name + '/' \ + + aircraft_project + '/' + + repository_name = str(root_of_workflow_tree.find( + './control_settings/program_specific_settings/iteration_settings/use_engine_from_existing_project/' + 'mode_specific_settings/mode_5/engine_repository_name/value').text) + branch = str(root_of_workflow_tree.find( + './control_settings/program_specific_settings/iteration_settings/use_engine_from_existing_project/' + 'mode_specific_settings/mode_5/engine_repository_branch/value').text) + name_of_checkout_dir_from_server = str(root_of_workflow_tree.find( + './control_settings/program_specific_settings/iteration_settings/use_engine_from_existing_project/' + 'mode_specific_settings/mode_5/name_of_engine_checkout_dir/value').text) + ssh_url = 'ssh://git@unicado.ilr.rwth-aachen.de:2222/source/' + repository_name + '.git' + + if repository_name.lower() == 'raircraftreferences': + if name_of_checkout_dir_from_server == 'cleanSheetDesign': + name_of_checkout_dir_from_server = aircraft_type + '/' + aircraft_project + '/cleanSheetDesign/engine_data' + elif name_of_checkout_dir_from_server == 'aerodynamicCalibration' \ + or name_of_checkout_dir_from_server == 'engineCalibration' \ + or name_of_checkout_dir_from_server == 'withoutCalibration': + name_of_checkout_dir_from_server = aircraft_type + '/' + aircraft_project + '/retrofitDesign/' \ + + name_of_checkout_dir_from_server + '/engine_data' + else: + path_to_local_repository += 'engine_data/' + + # call function for sparse-checkout from given ssh-git repository + sparse_checkout_flag = sparse_checkout_from_git(path_to_local_repository, ssh_url, branch, + name_of_checkout_dir_from_server) + + folder_name = 'ssh-server' + if not sparse_checkout_flag: + print('Error: Engine data could not checked out from ssh-server! \n ' + 'Be sure that you have necessary access rights to checkout from repository! \n ' + 'If you have, please check if the folder to checkout from git repository exist! \n ' + 'Current engine data will be used!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + + ': Error: Engine data could not checked out from ssh-server! \n ' + 'Be sure that you have necessary access rights to checkout from repository! \n ' + 'If you have, please check if the folder to checkout from git repository exist! \n ' + 'Current engine data will be used!') + + else: + engine_flag = True + + if engine_flag: + print('Engine data has been successfully replaced by engine from folder: ' + folder_name + '!') + log_file_list.append(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + ': ' + 'Engine data has been successfully replaced by engine from folder: ' + folder_name + '!') + + return engine_flag, sparse_checkout_flag, folder_name, log_file_list diff --git a/UNICADOworkflow/src/sub_function/sparse_checkout_from_git.py b/UNICADOworkflow/src/sub_function/sparse_checkout_from_git.py new file mode 100644 index 0000000000000000000000000000000000000000..562465ba0152948c240ebe5d235565d8ec1bafd5 --- /dev/null +++ b/UNICADOworkflow/src/sub_function/sparse_checkout_from_git.py @@ -0,0 +1,90 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def sparse_checkout_from_git(path_to_local_repository, ssh_url, branch, name_of_checkout_dir_from_server): + """ sparse_checkout_from_git enables checking out a given parent or child directory from a git repository. + + The input string "path_to_local_repository" contains the system path to the local directory to which the data is copied from the git repository. + + The input string "ssh_url" contains the ssh-link to the git repository which to be checked out. + + The input string "branch" contains the bane of branch of the git repository which to be checked out. + + The input string "name_of_checkout_dir_from_server" contains the name of the specific folder which to be checked out. + * If you want to check out a sub-folder from git, the given string has to be containing the folder path from parent directory to target folder. + * example: 'parent_folder_on_git/child_folder/child_of_child_folder' + + The output bool "sparse_checkout_flag" contains the status "True" if checkout is done of "False" if checkout failed. + + :param: path_to_local_repository: input string + :param: ssh_url: input string + :param: branch: input string + :param: name_of_checkout_dir_from_server: input string + :return: sparse_checkout_flag: output bool + """ + + ''' imports for python ''' + import git + import os + import shutil + from recursive_data_remove import recursive_data_remove + + sparse_checkout_flag = False + + # try to create local git-repository and connect to ssh-server + try: + # init local git repository + repo = git.Repo.init(path_to_local_repository) + # add possibility to sparse-checkout in git-configuration file + repo.config_writer().set_value("core", "sparsecheckout", "true").release() + # add ssh-url to remote node to git-configuration file + origin = repo.create_remote('origin', ssh_url) + + # create sparse-checkout file containing the string of directory to check out from git repository + sparse_checkout_file = open(path_to_local_repository + '/.git/info/sparse-checkout', 'w') + sparse_checkout_file.write(name_of_checkout_dir_from_server + '/*\n') + sparse_checkout_file.close() + + # pull given data from specific git-repository folder to local directory + origin.pull(branch, depth=1) + + # check if given checkout folder from repository a root folder -> if not: -> copy to local destination + if not name_of_checkout_dir_from_server.rfind('/') == -1: + name_of_parent_folder = name_of_checkout_dir_from_server[:name_of_checkout_dir_from_server.find('/')] + name_of_child_folder = name_of_checkout_dir_from_server[name_of_checkout_dir_from_server.rfind('/') + 1:] + shutil.copytree(path_to_local_repository + '/' + name_of_checkout_dir_from_server, path_to_local_repository + + '/' + name_of_child_folder) + + # call function to remove 'parent directory of sub-folder from local machine + recursive_data_remove(path_to_local_repository + '/' + name_of_parent_folder) + + # call function to remove '/.git' directory after checkout from local machine + recursive_data_remove(path_to_local_repository + '/.git') + + # set return + sparse_checkout_flag = True + + # exception handling, if ssh-checkout failed + except OSError: + # check if '/.git' exist on local machine -> if true: -> remove from local machine + if os.path.isdir(path_to_local_repository + '/.git'): + recursive_data_remove(path_to_local_repository + '/.git') + + return sparse_checkout_flag diff --git a/UNICADOworkflow/src/sub_function/write_to_log_file.py b/UNICADOworkflow/src/sub_function/write_to_log_file.py new file mode 100644 index 0000000000000000000000000000000000000000..13c9f418b3bfaa5ab964905fb75372e9f537c6f1 --- /dev/null +++ b/UNICADOworkflow/src/sub_function/write_to_log_file.py @@ -0,0 +1,38 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def write_to_log_file(path_of_working_directory_rce, current_workflow_name, log_file_list): + """ writes a log_file_list into unicado_workflow.log + + The input string path_of_working_directory_rce contains the system path to the working directory of rce. + + The input string current_workflow_name contains the name of the current workflow execution. + + The input list log_file_list contains the strings of workflow log-file from the caller function. + + :param: path_of_working_directory_rce: input string + :param: current_workflow_name: input string + :param: log_file_list: input list + """ + + log_file = open(path_of_working_directory_rce + current_workflow_name + '/unicado_workflow.log', 'a') + for row in log_file_list: + log_file.write(row + '\n') + log_file.close() \ No newline at end of file diff --git a/UNICADOworkflow/src/sub_function/xml_path_check.py b/UNICADOworkflow/src/sub_function/xml_path_check.py new file mode 100644 index 0000000000000000000000000000000000000000..6731f163f3e98e704d968e955e9b67ed53720f8a --- /dev/null +++ b/UNICADOworkflow/src/sub_function/xml_path_check.py @@ -0,0 +1,62 @@ +# UNICADO - UNIversity Conceptual Aircraft Design and Optimization +# +# Copyright (C) 2025 UNICADO consortium +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# +# Description: +# This file is part of UNICADO. + +def xml_path_check(xml_path_to_check): + """ Function to check if the given input xml-path an absolute or relative xml-path and correct the given path. + + The input string 'xml_path_to_check' contains the string to check if it is an absolute or relative xml-path. + + The output string 'corrected_path' contains the corrected path. + + :param: xml_path_to_check: input string + :return: corrected_xml_path: output string + """ + + ''' imports for python ''' + import os + + # replace all '\' character with '/' to operate on Windows and linux OS + xml_path_to_check = xml_path_to_check.replace(os.sep, '/') + + # check if the string "AcftExchangeFile" in the given xml-path -> if true: -> delete from string + if "aircraft_exchange_file" in xml_path_to_check: + length_of_string = len("aircraft_exchange_file") + index = xml_path_to_check.find('aircraft_exchange_file') + corrected_xml_path = '.' + xml_path_to_check[index+length_of_string:] + + # check if the string "ConfigFile" in the given xml-path -> if true: -> delete from string + elif "module_configuration_file" in xml_path_to_check: + length_of_string = len("module_configuration_file") + index = xml_path_to_check.find('module_configuration_file') + corrected_xml_path = '.' + xml_path_to_check[index+length_of_string:] + + else: + if xml_path_to_check[0] == '/': + corrected_xml_path = '.' + xml_path_to_check + + elif not xml_path_to_check[0:1] == './': + if xml_path_to_check[0] == '.': + corrected_xml_path = './' + xml_path_to_check[1:] + else: + corrected_xml_path = './' + xml_path_to_check + else: + corrected_xml_path = xml_path_to_check + + return corrected_xml_path diff --git a/UNICADOworkflow/unicado_workflow_conf.xml b/UNICADOworkflow/unicado_workflow_conf.xml new file mode 100644 index 0000000000000000000000000000000000000000..9b5db737a48c87ed3c8201845c2e8701adbebf97 --- /dev/null +++ b/UNICADOworkflow/unicado_workflow_conf.xml @@ -0,0 +1,239 @@ +<module_configuration_file Name="UNICADOworkflow Runtime Configuration."> + <control_settings description="General control settings for tool behavior."> + <aircraft_exchange_file_name description="Specify the name of the exchange file"> + <value>UNICADO-SMR-180-TF.xml</value> + </aircraft_exchange_file_name> + <aircraft_exchange_file_directory description="Specify the directory in which the aircraft exchange file can be found"> + <value>../projects/UNICADO-SMR/UNICADO-SMR-180-TF/</value> + </aircraft_exchange_file_directory> + <own_tool_level description="Specify the tool level of this tool"> + <value>1</value> + </own_tool_level> + <console_output description="Selector to specify the console output. Selector: mode_0 (Off) / mode_1 (only out/err/warn) / mode_2 (1 + info) / mode_3 (2 + debug)"> + <value>mode_1</value> + </console_output> + <log_file_output description="Selector to specify the log file output. Selector: mode_0 (Off) / mode_1 (only out/err/warn) / mode_2 (1 + info) / mode_3 (2 + debug)"> + <value>mode_1</value> + </log_file_output> + <plot_output description="Specify the way plotting shall be handled"> + <enable description="Switch to enable plotting. Switch: true (On) / false (Off)"> + <value>true</value> + </enable> + <copy_plotting_files description="Switch if plotting files shall be copied. Switch: true (On) / false (Off)"> + <value>true</value> + </copy_plotting_files> + <delete_plotting_files_from_tool_folder description="Switch if plotting files shall be deleted from folder. Switch: true (On) / false (Off)"> + <value>true</value> + </delete_plotting_files_from_tool_folder> + </plot_output> + <report_output description="Switch to generate an HTML report. Switch: true (On) / false (Off)"> + <value>true</value> + </report_output> + <tex_report description="Switch to generate a Tex report. Switch: true (On) / false (Off)"> + <value>true</value> + </tex_report> + <write_info_files description="Switch to generate info files. Switch: true (On) / false (Off)"> + <value>false</value> + </write_info_files> + <log_file description="Specify the name of the log file"> + <value>unicado_workflow.log</value> + </log_file> + <inkscape_path description="Path to the inkscape application (if inkscape is not installed and available in PATH, set here the path to the local inkscape folder)"> + <value>../inkscape/</value> + </inkscape_path> + <gnuplot_path description="Path to the gnuplot application (if gnuplot is not installed and available in PATH, set here the path to the local inkscape folder)"> + <value>../gnuplot/</value> + </gnuplot_path> + <program_specific_settings description="Program settings"> + <pre_workflow_operation_settings description="Parameter for the pre operation functionalities of workflow"> + <set_project_folder_to_default description="Delete all old files from project folder and set to default. Switch: true (project folder is set to default) / false (no files are deleted)"> + <value>false</value> + <default>false</default> + </set_project_folder_to_default> + <delete_plots_before_run description="Old plots and reports are deleted from folders (especially useful for studies). Switch: true (reporting/plots folder is cleared) / false (no files are deleted)"> + <value>true</value> + <default>true</default> + </delete_plots_before_run> + <delete_engines_before_run description="Old engine data are deleted from from project folder. Switch: true (engine_data folder is cleared) / false (no files are deleted)"> + <value>true</value> + <default>true</default> + </delete_engines_before_run> + <clear_old_log_files_before_run description="Clear all subtool logfiles at start. Switch: true (log_files of submodules are deleted before workflow start) / false (no files are deleted)"> + <value>true</value> + <default>true</default> + </clear_old_log_files_before_run> + </pre_workflow_operation_settings> + <iteration_settings description="Special handling during iteration."> + <switch_off_plots description="Switch to switch off plots during the iteration loop. Switch: true (no plots during iteration) / false (plotting in every iteration loop if plot_output is true)"> + <value>true</value> + </switch_off_plots> + <switch_off_html_report description="Switch to switch off HTML report during the iteration loop. Switch: true (no HTML report during iteration) / false (HTML report is written in every iteration loop if report_output is true)"> + <value>true</value> + </switch_off_html_report> + <switch_off_tex_report description="Switch to switch off TeX report during the iteration loop. Switch: true (no TeX report during iteration) / false (TeX report is written in every iteration loop if tex_report is true)"> + <value>true</value> + </switch_off_tex_report> + <switch_off_info_files description="Switch to switch off info file generation during the iteration loop. Switch: true (no info files are written during iteration) / false (info files are written in every iteration loop if write_info_files is true)"> + <value>true</value> + </switch_off_info_files> + <check_settings_for_design_logic description="Settings of submodules are checked and adapted according to the design mode given in ./program_settings/design_case_settings/design_mode. Switch: true (check settings of submodules for design mode and adapt accordingly) / false (no checks of settings in submodules) "> + <value>true</value> + <default>true</default> + </check_settings_for_design_logic> + <use_control_settings_for_subprograms description="The control settings of the workflow are copied to all submodules. Switch: true (the control_settings of workflow are also taken in submodules) / false (no adaption of submodule control settings)"> + <value>true</value> + <default>true</default> + </use_control_settings_for_subprograms> + <use_range_type_specific_factors description="Adapt aircraft specific factors in all used modules. Selector: mode_0 (No adaptation) / mode_1 (based on design range) / mode_2 (use short-range values) / mode_3 (use medium-range values) / mode_4 (use long-range values)"> + <value>mode_0</value> + <default>mode_0</default> + </use_range_type_specific_factors> + <use_configs_from_existing_project description="Handles configuration parameter of copy mode of used config files"> + <config_copy_mode description="Choose the place where the module configuration files for the current project should be taken from. Selector: mode_0 (Use current configuration files; either from project/config_files or from tool directory) / mode_1 (Use configuration files from clean sheet design folder) / mode_2 (Use configuration files from engine calibrated design folder) / mode_3 (Use configuration files from aero calibrated design folder) / mode_4 (Use configuration files from local repository folder)"> + <value>mode_0</value> + <default>mode_0</default> + </config_copy_mode> + <mode_specific_settings> + <mode_4 description="Specific settings for mode_4 (Use configuration files from local repository folder)"> + <name_of_config_checkout_dir description="Choose the local repository folder where to pick the configs from. Selector: clean_sheet_design / engine_calibration / aerodynamic_calibration / without_calibration)"> + <value>clean_sheet_design</value> + <default>clean_sheet_design</default> + </name_of_config_checkout_dir> + </mode_4> + </mode_specific_settings> + </use_configs_from_existing_project> + <use_engine_from_existing_project description="Handles configuration parameter of copy mode of used engine data"> + <engine_copy_mode description="Choose the place where the engine for the current project should be taken from. Selector: mode_0 (Use current engine; either from project folder/engine_data or from propulsion_design/engines) / mode_1 (Use engine from clean sheet design folder) / mode_2 (Use engine from engine calibrated design folder) / mode_3 (Use engine from aero calibrated design folder) / mode_4 (Use engine from local repository folder)"> + <value>mode_0</value> + <default>mode_0</default> + </engine_copy_mode> + <mode_specific_settings> + <mode_4 description="Specific settings for mode_4 (Use engine from local repository folder)"> + <name_of_engine_checkout_dir description="Choose the local repository folder where to pick the engine from. Selector: clean_sheet_design / engine_calibration / aerodynamic_calibration / without_calibration)"> + <value>clean_sheet_design</value> + <default>clean_sheet_design</default> + </name_of_engine_checkout_dir> + </mode_4> + </mode_specific_settings> + </use_engine_from_existing_project> + <save_aircraft_exchange_files_to_result_folder description="Switch to switch of saving of aircraft exchange files. Switch: true (save aircraft exchange file) / false (disable saving of aircraft exchange files)"> + <value>true</value> + <default>true</default> + </save_aircraft_exchange_files_to_result_folder> + </iteration_settings> + <post_workflow_operation_settings description="Parameter for the post operation functionalities of workflow"> + <save_configs_to_result_folder description="Configs of the subprograms are stored in the folder ../workflowResults/[Workflow name]/config_files. Switch: true (configs are saved in the results folder) / false (configs are not copied to the results folder)"> + <value>true</value> + <default>true</default> + </save_configs_to_result_folder> + <save_log_files_to_result_folder description="Logfiles of the subprograms are stored in the folder ../workflowResults/[Workflow name]/reporting/log_files. Switch: true (log_files are saved in the results folder) / false (log_files are not copied to the results folder)"> + <value>true</value> + <default>true</default> + </save_log_files_to_result_folder> + <save_final_aircraft_exchange_file_to_result_folder description="Aircraft exchange files of each iteration are stored in the folder ../workflowResults/[Workflow name]/aircraft_exchange_files. Switch: true (aircraft exchange files are saved in the results folder) / false (aircraft exchange files are not copied to the results folder)"> + <value>true</value> + <default>true</default> + </save_final_aircraft_exchange_file_to_result_folder> + </post_workflow_operation_settings> + </program_specific_settings> + </control_settings> + <program_settings description="Parameter settings for workflow behavior."> + <program_mode description="Selector for execution mode of the program. Selector: mode_0 (single aircraft design) / mode_1 (parameter study) / mode_2 (optimization)"> + <value>mode_0</value> + </program_mode> + <design_case_settings> + <design_mode description="Selector for design mode. Selector: mode_0 (standard design; no check in subprograms) / mode_1 (clean sheet design) / mode_2 (retrofit design with existing geometry) / mode_3 (mission study analysis without design sizing loop) / mode_4 (design sizing without mission study analysis)"> + <value>mode_1</value> + <default>mode_0</default> + </design_mode> + <iteration_settings> + <convergence_criteria description="permitted relative change to achieve convergence"> + <value>2.5e-3</value> + <default>2.5e-3</default> + </convergence_criteria> + <max_number_of_iterations_before_exit description="Number of iterations before the loop is aborted by exit(1)"> + <value>30</value> + <default>30</default> + </max_number_of_iterations_before_exit> + <bridge_constraint_analyzer description="Switch to bridge the module constraint_analysis. Switch: true (Module is bridged and not executed) / false (Module is executed during iteration)"> + <value>false</value> + <default>false</default> + </bridge_constraint_analyzer> + <damp_MTOM_during_iteration description="Switch to activate damping MTOM during iteration; Switch: true (Mean value of the last 2 MTOM values is used to suppress vibrations if necessary.) / false (Damping MTOM is deactivated)"> + <value>false</value> + <default>false</default> + </damp_MTOM_during_iteration> + </iteration_settings> + <parallel_execution description="Switch if a parallel execution of the workflow is planned; Switch: true (Parallel execution is planned (configuration files will not be restored at the end)) / false (No parallel execution is planned (configuration files will be restored at the end))"> + <value>false</value> + <default>false</default> + </parallel_execution> + <calibration_settings description="Detailed settings to design calibrated aircraft configurations."> + <ome_calibration_mode description="Selector for OME calibration mode. Selector: mode_0 (no calibration active) / mode_1 (calibration using fuselage mass)"> + <value>mode_0</value> + <default>mode_0</default> + </ome_calibration_mode> + <mtom_calibration_mode description="Selector for MTOM calibration mode. Selector: mode_0 (no calibration active) / mode_1 (calibration using engine fuel flow) / mode_2 (calibration using aerodynamic drag counts)"> + <value>mode_0</value> + <default>mode_0</default> + </mtom_calibration_mode> + <target_values description="Preset target values for MTOM and OME"> + <ome description="Preset value for target OME"> + <value>42100</value> + </ome> + <mtom description="Preset value for target MTOM"> + <value>77000</value> + </mtom> + </target_values> + <reset_calibration_factors_at_start description="Switches to reset calibration values at start."> + <reset_fuselage_mass description="Reset the fuselage_mass calibration value for OME calibration at start. Switch: true (reset of value) / false (value is kept)"> + <value>true</value> + <default>true</default> + </reset_fuselage_mass> + <reset_viscous_drag_counts description="Reset the aerodynamic calibration value for MTOM calibration at start. Switch: true (reset of value) / false (value is kept)"> + <value>true</value> + <default>true</default> + </reset_viscous_drag_counts> + <reset_engine_fuel_flow_factor description="Reset the fuel flow calibration value for MTOM calibration at start. Switch: true (reset of value) / false (value is kept)"> + <value>true</value> + <default>true</default> + </reset_engine_fuel_flow_factor> + </reset_calibration_factors_at_start> + <iteration_settings> + <number_of_before_new_mtom_calibration_step description="Number of iterations after which each MTOM calibration is performed"> + <value>4</value> + <default>4</default> + </number_of_before_new_mtom_calibration_step> + <factor_for_convergence_criteria description="Termination criterion: As factor regarding convergenceCriteria (see ./program_settings/design_case_settings/iteration_settings/convergence_criteria)"> + <value>5</value> + <default>5</default> + </factor_for_convergence_criteria> + <max_number_of_iterations_before_ome_calibration_exit description="Number of iterations before the OME calibration loop is aborted by exit(1)"> + <value>20</value> + <default>20</default> + </max_number_of_iterations_before_ome_calibration_exit> + <damp_MTOM_calibration description="Switch to activate damping MTOM during MTOM calibration."> + <enable description="Enable MTOM damping during calibration. If relativ change exceeds maximum_extrapolation_lever, it is automatically damped to that value. Switch: true (damping is on) / false (damping is off)"> + <value>false</value> + <default>false</default> + </enable> + <maximum_mtom_extrapolation_lever description="Maximum allowable relative change in MTOM between two calibrations"> + <value>2</value> + <default>2</default> + </maximum_mtom_extrapolation_lever> + </damp_MTOM_calibration> + <damp_OME_calibration description="Switch to activate damping OME during OME calibration."> + <enable description="Enable OME damping during calibration. If relativ change exceeds maximum_extrapolation_lever, it is automatically damped to that value. Switch: true (damping is on) / false (damping is off)"> + <value>false</value> + <default>false</default> + </enable> + <maximum_ome_extrapolation_lever description="Maximum allowable relative change in OME between two calibrations"> + <value>2</value> + <default>2</default> + </maximum_ome_extrapolation_lever> + </damp_OME_calibration> + </iteration_settings> + </calibration_settings> + </design_case_settings> + </program_settings> +</module_configuration_file> \ No newline at end of file diff --git a/UNICADOworkflow/version.txt b/UNICADOworkflow/version.txt new file mode 100644 index 0000000000000000000000000000000000000000..50aea0e7aba1ab64fce04e96fb64bf9599a1c2a5 --- /dev/null +++ b/UNICADOworkflow/version.txt @@ -0,0 +1 @@ +2.1.0 \ No newline at end of file diff --git a/jsonFiles/aerodynamic_analysis/configuration.json b/jsonFiles/aerodynamic_analysis/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..e922b9cf973b1ba328275065ac9fa26b5ae3d0a3 --- /dev/null +++ b/jsonFiles/aerodynamic_analysis/configuration.json @@ -0,0 +1,60 @@ +{ + "commandScriptLinux": "./aerodynamic_analysis -c ../workingDirectoryRCE/${in:current_workflow_name}/aerodynamic_analysis_conf.xml", + "commandScriptWindows": "aerodynamic_analysis.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/aerodynamic_analysis_conf.xml", + "copyToolBehavior": "never", + "deleteWorkingDirectoriesAfterWorkflowExecution": true, + "documentationFilePath": "", + "dontCrashOnNonZeroExitCodes": true, + "enableCommandScriptLinux": true, + "enableCommandScriptWindows": true, + "groupName": "sizingLoop", + "imitationScript": "", + "imitationToolOutputFilename": "", + "inputs": [ + { + "inputHandling": "Queue", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "Required", + "endpointName": "current_workflow_name", + "defaultInputHandling": "Queue", + "inputExecutionConstraint": "Required", + "endpointFolder": "" + } + ], + "integrationType": "Common", + "isActive": true, + "launchSettings": [ + { + "limitInstallationInstancesNumber": "10", + "limitInstallationInstances": "true", + "rootWorkingDirectory": "", + "host": "RCE", + "toolDirectory": "", + "version": "allTime" + } + ], + "outputs": [ + { + "inputHandling": "-", + "endpointFileName": "", + "endpointDataType": "ShortText", + "endpointName": "current_workflow_name", + "inputExecutionConstraint": "-", + "endpointFolder": "" + } + ], + "postScript": "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\t\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: aerodynamic_analysis' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript": "", + "setToolDirAsWorkingDir": true, + "toolDescription": "", + "toolIconPath": "", + "toolIntegrationVersion": 1, + "toolIntegratorE-Mail": "", + "toolIntegratorName": "", + "toolName": "aerodynamic_analysis", + "toolProperties": { + "Default": {} + }, + "uploadIcon": true +} \ No newline at end of file diff --git a/jsonFiles/constraint_analysis/configuration.json b/jsonFiles/constraint_analysis/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..eb4cbc134fd0aba9b789169a95ce7cd5092ee9b9 --- /dev/null +++ b/jsonFiles/constraint_analysis/configuration.json @@ -0,0 +1,60 @@ +{ + "commandScriptLinux": "./constraint_analysis-c ../workingDirectoryRCE/${in:current_workflow_name}/constraint_analysis_conf.xml", + "commandScriptWindows": "constraint_analysis.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/constraint_analysis_conf.xml", + "copyToolBehavior": "never", + "deleteWorkingDirectoriesAfterWorkflowExecution": true, + "documentationFilePath": "", + "dontCrashOnNonZeroExitCodes": true, + "enableCommandScriptLinux": true, + "enableCommandScriptWindows": true, + "groupName": "sizingLoop", + "imitationScript": "", + "imitationToolOutputFilename": "", + "inputs": [ + { + "inputHandling": "Queue", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "Required", + "endpointName": "current_workflow_name", + "defaultInputHandling": "Queue", + "inputExecutionConstraint": "Required", + "endpointFolder": "" + } + ], + "integrationType": "Common", + "isActive": true, + "launchSettings": [ + { + "limitInstallationInstancesNumber": "10", + "limitInstallationInstances": "true", + "rootWorkingDirectory": "", + "host": "RCE", + "toolDirectory": "", + "version": "allTime" + } + ], + "outputs": [ + { + "inputHandling": "-", + "endpointFileName": "", + "endpointDataType": "ShortText", + "endpointName": "current_workflow_name", + "inputExecutionConstraint": "-", + "endpointFolder": "" + } + ], + "postScript": "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\t\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: constraint_analysis' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript": "", + "setToolDirAsWorkingDir": true, + "toolDescription": "", + "toolIconPath": "", + "toolIntegrationVersion": 1, + "toolIntegratorE-Mail": "", + "toolIntegratorName": "", + "toolName": "constraint_analysis", + "toolProperties": { + "Default": {} + }, + "uploadIcon": true +} \ No newline at end of file diff --git a/jsonFiles/cost_estimation/configuration.json b/jsonFiles/cost_estimation/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..2915f698a9b956ee2e6b816eff549cf3a0ba213f --- /dev/null +++ b/jsonFiles/cost_estimation/configuration.json @@ -0,0 +1,54 @@ +{ + "commandScriptLinux" : "cost_estimation.py -c ../workingDirectoryRCE/${in:current_workflow_name}/cost_estimation_conf.xml", + "commandScriptWindows" : "cost_estimation.py -c ../workingDirectoryRCE/${in:current_workflow_name}/cost_estimation_conf.xml", + "copyToolBehavior" : "never", + "deleteWorkingDirectoriesAfterWorkflowExecution" : true, + "documentationFilePath" : "", + "dontCrashOnNonZeroExitCodes" : true, + "enableCommandScriptLinux" : true, + "enableCommandScriptWindows" : true, + "groupName" : "postProcessing", + "imitationScript" : "", + "imitationToolOutputFilename" : "", + "inputs" : [ { + "inputHandling" : "Queue", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "defaultInputExecutionConstraint" : "Required", + "endpointName" : "current_workflow_name", + "defaultInputHandling" : "Queue", + "inputExecutionConstraint" : "Required", + "endpointFolder" : "" + } ], + "integrationType" : "Common", + "isActive" : true, + "launchSettings" : [ { + "limitInstallationInstancesNumber" : "10", + "limitInstallationInstances" : "true", + "rootWorkingDirectory" : "C:/Programs/UNICADOworkflow/workingDirectoryRCE", + "host" : "RCE", + "toolDirectory" : "C:/Programs/UNICADOworkflow/cost_estimation", + "version" : "allTime" + } ], + "outputs" : [ { + "inputHandling" : "-", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "endpointName" : "current_workflow_name", + "inputExecutionConstraint" : "-", + "endpointFolder" : "" + } ], + "postScript" : "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: cost_estimation' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript" : "", + "setToolDirAsWorkingDir" : true, + "toolDescription" : "", + "toolIconPath" : "", + "toolIntegrationVersion" : 1, + "toolIntegratorE-Mail" : "", + "toolIntegratorName" : "", + "toolName" : "cost_estimation", + "toolProperties" : { + "Default" : { } + }, + "uploadIcon" : true +} \ No newline at end of file diff --git a/jsonFiles/cpacsInterface/configuration.json b/jsonFiles/cpacsInterface/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..f29dae7afaeec0bec9e684b3130cc44c4ba0cba4 --- /dev/null +++ b/jsonFiles/cpacsInterface/configuration.json @@ -0,0 +1,60 @@ +{ + "commandScriptLinux": "./cpacsInterface -c ../workingDirectoryRCE/${in:current_workflow_name}/cpacsInterface_conf.xml", + "commandScriptWindows": "cpacsInterface.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/cpacsInterface_conf.xml", + "copyToolBehavior": "never", + "deleteWorkingDirectoriesAfterWorkflowExecution": true, + "documentationFilePath": "", + "dontCrashOnNonZeroExitCodes": true, + "enableCommandScriptLinux": true, + "enableCommandScriptWindows": true, + "groupName": "visualization", + "imitationScript": "", + "imitationToolOutputFilename": "", + "inputs": [ + { + "inputHandling": "Queue", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "Required", + "endpointName": "current_workflow_name", + "defaultInputHandling": "Queue", + "inputExecutionConstraint": "Required", + "endpointFolder": "" + } + ], + "integrationType": "Common", + "isActive": true, + "launchSettings": [ + { + "limitInstallationInstancesNumber": "10", + "limitInstallationInstances": "true", + "rootWorkingDirectory": "", + "host": "RCE", + "toolDirectory": "", + "version": "allTime" + } + ], + "outputs": [ + { + "inputHandling": "-", + "endpointFileName": "", + "endpointDataType": "ShortText", + "endpointName": "current_workflow_name", + "inputExecutionConstraint": "-", + "endpointFolder": "" + } + ], + "postScript": "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: cpacsInterface' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript": "", + "setToolDirAsWorkingDir": true, + "toolDescription": "", + "toolIconPath": "", + "toolIntegrationVersion": 1, + "toolIntegratorE-Mail": "", + "toolIntegratorName": "", + "toolName": "cpacsInterface", + "toolProperties": { + "Default": {} + }, + "uploadIcon": true +} \ No newline at end of file diff --git a/jsonFiles/create_mission_xml/configuration.json b/jsonFiles/create_mission_xml/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..6c11290e91bd48f79d8ceb5767ca5c4a321829fd --- /dev/null +++ b/jsonFiles/create_mission_xml/configuration.json @@ -0,0 +1,54 @@ +{ + "commandScriptLinux" : "./create_mission_xml -c ../workingDirectoryRCE/${in:current_workflow_name}/create_mission_xml_conf.xml", + "commandScriptWindows" : "create_mission_xml.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/create_mission_xml_conf.xml", + "copyToolBehavior" : "never", + "deleteWorkingDirectoriesAfterWorkflowExecution" : true, + "documentationFilePath" : "", + "dontCrashOnNonZeroExitCodes" : true, + "enableCommandScriptLinux" : true, + "enableCommandScriptWindows" : true, + "groupName" : "sizingLoop", + "imitationScript" : "", + "imitationToolOutputFilename" : "", + "inputs" : [ { + "inputHandling" : "Queue", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "defaultInputExecutionConstraint" : "Required", + "endpointName" : "current_workflow_name", + "defaultInputHandling" : "Queue", + "inputExecutionConstraint" : "Required", + "endpointFolder" : "" + } ], + "integrationType" : "Common", + "isActive" : true, + "launchSettings" : [ { + "limitInstallationInstancesNumber" : "10", + "host" : "RCE", + "toolDirectory" : "", + "limitInstallationInstances" : "true", + "version" : "allTime", + "rootWorkingDirectory" : "" + } ], + "outputs" : [ { + "inputHandling" : "-", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "endpointName" : "current_workflow_name", + "inputExecutionConstraint" : "-", + "endpointFolder" : "" + } ], + "postScript" : "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: create_mission_xml' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript" : "", + "setToolDirAsWorkingDir" : true, + "toolDescription" : "", + "toolIconPath" : "", + "toolIntegrationVersion" : 1, + "toolIntegratorE-Mail" : "", + "toolIntegratorName" : "", + "toolName" : "create_mission_xml", + "toolProperties" : { + "Default" : { } + }, + "uploadIcon" : true +} \ No newline at end of file diff --git a/jsonFiles/ecological_assessment/configuration.json b/jsonFiles/ecological_assessment/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..3921fc0097d32c3de10003ee5d9a64d1ae9e6fd5 --- /dev/null +++ b/jsonFiles/ecological_assessment/configuration.json @@ -0,0 +1,60 @@ +{ + "commandScriptLinux": "./ecological_assessment -c ../workingDirectoryRCE/${in:current_workflow_name}/ecological_assessment_conf.xml", + "commandScriptWindows": "ecological_assessment.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/ecological_assessment_conf.xml", + "copyToolBehavior": "never", + "deleteWorkingDirectoriesAfterWorkflowExecution": true, + "documentationFilePath": "", + "dontCrashOnNonZeroExitCodes": true, + "enableCommandScriptLinux": true, + "enableCommandScriptWindows": true, + "groupName": "postProcessing", + "imitationScript": "", + "imitationToolOutputFilename": "", + "inputs": [ + { + "inputHandling": "Queue", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "Required", + "endpointName": "current_workflow_name", + "defaultInputHandling": "Queue", + "inputExecutionConstraint": "Required", + "endpointFolder": "" + } + ], + "integrationType": "Common", + "isActive": true, + "launchSettings": [ + { + "limitInstallationInstancesNumber": "10", + "limitInstallationInstances": "true", + "rootWorkingDirectory": "", + "host": "RCE", + "toolDirectory": "", + "version": "allTime" + } + ], + "outputs": [ + { + "inputHandling": "-", + "endpointFileName": "", + "endpointDataType": "ShortText", + "endpointName": "current_workflow_name", + "inputExecutionConstraint": "-", + "endpointFolder": "" + } + ], + "postScript": "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: ecological_assessment' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript": "", + "setToolDirAsWorkingDir": true, + "toolDescription": "", + "toolIconPath": "", + "toolIntegrationVersion": 1, + "toolIntegratorE-Mail": "", + "toolIntegratorName": "", + "toolName": "ecological_assessment", + "toolProperties": { + "Default": {} + }, + "uploadIcon": true +} \ No newline at end of file diff --git a/jsonFiles/empennage_design/configuration.json b/jsonFiles/empennage_design/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..91ff9d0657f5536c2a188710f0fa2e5bda8bc3f8 --- /dev/null +++ b/jsonFiles/empennage_design/configuration.json @@ -0,0 +1,60 @@ +{ + "commandScriptLinux": "./empennage_design -c ../workingDirectoryRCE/${in:current_workflow_name}/empennage_design_conf.xml", + "commandScriptWindows": "empennage_design.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/empennage_design_conf.xml", + "copyToolBehavior": "never", + "deleteWorkingDirectoriesAfterWorkflowExecution": true, + "documentationFilePath": "", + "dontCrashOnNonZeroExitCodes": true, + "enableCommandScriptLinux": true, + "enableCommandScriptWindows": true, + "groupName": "sizingLoop", + "imitationScript": "", + "imitationToolOutputFilename": "", + "inputs": [ + { + "inputHandling": "Queue", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "Required", + "endpointName": "current_workflow_name", + "defaultInputHandling": "Queue", + "inputExecutionConstraint": "Required", + "endpointFolder": "" + } + ], + "integrationType": "Common", + "isActive": true, + "launchSettings": [ + { + "limitInstallationInstancesNumber": "10", + "limitInstallationInstances": "true", + "rootWorkingDirectory": "", + "host": "RCE", + "toolDirectory": "", + "version": "allTime" + } + ], + "outputs": [ + { + "inputHandling": "-", + "endpointFileName": "", + "endpointDataType": "ShortText", + "endpointName": "current_workflow_name", + "inputExecutionConstraint": "-", + "endpointFolder": "" + } + ], + "postScript": "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: empennage_design' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript": "", + "setToolDirAsWorkingDir": true, + "toolDescription": "", + "toolIconPath": "", + "toolIntegrationVersion": 1, + "toolIntegratorE-Mail": "", + "toolIntegratorName": "", + "toolName": "empennage_design", + "toolProperties": { + "Default": {} + }, + "uploadIcon": true +} \ No newline at end of file diff --git a/jsonFiles/fuselage_design/configuration.json b/jsonFiles/fuselage_design/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..cadd128b9be79e4eb83e6bd397b74a8fd555645f --- /dev/null +++ b/jsonFiles/fuselage_design/configuration.json @@ -0,0 +1,59 @@ +{ + "commandScriptLinux" : "fuselage_design.py -c ../workingDirectoryRCE/${in:current_workflow_name}/fuselage_design_conf.xml", + "commandScriptWindows" : "fuselage_design.py -c ../workingDirectoryRCE/${in:current_workflow_name}/fuselage_design_conf.xml", + "copyToolBehavior" : "never", + "deleteWorkingDirectoriesAfterWorkflowExecution" : true, + "deleteWorkingDirectoriesNever" : false, + "documentationFilePath" : "", + "dontCrashOnNonZeroExitCodes" : true, + "enableCommandScriptLinux" : true, + "enableCommandScriptWindows" : true, + "groupName" : "sizingLoop", + "imitationScript" : "", + "imitationToolOutputFilename" : "", + "inputs" : [ + { + "inputHandling" : "Queue", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "defaultInputExecutionConstraint" : "Required", + "endpointName" : "current_workflow_name", + "defaultInputHandling" : "Queue", + "inputExecutionConstraint" : "Required", + "endpointFolder" : "" + } +], + "integrationType" : "Common", + "isActive" : true, + "launchSettings" : [ + { + "limitInstallationInstancesNumber" : "10", + "host" : "RCE", + "toolDirectory" : "C:/Programs/UNICADOworkflow/fuselage_design", + "limitInstallationInstances" : "true", + "version" : "allTime", + "rootWorkingDirectory" : "C:/Programs/UNICADOworkflow/workingDirectoryRCE" + } +], + "outputs" : [ + { + "inputHandling" : "-", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "endpointName" : "current_workflow_name", + "inputExecutionConstraint" : "-", + "endpointFolder" : "" + } +], + "postScript" : "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: fuselage_design' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript" : "", + "setToolDirAsWorkingDir" : true, + "toolDescription" : "", + "toolIntegrationVersion" : 1, + "toolIntegratorE-Mail" : "", + "toolIntegratorName" : "", + "toolName" : "fuselage_design", + "toolProperties" : { + "Default" : { } + } +} \ No newline at end of file diff --git a/jsonFiles/initial_sizing/configuration.json b/jsonFiles/initial_sizing/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..ff97a4d59b7b0a0ea74a3dcb2444d8ff9ebb7d11 --- /dev/null +++ b/jsonFiles/initial_sizing/configuration.json @@ -0,0 +1,55 @@ +{ + "commandScriptLinux" : "./initial_sizing -c ../workingDirectoryRCE/${in:current_workflow_name}/initial_sizing_conf.xml", + "commandScriptWindows" : "initial_sizing.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/initial_sizing_conf.xml", + "copyToolBehavior" : "never", + "deleteWorkingDirectoriesAfterWorkflowExecution" : true, + "deleteWorkingDirectoriesNever" : false, + "documentationFilePath" : "", + "dontCrashOnNonZeroExitCodes" : true, + "enableCommandScriptLinux" : true, + "enableCommandScriptWindows" : true, + "groupName" : "preSizing", + "imitationScript" : "", + "imitationToolOutputFilename" : "", + "inputs" : [ { + "inputHandling" : "Queue", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "defaultInputExecutionConstraint" : "Required", + "endpointName" : "current_workflow_name", + "defaultInputHandling" : "Queue", + "inputExecutionConstraint" : "Required", + "endpointFolder" : "" + } ], + "integrationType" : "Common", + "isActive" : true, + "launchSettings" : [ { + "limitInstallationInstancesNumber" : "10", + "host" : "RCE", + "toolDirectory" : "", + "limitInstallationInstances" : "true", + "version" : "allTime", + "rootWorkingDirectory" : "" + } ], + "outputs" : [ { + "inputHandling" : "-", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "endpointName" : "current_workflow_name", + "inputExecutionConstraint" : "-", + "endpointFolder" : "" + } ], + "postScript" : "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_temp_working_directory = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_temp_working_directory + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_temp_working_directory + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: initial_sizing' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript" : "", + "setToolDirAsWorkingDir" : true, + "toolDescription" : "", + "toolIconPath" : "", + "toolIntegrationVersion" : 1, + "toolIntegratorE-Mail" : "", + "toolIntegratorName" : "", + "toolName" : "initial_sizing", + "toolProperties" : { + "Default" : { } + }, + "uploadIcon" : true +} \ No newline at end of file diff --git a/jsonFiles/landing_gear_design/configuration.json b/jsonFiles/landing_gear_design/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..b63edca8c3e5ea3e164916ab5574be3c0146e9b6 --- /dev/null +++ b/jsonFiles/landing_gear_design/configuration.json @@ -0,0 +1,54 @@ +{ + "commandScriptLinux" : "landing_gear_design.py -c ../workingDirectoryRCE/${in:current_workflow_name}/landing_gear_design_conf.xml", + "commandScriptWindows" : "landing_gear_design.py -c ../workingDirectoryRCE/${in:current_workflow_name}/landing_gear_design_conf.xml", + "copyToolBehavior" : "never", + "deleteWorkingDirectoriesAfterWorkflowExecution" : true, + "documentationFilePath" : "", + "dontCrashOnNonZeroExitCodes" : true, + "enableCommandScriptLinux" : true, + "enableCommandScriptWindows" : true, + "groupName" : "sizingLoop", + "imitationScript" : "", + "imitationToolOutputFilename" : "", + "inputs" : [ { + "inputHandling" : "Queue", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "defaultInputExecutionConstraint" : "Required", + "endpointName" : "current_workflow_name", + "defaultInputHandling" : "Queue", + "inputExecutionConstraint" : "Required", + "endpointFolder" : "" + } ], + "integrationType" : "Common", + "isActive" : true, + "launchSettings" : [ { + "limitInstallationInstancesNumber" : "10", + "limitInstallationInstances" : "true", + "rootWorkingDirectory" : "C:/Programs/UNICADOworkflow/workingDirectoryRCE", + "host" : "RCE", + "toolDirectory" : "C:/Programs/UNICADOworkflow/landing_gear_design", + "version" : "allTime" + } ], + "outputs" : [ { + "inputHandling" : "-", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "endpointName" : "current_workflow_name", + "inputExecutionConstraint" : "-", + "endpointFolder" : "" + } ], + "postScript" : "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\t\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: landing_gear_design' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript" : "", + "setToolDirAsWorkingDir" : true, + "toolDescription" : "", + "toolIconPath" : "", + "toolIntegrationVersion" : 1, + "toolIntegratorE-Mail" : "", + "toolIntegratorName" : "", + "toolName" : "landing_gear_design", + "toolProperties" : { + "Default" : { } + }, + "uploadIcon" : true +} \ No newline at end of file diff --git a/jsonFiles/mission_analysis/configuration.json b/jsonFiles/mission_analysis/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..fc2d02476adc485ea6351cfbf525730220e8c1c6 --- /dev/null +++ b/jsonFiles/mission_analysis/configuration.json @@ -0,0 +1,60 @@ +{ + "commandScriptLinux": "./mission_analysis -c ../workingDirectoryRCE/${in:current_workflow_name}/mission_analysis_conf.xml", + "commandScriptWindows": "mission_analysis.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/mission_analysis_conf.xml", + "copyToolBehavior": "never", + "deleteWorkingDirectoriesAfterWorkflowExecution": true, + "documentationFilePath": "", + "dontCrashOnNonZeroExitCodes": true, + "enableCommandScriptLinux": true, + "enableCommandScriptWindows": true, + "groupName": "sizingLoop", + "imitationScript": "", + "imitationToolOutputFilename": "", + "inputs": [ + { + "inputHandling": "Queue", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "Required", + "endpointName": "current_workflow_name", + "defaultInputHandling": "Queue", + "inputExecutionConstraint": "Required", + "endpointFolder": "" + } + ], + "integrationType": "Common", + "isActive": true, + "launchSettings": [ + { + "limitInstallationInstancesNumber": "10", + "limitInstallationInstances": "true", + "rootWorkingDirectory": "", + "host": "RCE", + "toolDirectory": "", + "version": "allTime" + } + ], + "outputs": [ + { + "inputHandling": "-", + "endpointFileName": "", + "endpointDataType": "ShortText", + "endpointName": "current_workflow_name", + "inputExecutionConstraint": "-", + "endpointFolder": "" + } + ], + "postScript": "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + \t\t'/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: mission_analysis' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript": "", + "setToolDirAsWorkingDir": true, + "toolDescription": "", + "toolIconPath": "", + "toolIntegrationVersion": 1, + "toolIntegratorE-Mail": "", + "toolIntegratorName": "", + "toolName": "mission_analysis", + "toolProperties": { + "Default": {} + }, + "uploadIcon": true +} \ No newline at end of file diff --git a/jsonFiles/performance_assessment/configuration.json b/jsonFiles/performance_assessment/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..291f562427681eb5c42c201620c2f13841907119 --- /dev/null +++ b/jsonFiles/performance_assessment/configuration.json @@ -0,0 +1,60 @@ +{ + "commandScriptLinux": "./performance_assessment -c ../workingDirectoryRCE/${in:current_workflow_name}/performance_assessment_conf.xml", + "commandScriptWindows": "performance_assessment.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/performance_assessment_conf.xml", + "copyToolBehavior": "never", + "deleteWorkingDirectoriesAfterWorkflowExecution": true, + "documentationFilePath": "", + "dontCrashOnNonZeroExitCodes": true, + "enableCommandScriptLinux": true, + "enableCommandScriptWindows": true, + "groupName": "postProcessing", + "imitationScript": "", + "imitationToolOutputFilename": "", + "inputs": [ + { + "inputHandling": "Queue", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "Required", + "endpointName": "current_workflow_name", + "defaultInputHandling": "Queue", + "inputExecutionConstraint": "Required", + "endpointFolder": "" + } + ], + "integrationType": "Common", + "isActive": true, + "launchSettings": [ + { + "limitInstallationInstancesNumber": "10", + "limitInstallationInstances": "true", + "rootWorkingDirectory": "", + "host": "RCE", + "toolDirectory": "", + "version": "allTime" + } + ], + "outputs": [ + { + "inputHandling": "-", + "endpointFileName": "", + "endpointDataType": "ShortText", + "endpointName": "current_workflow_name", + "inputExecutionConstraint": "-", + "endpointFolder": "" + } + ], + "postScript": "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: performance_assessment' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript": "", + "setToolDirAsWorkingDir": true, + "toolDescription": "", + "toolIconPath": "", + "toolIntegrationVersion": 1, + "toolIntegratorE-Mail": "", + "toolIntegratorName": "", + "toolName": "performance_assessment", + "toolProperties": { + "Default": {} + }, + "uploadIcon": true +} \ No newline at end of file diff --git a/jsonFiles/propulsion_design/configuration.json b/jsonFiles/propulsion_design/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..89341c5603ec0f5b12d1e86cca210d6569b8e356 --- /dev/null +++ b/jsonFiles/propulsion_design/configuration.json @@ -0,0 +1,60 @@ +{ + "commandScriptLinux": "./propulsion_design -c ../workingDirectoryRCE/${in:current_workflow_name}/propulsion_design_conf.xml", + "commandScriptWindows": "propulsion_design.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/propulsion_design_conf.xml", + "copyToolBehavior": "never", + "deleteWorkingDirectoriesAfterWorkflowExecution": true, + "documentationFilePath": "", + "dontCrashOnNonZeroExitCodes": true, + "enableCommandScriptLinux": true, + "enableCommandScriptWindows": true, + "groupName": "sizingLoop", + "imitationScript": "", + "imitationToolOutputFilename": "", + "inputs": [ + { + "inputHandling": "Queue", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "Required", + "endpointName": "current_workflow_name", + "defaultInputHandling": "Queue", + "inputExecutionConstraint": "Required", + "endpointFolder": "" + } + ], + "integrationType": "Common", + "isActive": true, + "launchSettings": [ + { + "limitInstallationInstancesNumber": "10", + "limitInstallationInstances": "true", + "rootWorkingDirectory": "", + "host": "RCE", + "toolDirectory": "", + "version": "allTime" + } + ], + "outputs": [ + { + "inputHandling": "-", + "endpointFileName": "", + "endpointDataType": "ShortText", + "endpointName": "current_workflow_name", + "inputExecutionConstraint": "-", + "endpointFolder": "" + } + ], + "postScript": "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: propulsion_design' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript": "", + "setToolDirAsWorkingDir": true, + "toolDescription": "", + "toolIconPath": "", + "toolIntegrationVersion": 1, + "toolIntegratorE-Mail": "", + "toolIntegratorName": "", + "toolName": "propulsion_design", + "toolProperties": { + "Default": {} + }, + "uploadIcon": true +} \ No newline at end of file diff --git a/jsonFiles/report_generator/configuration.json b/jsonFiles/report_generator/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..fc7ef8d65df19e75e6a89b0e76b1d0ba33c6835f --- /dev/null +++ b/jsonFiles/report_generator/configuration.json @@ -0,0 +1,70 @@ +{ + "commandScriptLinux": "./report_generator -c ../workingDirectoryRCE/${in:current_workflow_name}/report_generator_conf.xml", + "commandScriptWindows": "report_generator.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/report_generator_conf.xml", + "copyToolBehavior": "never", + "deleteWorkingDirectoriesAfterWorkflowExecution": true, + "documentationFilePath": "", + "dontCrashOnNonZeroExitCodes": true, + "enableCommandScriptLinux": true, + "enableCommandScriptWindows": true, + "groupName": "postProcessing", + "imitationScript": "", + "imitationToolOutputFilename": "", + "inputs": [ + { + "inputHandling": "Queue", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "Required", + "endpointName": "current_workflow_name", + "defaultInputHandling": "Queue", + "inputExecutionConstraint": "Required", + "endpointFolder": "" + }, + { + "inputHandling": "Single", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "RequiredIfConnected", + "endpointName": "optional_trigger_signal", + "defaultInputHandling": "Single", + "inputExecutionConstraint": "RequiredIfConnected", + "endpointFolder": "" + } + ], + "integrationType": "Common", + "isActive": true, + "launchSettings": [ + { + "limitInstallationInstancesNumber": "10", + "limitInstallationInstances": "true", + "rootWorkingDirectory": "", + "host": "RCE", + "toolDirectory": "", + "version": "allTime" + } + ], + "outputs": [ + { + "inputHandling": "-", + "endpointFileName": "", + "endpointDataType": "ShortText", + "endpointName": "current_workflow_name", + "inputExecutionConstraint": "-", + "endpointFolder": "" + } + ], + "postScript": "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: report_generator' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript": "", + "setToolDirAsWorkingDir": true, + "toolDescription": "", + "toolIconPath": "", + "toolIntegrationVersion": 1, + "toolIntegratorE-Mail": "", + "toolIntegratorName": "", + "toolName": "report_generator", + "toolProperties": { + "Default": {} + }, + "uploadIcon": true +} \ No newline at end of file diff --git a/jsonFiles/systems_design/configuration.json b/jsonFiles/systems_design/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..ca252cda3596886ce511632a525830f281e52a88 --- /dev/null +++ b/jsonFiles/systems_design/configuration.json @@ -0,0 +1,60 @@ +{ + "commandScriptLinux": "./systems_design -c ../workingDirectoryRCE/${in:current_workflow_name}/systems_design_conf.xml", + "commandScriptWindows": "systems_design.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/systems_design_conf.xml", + "copyToolBehavior": "never", + "deleteWorkingDirectoriesAfterWorkflowExecution": true, + "documentationFilePath": "", + "dontCrashOnNonZeroExitCodes": true, + "enableCommandScriptLinux": true, + "enableCommandScriptWindows": true, + "groupName": "sizingLoop", + "imitationScript": "", + "imitationToolOutputFilename": "", + "inputs": [ + { + "inputHandling": "Queue", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "Required", + "endpointName": "current_workflow_name", + "defaultInputHandling": "Queue", + "inputExecutionConstraint": "Required", + "endpointFolder": "" + } + ], + "integrationType": "Common", + "isActive": true, + "launchSettings": [ + { + "limitInstallationInstancesNumber": "10", + "limitInstallationInstances": "true", + "rootWorkingDirectory": "", + "host": "RCE", + "toolDirectory": "", + "version": "allTime" + } + ], + "outputs": [ + { + "inputHandling": "-", + "endpointFileName": "", + "endpointDataType": "ShortText", + "endpointName": "current_workflow_name", + "inputExecutionConstraint": "-", + "endpointFolder": "" + } + ], + "postScript": "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: systems_design' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript": "", + "setToolDirAsWorkingDir": true, + "toolDescription": "", + "toolIconPath": "", + "toolIntegrationVersion": 1, + "toolIntegratorE-Mail": "", + "toolIntegratorName": "", + "toolName": "systems_design", + "toolProperties": { + "Default": {} + }, + "uploadIcon": true +} \ No newline at end of file diff --git a/jsonFiles/tank_design/configuration.json b/jsonFiles/tank_design/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..5217307492b6e318bb6048d019acfc3514677055 --- /dev/null +++ b/jsonFiles/tank_design/configuration.json @@ -0,0 +1,54 @@ +{ + "commandScriptLinux" : "tank_design.py -c ../workingDirectoryRCE/${in:current_workflow_name}/tank_design_conf.xml", + "commandScriptWindows" : "tank_design.py -c ../workingDirectoryRCE/${in:current_workflow_name}/tank_design_conf.xml", + "copyToolBehavior" : "never", + "deleteWorkingDirectoriesAfterWorkflowExecution" : true, + "documentationFilePath" : "", + "dontCrashOnNonZeroExitCodes" : true, + "enableCommandScriptLinux" : true, + "enableCommandScriptWindows" : true, + "groupName" : "sizingLoop", + "imitationScript" : "", + "imitationToolOutputFilename" : "", + "inputs" : [ { + "inputHandling" : "Queue", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "defaultInputExecutionConstraint" : "Required", + "endpointName" : "current_workflow_name", + "defaultInputHandling" : "Queue", + "inputExecutionConstraint" : "Required", + "endpointFolder" : "" + } ], + "integrationType" : "Common", + "isActive" : true, + "launchSettings" : [ { + "limitInstallationInstancesNumber" : "10", + "limitInstallationInstances" : "true", + "rootWorkingDirectory" : "C:/Programs/UNICADOworkflow/workingDirectoryRCE", + "host" : "RCE", + "toolDirectory" : "C:/Programs/UNICADOworkflow/tank_design", + "version" : "allTime" + } ], + "outputs" : [ { + "inputHandling" : "-", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "endpointName" : "current_workflow_name", + "inputExecutionConstraint" : "-", + "endpointFolder" : "" + } ], + "postScript" : "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\t\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: tank_design' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript" : "", + "setToolDirAsWorkingDir" : true, + "toolDescription" : "", + "toolIconPath" : "", + "toolIntegrationVersion" : 1, + "toolIntegratorE-Mail" : "", + "toolIntegratorName" : "", + "toolName" : "tank_design", + "toolProperties" : { + "Default" : { } + }, + "uploadIcon" : true +} \ No newline at end of file diff --git a/jsonFiles/weight_and_balance_analysis/configuration.json b/jsonFiles/weight_and_balance_analysis/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..6a501bbfcacd06dbf859ff1f30f1154eb337a7b1 --- /dev/null +++ b/jsonFiles/weight_and_balance_analysis/configuration.json @@ -0,0 +1,54 @@ +{ + "commandScriptLinux" : "weight_and_balance_analysis.py -c ../workingDirectoryRCE/${in:current_workflow_name}/weight_and_balance_analysis_conf.xml", + "commandScriptWindows" : "weight_and_balance_analysis.py -c ../workingDirectoryRCE/${in:current_workflow_name}/weight_and_balance_analysis_conf.xml", + "copyToolBehavior" : "never", + "deleteWorkingDirectoriesAfterWorkflowExecution" : true, + "documentationFilePath" : "", + "dontCrashOnNonZeroExitCodes" : true, + "enableCommandScriptLinux" : true, + "enableCommandScriptWindows" : true, + "groupName" : "sizingLoop", + "imitationScript" : "", + "imitationToolOutputFilename" : "", + "inputs" : [ { + "inputHandling" : "Queue", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "defaultInputExecutionConstraint" : "Required", + "endpointName" : "current_workflow_name", + "defaultInputHandling" : "Queue", + "inputExecutionConstraint" : "Required", + "endpointFolder" : "" + } ], + "integrationType" : "Common", + "isActive" : true, + "launchSettings" : [ { + "limitInstallationInstancesNumber" : "10", + "limitInstallationInstances" : "true", + "rootWorkingDirectory" : "C:/Programs/UNICADOworkflow/workingDirectoryRCE", + "host" : "RCE", + "toolDirectory" : "C:/Programs/UNICADOworkflow/weight_and_balance_analysis", + "version" : "allTime" + } ], + "outputs" : [ { + "inputHandling" : "-", + "endpointFileName" : "", + "endpointDataType" : "ShortText", + "endpointName" : "current_workflow_name", + "inputExecutionConstraint" : "-", + "endpointFolder" : "" + } ], + "postScript" : "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: weight_and_balance_analysis' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript" : "", + "setToolDirAsWorkingDir" : true, + "toolDescription" : "", + "toolIconPath" : "", + "toolIntegrationVersion" : 1, + "toolIntegratorE-Mail" : "", + "toolIntegratorName" : "", + "toolName" : "weight_and_balance_analysis", + "toolProperties" : { + "Default" : { } + }, + "uploadIcon" : true +} \ No newline at end of file diff --git a/jsonFiles/wing_design/configuration.json b/jsonFiles/wing_design/configuration.json new file mode 100644 index 0000000000000000000000000000000000000000..fd777edb0bc64b0200c683354d7b8dad60a9e475 --- /dev/null +++ b/jsonFiles/wing_design/configuration.json @@ -0,0 +1,60 @@ +{ + "commandScriptLinux": "./wing_design -c ../workingDirectoryRCE/${in:current_workflow_name}/wing_design_conf.xml", + "commandScriptWindows": "wing_design.exe -c ../workingDirectoryRCE/${in:current_workflow_name}/wing_design_conf.xml", + "copyToolBehavior": "never", + "deleteWorkingDirectoriesAfterWorkflowExecution": true, + "documentationFilePath": "", + "dontCrashOnNonZeroExitCodes": true, + "enableCommandScriptLinux": true, + "enableCommandScriptWindows": true, + "groupName": "sizingLoop", + "imitationScript": "", + "imitationToolOutputFilename": "", + "inputs": [ + { + "inputHandling": "Queue", + "endpointFileName": "", + "endpointDataType": "ShortText", + "defaultInputExecutionConstraint": "Required", + "endpointName": "current_workflow_name", + "defaultInputHandling": "Queue", + "inputExecutionConstraint": "Required", + "endpointFolder": "" + } + ], + "integrationType": "Common", + "isActive": true, + "launchSettings": [ + { + "limitInstallationInstancesNumber": "10", + "limitInstallationInstances": "true", + "rootWorkingDirectory": "", + "host": "RCE", + "toolDirectory": "", + "version": "allTime" + } + ], + "outputs": [ + { + "inputHandling": "-", + "endpointFileName": "", + "endpointDataType": "ShortText", + "endpointName": "current_workflow_name", + "inputExecutionConstraint": "-", + "endpointFolder": "" + } + ], + "postScript": "import os\r\ncurrent_working_dir = \"${in:current_workflow_name}\"\r\n\r\nif ${addProp:exitCode} != 0:\r\n\t### read sys path for python scripts\r\n\tuser_path_string = os.path.expanduser(\"~\")\r\n\r\n\t## convert path of curent working directory to a python path -> \\ to /\r\n\tuser_path_string = user_path_string.replace(os.sep, '/')\r\n\r\n\t## generate sys paths from file in .rce-directory\r\n\tinstall_path = open(user_path_string + '/.rce/default/integration/tools/common/absolutPathToUNICADOInstallDirectory.txt','r')\r\n\tinstall_path_directory = str(install_path.read())\r\n\tinstall_path_directory = install_path_directory.replace(os.sep, '/')\r\n\r\n\t## path to working directory of rce \r\n\tpath_of_working_directory_rce = install_path_directory + 'workingDirectoryRCE/' + current_working_dir\r\n\r\n\t## write error data to system\r\n\terror_dat = open(path_of_working_directory_rce + '/temp/workflowExecutionError.dat', 'a+')\r\n\terror_dat.close()\r\n\r\n\t## write tool name to tool error list of current workflow loop\r\n\ttool_error_list = open(path_of_working_directory_rce + '/temp/toolErrorList.log', 'a+')\r\n\ttool_error_list.write('Error occurred in design tool: wing_design' + '\\n')\r\n\ttool_error_list.close()\r\n\r\n${out:current_workflow_name} = current_working_dir\r\n", + "preScript": "", + "setToolDirAsWorkingDir": true, + "toolDescription": "", + "toolIconPath": "", + "toolIntegrationVersion": 1, + "toolIntegratorE-Mail": "", + "toolIntegratorName": "", + "toolName": "wing_design", + "toolProperties": { + "Default": {} + }, + "uploadIcon": true +} \ No newline at end of file