Русский
Русский
English
Статистика
Реклама

Как мы SciArt-ом логотип конференции прокачали

В прошлом (2020) году в связи с пандемией мы проводили онлайн конференцию, и для неё сделали логотип, который был, мягко говоря, так себе. Под катом рассказ о том, как мы его прокачали для конференции этого (2021) года при помощи небольшого количества квантовой механики, метода Монте-Карло, Python и Gnuplot.

Немного предыстории

2020 год, короновирус набирает силу, вводятся ограничения, и для поддержания уровня научной дискуссии, улучшения научного сотрудничества среди русскоязычных учёных, разбросанных по всему миру, и для всего остального хорошего, мы организовывали в онлайне мини-симпозиум по вычислительной химии.

Но что это за конференция без логотипа? И собрав в кулак все художественные (от слова "худо") возможности оргкомитета конференции, в Inkscape был выстрадан логотип:

Изначальный логотип, который мы сделали при помощи Inkscape и Jmol+Gimp (для рисования фуллеренов).Изначальный логотип, который мы сделали при помощи Inkscape и Jmol+Gimp (для рисования фуллеренов).

Содержание простое: в верхней левой части у нас есть светлячок, который по совместительству d-образная орбиталь, справа летают бакминстерфуллерены, слева внизу присутствует стилизованный гауссовообразный лазерный импульс. Ну и в самом низу олицетворение всея квантовой механики: буква , привычно обозначающая волновую функцию, эта буква стилизована под факел. Несмотря на присутствие огня внутри картинки, сам логотип получился далеко не огонь. Поэтому в этом году мы предприняли попытку to Pimp My Ride Logo.

Генерируем светлячка из настоящих орбиталей

Основным элемента логотипа, который был в 2020 году, был светлячок-орбиталь. Его мы и захотели сохранить и улучшить. И что может быть более крутым, чем настоящая квантово-механическая орбиталь?

Поэтому мы решили собрать нового светлячка из настоящих орбиталей. Ограничиться решили несколькими составными частями:

  • крылья,

  • туловище,

  • голова,

  • и последним элементом было свечение туловища, огонь.

Все эти штуки мы решили представить в виде каких-то орбиталей (волновых функций), зависящих от координат (x,y,z)=r. Красивой и простейшей идеей показалось отобразить квантовость при помощи семплирования по методу Метрополиса. Волновая функция в данном случае была бы представлена как траектория точек r0, r1, r2, ..., rN, N - это длина траектории. В каждой из этих точек нам ещё известно значение волновой функции n=(rn). Сам алгоритм семплирования простейший, и пишется на Python за три минуты:

  • находясь в точке rn мы генерируем новую пробную точку rtrial, добавляя к каждой координате (xn,yn,zn) точки rn случайную добавку в диапазоне от - до +, где -- некое число, которое мы подбирали для каждого из случаев отдельно,

  • вероятность принятия новой точки равна pacc = |trial|2/|n|2, генерируя значение q из равномерного распределения от 0 до 1, мы сравниваем pacc и q: если pacc<q, то мы остаёмся в той же точке (rn+1=rn), а если нет, то переходим в новую точку (rn+1=rtrial),

  • в случае если мы остались в той же точке, чтоб не было скучно, мы добавляем к сохраняемой в траектории точке случайное смещение по каждой координате в диапазаоне от -0.1 до +0.1.

Стартовать траекторию, естественно, надо с точки с ненулевой волновой функцией. Первые же 10% траектории мы выкидывали, на поскольку симуляции быстрые, то это не особо вычислительно напряжно. Количество точек для каждого куска светлячка подбирали отдельно.

Крылья

Начать решили с крыльев. В качестве праобраза взяли d-орбиталь вида:

\psi(x,y,z) = x \cdot y \cdot \exp(-r)

r -- это модуль вектора r, нормировка для алгоритма Метрополиса не важна, поэтому здесь и далее мы её опускаем. Это выражение даёт четырёхлистник с одинаковыми лепестками, что не очень похоже на бабочку. Чтобы исправить это недоразумение, мы немного модифицировали эту функцию, добавив немного асимметрии:

\psi(x,y,z) = (0.05\cdot y^3 + 0.9 \cdot x \cdot y ) \cdot \exp(-r)

Из необычного, мы сохраняли положительные и отрицательные значения волновой функции в разные файлы, чтобы строить их отдельно.

Код на Python для генерации крыльев
import numpy as npimport random as rndDXYZ = 4.0dxyz = 0.1*DXYZdef getWFN(R, a=0.05, b=0.9, R0=1.0):    return (a*(R[1])**3 + b*R[0]*R[1])*np.exp(-np.sqrt(np.dot(R,R))/R0)Npts = 40000N2ignore = Npts/10outf = open("wfn.dat", "w")outfp = open("wfn_pos.dat", "w")outfn = open("wfn_neg.dat", "w")genNewXYZ = lambda xyz, shift: xyz + np.array([rnd.uniform(-shift,shift) for q in range(0,3)])XYZ = np.array([1.0,1.0,0.0])Psi = getWFN(XYZ, DXYZ)for i in range(0,Npts):    trialXYZ = genNewXYZ(XYZ, DXYZ)    trialPsi = getWFN(trialXYZ)    if i % N2ignore == 0:        print("step #%i" % (i))    Ptrial = rnd.random()    Ptest = trialPsi**2/Psi**2    Accepted = False    if Ptrial < Ptest:        Psi = trialPsi        XYZ = trialXYZ        Accepted = True    if i>N2ignore:        r2save = XYZ        if not Accepted:            r2save = genNewXYZ(XYZ, dxyz)        outf.write(" %15.10f %15.10f %15.10f %15.5e\n" % tuple(list(r2save)+[Psi]))        if Psi > 0.0:            outfp.write(" %15.10f %15.10f %15.10f %15.5e\n" % tuple(list(r2save)+[Psi]))        else:            outfn.write(" %15.10f %15.10f %15.10f %15.5e\n" % tuple(list(r2save)+[Psi]))

Туловище

Для построения туловища была выбрана более сложная конструкция:

\psi(x,y,z) =\begin{cases} (y^3 + 0.5\cdot y)\cdot \exp\left( -\frac{|x|}{0.2}-\frac{|y|}{0.5} -\frac{|z|}{0.2}\right) \ , \ y<0 \\ 0 , \ y\geq 0 \end{cases}Код на Python для генерации туловища
import numpy as npimport random as rndDXYZ = 0.5dxyz = 0.1*DXYZdef getWFN(R, a=1.0, b=0.5, X0=0.2, Y0=0.5, Z0=0.2):    if R[1]<0.:        return (a*(R[1])**3 + b*R[1])*np.exp(-np.abs(R[0])/X0 - np.abs(R[1])/Y0 - np.abs(R[2])/Z0)    else:         return 0.0Npts = 20000N2ignore = Npts/10outf = open("body.dat", "w")genNewXYZ = lambda xyz, shift: xyz + np.array([rnd.uniform(-shift,shift) for q in range(0,3)])XYZ = np.array([0.0,-0.2,0.0])Psi = getWFN(XYZ, DXYZ)for i in range(0,Npts):    trialXYZ = genNewXYZ(XYZ, DXYZ)    trialPsi = getWFN(trialXYZ)    if i % N2ignore == 0:        print("step #%i" % (i))    Ptrial = rnd.random()    Ptest = trialPsi**2/Psi**2    Accepted = False    if Ptrial < Ptest:        Psi = trialPsi        XYZ = trialXYZ        Accepted = True    if i>N2ignore:        r2save = XYZ        if not Accepted:            r2save = genNewXYZ(XYZ, dxyz)        outf.write(" %15.10f %15.10f %15.10f %15.5e\n" % tuple(list(r2save)+[Psi]))

Голова

Голова была представлена функцией, напоминающей s-орбиталь:

\psi(x,y,z) = \exp\left(-\frac{|x|}{0.3}-\frac{|y|}{0.5}-\frac{|z|}{0.3} \right)Код на Python для генерации головы
import numpy as npimport random as rndDXYZ = 0.9dxyz = 0.1*DXYZdef getWFN(R, a=1.0, b=0.5, X0=0.3, Y0=0.5, Z0=0.3):    return np.exp(-np.abs(R[0])/X0 - np.abs(R[1])/Y0 - np.abs(R[2])/Z0)Npts = 10000N2ignore = Npts/10outf = open("head.dat", "w")genNewXYZ = lambda xyz, shift: xyz + np.array([rnd.uniform(-shift,shift) for q in range(0,3)])XYZ = np.array([0.0,-0.2,0.0])Psi = getWFN(XYZ, DXYZ)for i in range(0,Npts):    trialXYZ = genNewXYZ(XYZ, DXYZ)    trialPsi = getWFN(trialXYZ)    if i % N2ignore == 0:        print("step #%i" % (i))    Ptrial = rnd.random()    Ptest = trialPsi**2/Psi**2    Accepted = False    if Ptrial < Ptest:        Psi = trialPsi        XYZ = trialXYZ        Accepted = True    if i>N2ignore:        r2save = XYZ        if not Accepted:            r2save = genNewXYZ(XYZ, dxyz)        outf.write(" %15.10f %15.10f %15.10f %15.5e\n" % tuple(list(r2save)+[Psi]))

Огонь вокруг туловища

Огонь был сгенерирован функцией того же вида, что и туловище, но со слегка подкрученными параметрами:

\psi(x,y,z) =\begin{cases} (y^3 + 0.5\cdot y)\cdot \exp\left( -\frac{|x|}{0.4}-\frac{|y|}{0.68} -\frac{|z|}{0.3}\right) \ , \ y<0 \\ 0 , \ y\geq 0 \end{cases}Код на Python для генерации огня вокруг туловища
import numpy as npimport random as rndDXYZ = 0.9dxyz = 0.1*DXYZdef getWFN(R, a=1.0, b=0.5, X0=0.4, Y0=0.68, Z0=0.3):    if R[1]<0.:        return (a*(R[1])**3 + b*R[1])*np.exp(-np.abs(R[0])/X0 - np.abs(R[1])/Y0 - np.abs(R[2])/Z0)    else:         return 0.0Npts = 1000N2ignore = Npts/10outf = open("body_fire.dat", "w")genNewXYZ = lambda xyz, shift: xyz + np.array([rnd.uniform(-shift,shift) for q in range(0,3)])XYZ = np.array([0.0,-0.2,0.0])Psi = getWFN(XYZ, DXYZ)for i in range(0,Npts):    trialXYZ = genNewXYZ(XYZ, DXYZ)    trialPsi = getWFN(trialXYZ)    if i % N2ignore == 0:        print("step #%i" % (i))    Ptrial = rnd.random()    Ptest = trialPsi**2/Psi**2    Accepted = False    if Ptrial < Ptest:        Psi = trialPsi        XYZ = trialXYZ        Accepted = True    if i>N2ignore:        r2save = XYZ        if not Accepted:            r2save = genNewXYZ(XYZ, dxyz)        outf.write(" %15.10f %15.10f %15.10f %15.5e\n" % tuple(list(r2save)+[Psi]))

Рисуем светлячка

Питоновские скрипты сгенерировали нам метрополисовские траектории вида (xn, yn, zn, n) для n=0,1,2,..., и их надо было превратить в картинку. Для этого мы использовали Gnuplot в режиме multiplot. В качестве вида взяли вид карты. Основной задачей оказался подобор палитр для раскрашивания бабочки, их мы выбирали из представленных в этом репозитории на Гитхабе: https://github.com/Gnuplotting/gnuplot-palettes.

Для тела очень быстро подобралась палитра inferno, для огонька -- ylrd, а вот с крылями пришлось возиться больше. Из более-менее применимых было три варианта: plasma, parula, и итоговый вариант -- prgn.

Plasma -- классная тема, но фиолетовый на краях очень сильно сливался с тёмно-синим фоном, а огонёк туловища был слабо заметен в паре с жёлтым крылом. Parula была хороша всем, кроме того, что вызывала у некоторых членов оргкомитета ассоциации с цветами ...шведского флага, поэтому, чтобы лишний раз не провоцировать политических флеймов вокруг научного мероприятия, от этой схемы мы отказались. В итоге удалось подобрать схему prgn, которая хороша всем: не сливается с фоном, огонёк хорошо заметен, да и сама схема приятна глазу. Ну а дальше манипуляциями в Inkscape получился окончательный вариант логотипа.

Скрипт для построения светлячка в Gnuplot
#set terminal pngcairo size 1500,1500   transparent set terminal pngcairo size 1500,1500  background rgb '#080045' set output "ff_v2.png" set multiplotset view map set size ratio 1unset colorboxunset borderunset keyunset xticsunset yticsXMax = 7.set xrange [-XMax:XMax]set yrange [-XMax:XMax]set pm3d depthorder hidden3d 1set hidden3dset style fill  transparent solid 0.35 noborderset style circle radius 0.02load 'prgn.pal'#load 'plasma.pal'#load 'parula.pal'splot 'wfn_pos.dat' u 2:1:3:4 w p pt 7 ps 2 lc palettesplot 'wfn_neg.dat' u 2:1:3:4 w p pt 7 ps 2 lc palette      load 'inferno.pal'splot 'body.dat' u 1:2:3:4 w l lc palette      splot 'head.dat' u 1:2:3:4 w l lc paletteload 'ylrd.pal'splot 'body_fire.dat' u 1:2:3:(-$4)  w l lw 3 lc palette

Заключение

Рисование картинок из квантовой механики -- забавная штука (см. например ещё этот пост): не очень простая, гемморойная, но результат обычно стоит затраченных усилий. :)

Источник: habr.com
К списку статей
Опубликовано: 24.03.2021 16:21:32
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Python

Физика

Diy или сделай сам

Химия

Квантовые технологии

Sciart

Квантовая физика

Монте-карло

Gnuplot

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru