Наш пример представляет собой расчет нагрузки от воды, приложенной к балке, которая увеличивается из-за прогиба балки. Для удобства пользователь должен иметь возможность выбрать балку или балки. Кроме того, не должны изменяться дополнительные нагрузки на кровлю, которые действуют в одном и том же загружении независимо от нагрузки от воды. Известны/применены следующие граничные условия:
- Уровень воды над недеформированной системой
- Ширина зоны подачи стержня для распределенной по площади нагрузки
- Номер загружения, в котором должна быть приложена нагрузка
- Нагрузка от воды на м уровня воды (10000 Н/м³)
- Идентификатор, используемый для идентификации распределенных нагрузок
Поэтому в программе создаются следующие переменные:
double h_water = 0.1; // высота воды над недеформированной системой в [м]
double w_ref = 2; // исходная ширина при нагрузке на поверхность в [м]
iint load_case_no = 1; // номер загружения, в котором приложена нагрузка
string water_accu_comment = "water accumulation"; // строка идентификатора
double std_magnitude = 10000; // нагрузка на поверхность на высоту воды в [Н/м^3]
Что касается применения, то программа должна включать следующие элементы:
- Фильтрация выбранных стержней
- Удаление нагрузок от воды из предыдущих прогонов
- Создание новых нагрузок
- Начать расчет
- Определение прогиба
- Возврат к шагу 3 и создание новых нагрузок от деформаций
- Повторение итераций до тех пор, пока не будет достигнуто предельное значение
Кроме этих функций, требуется соединение с программой и моделью, использование различных блоков try-catch и другие стандартные элементы, которые мы не будем более подробно описывать. Эти элементы затем включены в исходный код, который можно скачать по ссылке в нашей статье.
1. Фильтрация выбранных стержней
Сначала мы получим информацию о всех выбранных объектах с помощью функции get_all_selected_objects. Полученный массив содержит элементы object_location, которыми могут быть, например, тип, номер и «материнский» номер объекта более высокого порядка. В следующем цикле извлекаются номера всех объектов типа E_OBJECT_TYPE_MEMBER (т.е. все номера стержней) и сохраняются в массиве mem_noes_sel.
// get selected objects
object_location[] obj_locs = model.get_all_selected_objects();
// extract members
int[] mem_noes_sel = new int[0];
foreach(object_location obj_loc in obj_locs)
{
if (obj_loc.type == object_types.E_OBJECT_TYPE_MEMBER)
{
Array.Resize(ref mem_noes_sel, mem_noes_sel.Length + 1);
mem_noes_sel [mem_noes_sel.Length-1] = obj_loc.no;
}
}
2. Удаление нагрузок от воды из предыдущих прогонов
С помощью номера стержня теперь можно отфильтровать соответствующие нагрузки на стержень из всех нагрузок на стержни. При этом используется цикл, наложенный на номера нагрузок на стержень. В данном цикле мы получаем данные для нагрузки на стержень, проверяем номера стержней на соответствие выбранным номерам стержней и, если найдено совпадение, соответствующая нагрузка на стержень удаляется:
// delete all water_accu loads
// get all memberload numbers
int[] mem_load_noes = model.get_all_object_numbers(object_types.E_OBJECT_TYPE_MEMBER_LOAD, load_case_no);
// loop through all member loads of the load case
foreach(int mem_load_no in mem_load_noes)
{
// get member load
member_load mem_load = model.get_member_load(mem_load_no, load_case_no);
if(mem_load.comment == water_accu_comment)
{
// loop through the members of the member load
for(int i= 0; i < mem_load.members.Length; i++)
{
// loop through the members of the member load
for (int j = 0; j < mem_noes_sel.Length; j++)
{
if(mem_load.members[i] == mem_noes_sel[j])
{
// delete member load
model.delete_object(object_types.E_OBJECT_TYPE_MEMBER_LOAD, mem_load_no, load_case_no);
}
}
}
}
}
Для того, чтобы никакие другие нагрузки на стержень не были переписаны, считывается последний использованный номер нагрузки на стержень:
// get last load number
int no_offset = model.get_nth_object_number(object_types.E_OBJECT_TYPE_MEMBER_LOAD,0, load_case_no) + 1;
Следующим шагом будет создание новых нагрузок на стержень, которое уже является частью итерационного цикла do-while. Данный цикл имеет следующую структуру:
do
{
// reset delta deformation
delta_def = 0;
// apply load
model.begin_modification("Loads");
// create member loads for each member
...
model.finish_modification();
...
// calculate load case
...
// get member end deformations
...
// check criterion
} while (delta_def > 0.0001);
Для остановки итерационного цикла выберем изменение деформации, определенное при фильтрации результатов. Если все деформации отклоняются от деформаций предыдущего прохода менее чем на 0,0001 м (т.е. 0,1 мм), то цикл останавливается.
3. Создание новых нагрузок
В качестве типа нагрузки была выбрана трапециевидная нагрузка, действующая в глобальном направлении z, которая может иметь различные значения в начале и на конце стержня. Обратите, пожалуйста, внимание также на то, что для передачи всех параметров соответствующая переменная «Задана» должна быть установлена на «true». Это необходимо для того, чтобы не передавать все параметры класса и таким образом сохранить относительно небольшой объем данных, которые должны быть переданы. Значение нагрузки's рассчитывается на основе начальной высоты «h_water» (была задана) и дополнительной узловой деформации в этом месте. Затем нужно умножить высоту, данную в [м], на «std_magnitude» в [Н/м3 ] и ширину зоны нагрузки, указанную в [м], в результате мы получим линейную нагрузку в [Н/м]:
- code.cshamp#
для (int i = 0; i < mem_noes_sel.Length; ++i)
{
Member_load mem_load = новый Member_load ();
mem_load.no = no_offset + i;
mem_load.comment =water_accu_comment;
mem_load.members = новый int [] { mem_noes_sel [i] };
mem_load.distant_a_is_specific_as_relative = true;
mem_load.distant_a_is_specific_as_relativeStecification = true;
mem_load.distant_a_relative = 0,0;
mem_load.distant_a_relativeStecification = true;
mem_load.расстояние_b_is_specific_as_relative = true;
mem_load.distant_b_is_specific_as_relativeStecification = true;
mem_load.distant_b_relative = 1,0;
mem_load.distant_b_relativeStecification = true;
mem_load.load_direction = Member_load_load_direction.LOAD_DIRECTION_GLOBAL_Z_OR_USER_DEFINED_W_TRUE;
mem_load.load_directionSspecificed = true;
mem_load.load_type = Member_load_load_type.LOAD_TYPE_FORCE;
mem_load.load_typeSspecificed = true;
mem_load.load_distribution = Member_load_load_distribution.LOAD_DISTRIBUTION_traPEZOIDAL;
mem_load.load_distributionSspecificed = true;
- mem_load.magnitude_1 = std_magnitude * ((h_water + mem_end_defs [i,0]) * w_ref);
mem_load.magnitude_1Stecification = true;
mem_load.magnitude_2 = std_magnitude * ((h_water + mem_end_defs [i,1]) * w_ref);
mem_load.magnitude_2Stecification = true;
model.set_member_load(load_case_no, mem_load);
}
- /код#
Для передачи нагрузки используется функция set_member_load. Для назначения нагрузок используется в качестве комментария строкаwater_accu_comment. В следующих итерациях нагрузки уже не удаляются, вместо этого, при указании номера нагрузки, они будут заменены при повторной передаче. Таким образом, комментарий требуется только для фильтрации и удаления нагрузок при перезапуске приложения. Кроме того, была выбрана относительная величина для задания нагрузки, которая, однако, колеблется в диапазоне 0-100%.
Следующим шагом будет инициирование самого расчета. Сначала создается поле с объектами типа calculate_specific_loading. Это поле содержит все рассчитываемые загружения/сочетания. В данном случае создается только один элемент типа загружения с указанным номером загружения load_case_no:
- code.cshamp#
calculate_specific_loading[] csl =new calculate_specific_loading[1];
csl[0] = новый calculate_specific_loading();
csl [0] .no = load_case_no;
csl[0].type =case_object_types.E_OBJECT_TYPE_LOAD_CASE;
model.calculate_specific(csl, true);
- /код#
Теперь, когда доступны результаты, необходимо отфильтровать общие деформации в начале и в конце каждого стержня. Функция get_results_for_members_global_deformations используется для получения всех общих деформаций стержней для указанного загружения и выбранных стержней. Структура результатов такая же, как в соответствующей таблице в RFEM 6. Одним из вариантов является считывание длины стержня и сравнение результата с позицией x. В другом варианте используется данное описание и тот факт, что экстремумы следуют после всех x-разрезов. Был выбран второй вариант, и при первом упоминании «Экстремумы» в описании используется предыдущий индекс для нахождения последнего х-разреза стержня. Поскольку первое местоположение стержня также влияет на первую запись, дальнейшая фильтрация здесь не требуется:
- code.cshamp#
для (int i = 0; i < mem_noes_sel.Length; ++i)
{
- Members_global_deformations_row[] mem_defs_glbl = model.get_results_for_members_global_deformations(case_object_types.E_OBJECT_TYPE_LOAD_CASE, load_case_no, mem_noes_sel [i]);
- //возьмем начальную точку
- //рассчитать дельта-деформацию
- if (Math.Abs(mem_end_defs[i, 0] - mem_defs_glbl [0].row.displacement_z) > delta_def)
- delta_def = Math.Abs(mem_end_defs[i, 0] - mem_defs_glbl [0].row.displacement_z);
- mem_end_defs [i, 0] = mem_defs_glbl [0] .row.displacement_z;
- //получить деформацию в конечной точке
- для (int j = 0; j
- {
- if (mem_defs_glbl [j] .description == "Экстремумы")
- {
- //рассчитать дельта-деформацию
- if (Math.Abs(mem_end_defs[i, 1] - mem_defs_glbl [j - 1].row.displacement_z) > delta_def)
- delta_def = Math.Abs(mem_end_defs[i, 1] - mem_defs_glbl [j - 1].row.displacement_z);
- mem_end_defs [i, 1] = mem_defs_glbl [j - 1].row.displacement_z;
- разрыв;
- }
- }
}
- /код#
Кроме определения деформаций, также рассчитывается переменная «delta_def», которая используется для критерия останова. Сначала рассчитывается разница от значения деформации предыдущей итерации (ноль в начале) и текущего значения. Из разности берется абсолютное значение, и затем находитс максимум. Как уже было показано в описании итерационного цикла, мы останавливаемся на значении меньшем, чем 0,0001 м (т.е. 0,1 мм).
В видео, прилагаемом к данной статье, можно увидеть, с одной стороны, фильтр нагрузок, а с другой, шаги итерации до упора. Наконец, найденная нагрузка будет отображена на изображении.
Интерфейс веб-сервис предлагает в RFEM 6/RSTAB 9 множество возможностей для изменения элементов, а также для считывания результатов. С его помощью можно реализовать множество различных проектов. Программа, представленная в нашей статье, включает в себя из множества различных элементов только первый шаг:
- Выбрать выбранные элементы
- Создание нагрузок
- Получить и отфильтровать результаты
- Фильтровать элементы по комментариям
- Удалить элементы
Благодаря такому разнообразию. программа также может служить образцом для других проектов.