Методы решения инженерных задач
Введение
Цель:
- Научиться оформлять работы в виде документа
- Научиться базовым понятиям: переменная, функция, массивы, установки пакетов
- Освоить пакет Plots для построения графиков
- Освоить пакет Roots для решения уравнений
- Освоить пакет NLsolve для решения систем уравнений
Текстовое оформление
В инженерных расчетах требуется не только вычисления, но и пояснения к вычисленим. Поэтому даная концепция в виде интерактивных блокнотов (notebook) внедрена во многие практические рализаци для написания кода: среду engee, пакеты Pluto и Jupiter
Примечание
название данного пакета складывается из трех языков программрования julia, python и R
Для оформления текстаиспользуется язык язык ращзметки Markdown.
Элементы базового синтаксиса:
# Заголовок первого уровня
## Заголовок второго уровня
*текст курсивом*
**жирный текст**
> Цитата
Нумерованый список:
1. Элемент нумерованного списка
2. Элемент №2 того же списка
9. Элемент №3 списка — элементы нумеруются по порядку, цифра в начале строки не имеет значения
Маркированый список:
* элемент маркированного списка
- ещё один элемент ненумерованного списка
+ буллеты элементов могут быть разными
`исходный код программы` будет написан моноширный шрифтом
[ссылка](https://www.kstu.ru)
| Таблица | заголовок |
| ----------- | ----------- |
| поле таблицы | поле таблицы |
| поле таблицы | поле таблицы |
Внутри текста можно написать формулу с использованием языка разметки . Текст формулы ограничивается с двух сторон знаком $
Некоторые примеры:
a = 10
Внутри текстовых блоков можно выводить значения переменных. Для этого ставится $(имя переменной).
Пример: значение переменной a равно $(a)
Примечание
Если в конце выражения для вычисления стоит ;то результат вычисления не будет выводиться на экран
Переменные
Переменная - именованная область памяти, хранящая какие-либо данные. В зависимости от типа переменной выделяется различное количество памяти. В основном для расчето будут использоваться следующие типы:
- целые числа Int64
- дробные числа (числа с плавающей точкой) Float64
- текстовые переменные
b = 10 #целочисленная переменная
c = 0.456 #переменная с плавающей точкой
d = "text" #текстовая переменная
Примечание
Текст после знака # является комнтарием и не исполняется как код программы
Посмотреть тип какой-либо переменной можно с использованием функции typeof()
typeof(b)
typeof(c)
typeof(d)
Функции
Часто повторяющие действия в програмировании объединяются в функции.
Функции в julia записываются через блок function - end. В скобочках записываются аргументы функции.
function myfunction(x)
return x^2
end
myfunc2(x) = x^2
Для одной и той же функции можно задать различные методы реализации в зависимости от того сколько аргументов у функции и какого типа дынные переменные.
myfunc2(x::Int64) = 1/x
Теперь при вызове функции myfunc() результат будет определяться типом аргумента. Если аргумент будет целочисленный:
myfunc2(10) = $(myfunc2(10))
если число с плавающей точкой:
myfunc2(10.0) = $(myfunc2(10.0))
Примечание
Старайтесь называть переменные и функции так, чтобы было понятно что они хранят или что делают.
Массивы
Часто в инженерных расчетах применяются массивы. Переменные которые хранятне множество знаений.
В химической технологии наиболее часто применяются одномерные массивы - векторы. Например, при проведении нескольких экспериментов измеренные величины хранятся в соотвествующих массивах.
Пример задания массива с целочисленными значениями:
arr1 = [1, 2, 3, 4] #массив с целочисленными значениями
typeof(arr1)
arr2 = [1.0, 2, 3, 4, 5, 6, 7 ,9]
typeof(arr2)
Нумерация массивов начинается с единицы. В отличие от многих других языков программирования.
arr2[1] #первый элемент массива
arr2[2:4] #массив содержащий срез массива с элементами от 2 до 4
arr2[3:end] #массив с 3 элемента и до конца массива
length(arr2) #размер массива (количество элементов)
В случае если изначально размер массива неизвестен, то можно создать пустой массив. А потом добавить лять в него новые значения с использованием функции push!
arr3 = []
push!(arr3, 1)
push!(arr3, 3)
push!(arr3, 6)
В julia принято в функциях, меняющишх значение аргументов в названии использовать восклицательный знак. В данном случае меняется значение аргумента arr3.
Однако время выполнения функции push! очень большое, поэтому ее лучше не использовать (или использовать не часто).
Поэтому можно создавать массивы с заданными размерами. Для этого можно использовать функцию zeros. Создующую массив из нулей.
zeros(Float64, 10) #массив из 10 чисел с плавающей точкой заполнгеный нулями
arr4 = zeros(Int64, 10) #массив из 10 целых чисел заполнгеный нулями
А после уже заполнить массив нужными значениями. Например:
arr4[1] = 5
arr4
Удобно задавать массивы с использованием функции collect. Например создадим массив из 10 чисел от 1 до 10 содержащий квадраты индексов:
collect(i^2 for i = 1:10)
Также можно внутри цикла можно проверять значения. Например к предыдущему примеру добавим условие, что куб от индекса должен быть меньше 100:
arr6 = collect(i^2 for i = 1:10 if i^3 < 100)
Матричные и поэлементные операторы.
В случае умножения или деления двух матриц используя знак умножения происходит матричное умножение. Однако чаще применяется поэлементные операции, когда операция провордится для элементов с одинаковыми индексами. Для поэлементных операций ставится точка перед знаком умножения (или деления).
При использовании массивов в качестве аргумента функции должна быть реализация метода этой функции для массива в качестве аргумента. Другим вариантом является применение функции для каждого элеменат массива. Для этого в конце названия функции ставится точка.
mata = [1 2 3; 2 3 4; 1 3 5]
matb = [2 3 4; 5 6 7; 2 4 56]
mata * matb #матричное умножение
mata .* matb #поэлементное умножение
exp.(mata) #поэлементное применение экспоненты
Размерности (пакет Unitful)
На практике у физиеческих переменных есть не только значение, но и размерность. Обычно расчеты ведутся в единой системе (в хим технологии принято СИ). И много ошибок в расчетах бывают связаны именно с тем, что некоторые значения не были приведены в единую систему.
Отловить такие ошибки можно с использованием пакета Unitful. Данный пакет позволяет к переменным добавить размерности.
Для примера найдем объем ящика при известных длинах сторон.
using Unitful
box_a = 10.8u"cm" #сторона ящика 10.8 сантиметров
box_b = 200.9u"mm" #сторона ящика 200.9 миллиметров
box_c = 3u"m" #сторона ящика 3 метра
box_v = box_a * box_b * box_c #находим объем бокса
box_v |> u"m^3" #объем ящика выраженная в кубических метрах
box_v |> u"l" #объем ящика выраженная в литрах
Построение графиков
Для построения графиков существует множество пакетов. Мы будем использовать пакет Plots.
Для построения графика в декартовых координатах необходимо задать два ветора с координатами по осям абсцисс и ординат.
Построим график функции и на этом же графике функцию косинуса в диапазоне от 0 до 10
using Plots
y(x) = sin(x) #задаем функцию
px = 0:0.2:10 #задаем диапазон по x от 0 до 10 с шагом 0.2
py = y.(px) #определяем значения функции для выбранного диапазона
plot(px, py, label = "y(x)") #строим график функции, подпись в легенду "y(x)"
plot!(px, cos.(px), label = "cos(x)", color = "red") #график функции косинуса
xlabel!("x") #подпись по оси x
ylabel!("y") #подпись по оси y
Восклицательный знак в названии функции пакета Plots означает, что функция будет применена для текущего графика.
Обычно экспериментальные даные представляются на графике в виде точек, а не в виде линий.
Для построения графика в виде точек используется функция scatter.
pa = [1, 2, 3, 4, 5, 6]
pb = [0.1, 0.4, 0.8, 1.8, 0.4, 0.9]
scatter(pa, pb, label = "") #строим график в виде точек, подпись в легенде убираем
Построение таблиц
Для построения таблиц с данными можно использовать пакет PrettyTables
Для примера построим таблицу со значениями из предыдущего задания.
using PrettyTables
pretty_table(HTML, hcat(pa,pb), header = ["Значения x", "Значение y"], title = "Таблица 1 со значениями") #функция hcat объединяет массивы горизонтально
Решение уравнений
Для решения уравнений применяется пакет Roots.
Решение уравнения заключается в определении значения аргумента, при котором функция становится равной нулю. Поэтому уравнения вида:
преобразуются к виду:
Для численного решения уравнений применяются разные алгоритмы, но в большинстве случаев для работы алгоритма необходимо задать начальное приближение - значение с которого алгоритм начнет поиск. Чем ближе будет значение к корню тем быстрее будет произведен поиск.
Также у функции может быть несколько корней, поэтому в зависимости от наачльного приближения могут быть найдены различные корни.
using Roots
fz(x) = x^2 - 3 * x - 5
find_zero(fz, 0.5) #определение корня для начального приближения 0.5
find_zero(fz, 10) #определение корня для начального приближения 10
find_zeros(fz, (-10,10)) #определение всех корней в диапазоне от -10 до 10
Можно использовать анонимные функции, функции не имеющие названий. Анимные функции могут быть использованы, опрделяется корни функций нескольких переменных.
find_zero(x -> x^2 - 3*x -5, 0.1) #пример применения анонимных функций
Решение систем уравнений
Для решения систем уравнений применяется пакет NLsolve.
Решим систему:
Для решения преобразуем систему, чтобы в правой части от знака равно был ноль. Неизвестные перменные предаставляют в виде массива , таким образом искомое значение x в уравнении заменяем на x[1], а y на x[2].
using NLsolve
function urav(x) #функция для определения корней (нулевых значений функции)
[x[1]^2 + x[2]^2 - 10.0,
x[2] - x[1]^2 + 3]
end
sol = nlsolve(urav, [1.0,1.0]) #поиск решения для начального приближения [1, 1]
sol.zero #корни уравнения
sol2 = nlsolve(urav, [-1.0,-1.0]) #поиск решения для начального приближения [-1, -1]
sol2.zero #корни уравнения