Проблемы интеграции своих программ с чужими все более широко охватывают область разработки программного обеспечения. Многие программисты считают, что нужно писать свое, интегрироваться с чужими разработками это плохо, причем не учитывают размеры команд разработчиков, их опыт и целесообразность. Да и в течении года-два реализовать ту же самую систему расчета методом конечных элементов хоть и можно, но высокого качества она не будет. Разве можно за пару лет повторить путь развития проекта, который развивался 10–20 лет? Естественно нельзя и часто нецелесообразно.
Никто ведь не спорит, что в России самыми популярными программными средствами являются ANSYS, ABAQUS, SCAD, LIRA, PLAXIS и т.д. И какова вероятность занять свою нишу в этом уже давно поделенном участке рынка? Да и мало кто захочет переучиваться под новую программу. А вот проблемы интеграции своих программ с мощными расчетными системами и перенос результатов из одной в другую задача намного более востребованная. Мы имеем мощные вычислительные пакеты, на разработку и отладку которых ушло много лет, имеем некую задачу, реализовать которую в одной вычислительной системе подчас весьма сложно, или отсутствуют необходимые нам возможности, которые мы можем сами реализовать.
Этой задачей я занялся при необходимости выполнить параметрическую оптимизацию моделей материалов, для соответствия результатов моделирования группы реальных испытаний с их расчетными моделями. Это еще усугубляется тем, что каждый программный продукт считает по своему и результаты расчетов в ANSYS не будут идентичными расчету в ABAQUS при одинаковых параметрах модели. Это зависит от конкретной реализации расчетов, типов конечных элементов и даже расположения узлов сетки. В итоге инженер вводит параметры материалов, не зная, на сколько точно они соответствуют реальности. Причем вариативность оптимальных параметров может достигать 70% от результатов испытаний, тем более что обработка испытаний выполняется в рамках одной, максимум двух условий прочности, зачастую самых простых, а для сложных моделей не всегда даже известно как определить требуемые параметры, особенно когда их предлагают задать исходя из опыта в каком либо диапазоне.
Именно для решения этой проблемы и была поставлена задача интегрировать программу с расчетным ядром ANSYS. Задача интеграции была успешно решена, хотя и не без проблем. Причем главной проблемой оказалось полное отсутствие документации в свободном доступе, так что я думаю информация по реализации интеграции будет весьма полезна тем, у кого возникли такие же проблемы, как и у меня.
Механизм интеграции
С началом интеграции всех программных продуктов компании ANSYS под единую среду ANSYS Workbench возникла возможность интегрировать свои программы непосредственно с этой средой. Сама архитектура ANSYS Workbench построена на использовании Java и VB скриптов, посредством которых и происходит вызов тех или иных модулей ANSYS, которые называются апплетами (Applets).
Самым первым вариантом, который приходит на ум любому разработчику, что достаточно вызывать из программы написанные ранее или сгенерированные скрипты на Java-Script. Однако такой путь содержит один достаточно серьезный изъян: каждый раз при вызове скрипта необходимо будет заново открывать Workbench, инициализировать апплет ANSYS и только после этого отсылать ядру команды для расчета. Это видно из скрипта, который расположен в C:Program FilesANSYS Incv110AISOLSDKsamplesJPDLDemo.js. Текст скрипта приведен ниже:
, true);
- oWB = new ActiveXObject("AnsysWB.WB.90");
- oWB.StartApplet = "AAOApplet";
- oWB.Run();
- oWB.Title="ANSYS Workbench";
- ConnectToAnsysCS();
- var fs, a;
- ForAppending = 8;
- fs = new ActiveXObject("Scripting.FileSystemObject");
- a = fs.CreateTextFile("d:\rundir\testfile.txt"
with (ansys.cmd) { for (l=4;l<10;l++) { _clear(); _prep7(); _view(null,-1,-2,-3); var w=3; var d=2; block(null,l,null,w,null,d); kp4x = ansys.apdl.get("KP",4,"LOC","X"); commentx = "KP 4 X LOC = "; commentx += kp4x; kp4y = ansys.apdl.get("KP",4,"LOC","Y"); commenty = "KP 4 Y LOC = "; commenty += kp4y; kp4z = ansys.apdl.get("KP",4,"LOC","Z"); commentz = "KP 4 Z LOC = "; commentz += kp4z; ret = _com(commentx); ret = _com(commenty); ret = _com(commentz); this.a.WriteLine(commentx); this.a.WriteLine(commenty); this.a.WriteLine(commentz); sphere(1); vsbv(1,2); et(2,92); vmesh("all"); da(9,"all"); sfa(4,1,"pres",10000000); mp("EX ",1, 27E+06); mp("PRXY",1,0.3); finish(); _solu(); solve(); finish(); _post1(); set("LAST"); plnsol("S","EQV"); _replot(); finish(); } } a.Close();
Если генерировать программно скрипты и их запускать, то это будет очень неудобно, т.к. сам скрипт будет выполняться внешним обработчиком, что существенно усложнит его отладку. Да и генерировать скрипт, который отвечает за полный цикл работы очень неудобно.
Главной проблемой было получение дескриптора на среду WorkBench и его сохранение. С этой точки зрения наиболее интересной является часть, отвечающая за загрузку среды Workbench:
- oWB = new ActiveXObject("AnsysWB.WB.90");
- oWB.StartApplet = "AAOApplet";
- oWB.Run();
- oWB.Title="ANSYS Workbench";
При изучении этого и других скриптов у меня возник вопрос: если это может Java-Script, то почему не может C#? И оказалось, что вполне может. При установке ANSYS MS Visual Studio сама находит ссылки на все библиотеки ANSYS, но они, по крайней мере в 11 версии, сильно «урезанные“. Но среди них нашлась библиотека, которая как раз отвечала за программную работу со средой Workbench: AnsysWB, которая подключается в виде пространства имен ANSYSWBLib.
Для запуска ANSYS оказалось достаточно написать следующий код:
- ANSYSWBLib.WBClass wb = new ANSYSWBLib.WBClass(); // Создаем объект ABSYS WB
- wb.CommandLine.Directory = @"c:tmp"; // Указываем рабочий каталог
- wb.CommandLine.JobName = "Test"; // Указываем название проекта
- wb.CommandLine.CadFile = @"c:tmpqwe.ewq"; // Указываем рабочий файл
- wb.StartApplet = "AAOApplet"; // Указываем, что нам нужен модуль классического ANSYS
- wb.Run(0);
Итак, этот код позволяет запустить ANSYS, причем в качестве стартового апплета указан непосредственно апплет классического ANSYS, который и будет запущен. Но далее нам нужно организовать передачу управляющих команд ему, и вот тут возникли сложности. В Java-Script это реализуется следующей строчкой
- App.Script.ans_sendcommand(Command)
Где App — ссылка на дескриптор модуля AAOApplet. Она хранится в свойстве класса
- wb.AppletList.get_WBApplet("AAOApplet").Applet.App
Но в 11 версии ANSYS в подключаемых библиотеках я не нашел интерфейса для работы с апплетом ANSYS. К счастью в NET FrameWork есть такая библиотека, как Microsoft.JScript, которая позволяет прямо в памяти компилировать скрипты JScript и исполнять их, причем можно реализовать из C# вызов необходимой функции.
Для этой цели я решил написать свой класс, который бы реализовывал все необходимые возможности, для работы с ANSYS/ Код класса представлен ниже.
- class WBCommand
- {
- ANSYSWBLib.WBClass wb;
- public WBCommand(ANSYSWBLib.WBClass WB)
- {
- wb = WB;
- aao = wb.AppletList.get_WBApplet("AAOApplet").Applet.App;
- string code = @"function closure()
- {
- return function (App, Command)
- {
- return App.Script.ans_sendcommand(Command);
- }
- }
- closure()";
- //
- SendCommandClosure = (Closure)Microsoft.JScript.Eval.JScriptEvaluate(code, Microsoft.JScript.Vsa.VsaEngine.CreateEngine());
- }
- private Closure SendCommandClosure = null;
- private Closure SetWorkingDirectoryClosure = null;
- private object aao = null;
- public object SendCommand(string Command)
- {
- return SendCommandClosure.Invoke(null, new object[] { aao, Command });
- }
- public void SetWorkingDirectory(string WorkingDirectory)
- {
- SendCommand("/CWD, " + WorkingDirectory);
- }
- }
При вызове конструктора моего класса происходит формирование вызываемой процедуры на JScript и сохранение ее точки входа:
- string code = @"function closure()
- {
- return function (App, Command)
- {
- return App.Script.ans_sendcommand(Command);
- }
- }
- closure()";
- //
- SendCommandClosure = (Closure)Microsoft.JScript.Eval.JScriptEvaluate(code, Microsoft.JScript.Vsa.VsaEngine.CreateEngine());
Для вызова ее был реализован метод:
- public object SendCommand(string Command)
- {
- return SendCommandClosure.Invoke(null, new object[] { aao, Command });
- }
В качестве входного параметра которому необходима текстовая команда, а при вызове JSCript функции дополнительно передается ссылка на апплет, которая была получена в конструкторе и сохранена в переменную aao.
Теперь вызывая метод SendCommand можно будет передавать ANSYS команды на языке APDL из нашего внешнего приложения, выполняя все необходимые действия. Этот метод эмулирует ввод команд непосредственно в командную строку ANSYS, но на многие команды ведь необходимо подтверждение. Для того, что бы избежать запросов на подтверждение действий достаточно не вставлять команды по одной, а записать их в APDL файл и вызвать команду SendCommand ("/inp, f, apdl»). В этом случае ANSYS не будет требовать подтверждения на выполнение той или иной операции.
Работу с новыми версиями ANSYS я не проверял, так что возможно сейчас уже можно полностью отказаться от использования JS, но если необходима совместимость с 11 версией, то иного способа интегрировать свою программу я не нашел.
Автор: XAHOK