суббота, 17 сентября 2016 г.

Специфика "научного" программирования

Я часто общаюсь с программистами, и есть те вопросы, которые задаются мне регулярно. В этом посте я постарался ответить на эти вопросы наиболее полным образом, учитывая разницу между «научным» и «производственным» программированиями. Я искренне надеюсь, что этот текст, хотя и ориентирован на людей, умеющих программировать, будет понятен каждому заинтересовавшемуся читателю.

Наша научно-исследовательская группа разрабатывает программный код для моделирования эволюции землеподобных планет, включая, например, ледяные планеты и спутники (Европа). Типичные временные интервалы — это от сотен миллионов до нескольких миллиардов лет модельного времени. Обычно полученные данные используются для интерпретации наблюдений (зоны субдукции на Земле или новы и другие вулканические структуры на Венере, например. Наиболее общие вопросы, на которые мы хотим дать ответ или хотя бы понять, каким он может быть — это критерии обитаемости, в том числе, человеком. Эти темы так или иначе регулярно фигурируют в докладах нашей группы.
Для ответов на все эти вопросы нужна довольно общая физика, которая во многих своих аспектах, казалось бы, совсем посторонние вещи.
 

Что у нас получается и каковы ограничения


Софт, который мы разрабатываем, изначально пишется под суперкомпьютеры (MPI и все дела). Обычное время работы на суперкомпьютере — от недель до месяцев. У нашей программы потому нет и не будет графического интерфейса и многих других фишек: это очень дорого по ресурсам.
Если честно, я безумно устал от вопросов «а почему у вас так долго считается? Вы, наверное, плохо пишете?». Предложите решение быстрее — вас будут благодарить все, от метеорологов до компании airbus. Да-да, той самой, которая самолёты строит. Им бы тоже хотелось, чтобы модельки быстрее считались. Кучу денег дадут. Большую кучу. Очень большую кучу.
Естественно, в процессе написания-отладки пускаются простые модельки (в первую очередь, двухмерные и с низким разрешением — с очень крупными численными ячейками), которые отрабатывают за часы и сутки.

Лимитирующими факторами в нашем случае являются скорость передачи данных на шине RAMCPU и вычислительная мощность самого CPU (нет, с диска мы не читаем). Оптимизации идут на уровне «в каком порядке перебирать индексы измерений массивов, чтобы оно работало быстрее» (это касается организации таблиц памяти в кэшах процессора и подгрузки данных в них). Да, у нас есть тестовые порты под GPU.
Поэтому распределённые вычисления, как SETI@home, — это не наш выбор.

Что мы используем.
Не считая «простых» численных схем решения систем дифференциальных уравнений на сетке решальщиков закорючек типа multigrid, мы пользуемся сторонними библиотеками. Среди самых известных — PETSc. Выходные данные пишутся стандартной библиотекой HDF5. Для постпроцессинга HDF5 (например, сборки «мультиков») используется paraview — бесплатное opensource решение.
 

Как идёт разработка. Контроль версий


Наша исследовательская группа состоит из 20-25 человек, среди которых 2 профессора. У каждого профессора по полгруппы сотрудников. Каждая подгруппа развивает свой, полностью независимый софт. Это очень здорово, поскольку специфика софта немного разная, и это даёт превосходную возможность сравнивать результаты расчётов между собой «не отходя от кассы».
Нашей программе уже порядка 20 лет, её писало, наверное, сотня человек. Сейчас объём кода, не считая сторонних библиотек, составляет > 100 000 строк кода, > 400 000 слов, 3.6 Мб. Это примерно полторы «Войны и мира». То есть это довольно большой программный продукт, в рамках которого каждый разрабатывает свой кусок кода, ответственный за определённую физику.

Последние месяцы наш проект таки переезжает на github, что я считаю большим шагом в будущее. До этого у нас вообще не было системы контроля версий. Да, действительно, в чём-то это провал. С другой стороны, не настолько большой.
Могу сказать так. У меня большие обновления моего блока функций проходят раз в два месяца — когда я могу сказать «да, мой кусок кода перешёл на стратегически новый уровень».
Основной костяк программы написан и неизменен — на том уровне, что раз в год обновляется несколько самых-важных файлов, и раз в пару месяцев проходят изменения типа «всем поменять 2-3 строчки кода, там был баг». То есть потратить раз в полгода один день — это примерно равно по времени работе с SVN системой.
Сейчас, надеюсь, всё же мы станем более современными.
 

На чём мы пишем 

 
Очень больная тема. Если человек забивает гвоздь молотком — так и надо. Если человек носит воду в ведре — это всех устраивает. Если ты решаешь уравнения математической физики на fortran, на тебя тычут пальцами, как на динозавра, и крутят пальцем у виска.
Да, правда, мы пишем на фортране. Более того, большинство приложений под суперкомпьютеры в современном мире пишутся либо на C, либо на fortran. Да, есть умельцы, кто пишет на C#, python и java, но это довольно небольшая часть рынка научных приложений. Более того, даже C++ не столь распространён.

Почему. Попытаюсь описать кратко. Во-первых. Большинство современных библиотек, начиная от HDF5 и Petsc, и кончая MPI, по умолчанию дают интерфейс на C и fortran. Во-вторых. Fortran изначально создавался как язык высокого уровня для решения математики. Это и встроенная векторизация работы с массивами и прочим, и многие другие мелкие удобства. Читабельность кода — это очень большее преимущество по сравнению с другими плюшками, предлагаемыми языками. Третье. Почему-то все убеждены в том, что фортран остановил своё развитие в 70х. Это не так. Свежайшие стандарты фортрана — 2008 и 2015 годы. Не каждый современный язык программирования может таким «похвастаться».

Есть и более «тонкие» преимущества фортрана. Например, встроенный ILP (Instruction Level Parallism) для управления памятью. Про C говорят, что там множатся указатели, которые могут замедлять работу. Многие другие языки изначально вообще не ставят скорость работы кода критическим параметром. Честно — вот в этом я (пока) не особо специалист. Желающим рекомендую почитать более сведущих в этом людей.

Какие есть альтернативы. Возможно, python. Остальные языки не нацелены на решение математики. Я серьёзно. Если мне нужно быстро перегонять многомерные массивы с заполнением их частными производными в конечных разностях, мне глубоко побоку концепции ООП или регулярные выражения perl.

Почему бы не взять и не переписать всё на python (любой другой язык программирования по выбору слушателя)? Я прикинул, что для переписывания нашего кода на другой язык, и не быдлокодинг, а именно реструктуризацию с учётом всей особенности решений, предлагаемых этим языком — это работа коллектива программистов, именно программистов, не учёных, где-то на полгода минимум. Это, даже теоретически, в науке никто не оплатит. Более того, возможные профиты от этого тоже весьма условны.
И это точно задача не для аспирантов, у которых часики-то тикают.
 

Почему мы не программисты?


Очень часто сталкиваюсь с вопросами типа «Вот ты геохимик. Почему ты занимаешься программированием, и не будет ли эффективнее нанять вместо тебя программиста?».
Довольно интересный вопрос. Моё личное мнение состоит из трёх пунктов.
  • Само по себе программирование — это весьма малый процент затрат времени. Да, есть отладка, есть оптимизация алгоритмов, но это всё равно не более 10% затрат (см. ниже).
  • Сопровождение кода и техническая документация. При разработке надо учитывать множество мелочей. Как мы, например, оцениваем количество расплава? Это массовая доля, объёмная или молярная? В каждом уравнении она может быть своя, и это надо учитывать. Теоретически возможно написание всеобъемлющего технического описания, которое станет «интерфейсом взаимодействия» между учёным, который ставит задачу, и программистом, который её решает. Практически — это приведёт к ещё большим затратам времени, и, что важнее, потребует дополнительные кадры, например, тестеров ПО, специалистам по технической документации и прочему. 
  • Правильная физика — это гораздо важнее, чем оптимальность алгоритма. Изменение входных параметров, например, вязкости, может поменять время работы программы в разы. Да, оптимизированный, грамотно написанный код — это очень важно. Но во многих случаях оптимизация, заточка под один набор входных параметров может привести к тому, что программа будет работать медленнее, неправильно, или, в лучшем случае, просто падать при изменении входных параметров.
  • Междисциплинарное взаимодействие — это уже непросто. Я вижу, насколько разными являются подходы меня, геохимика, и моих коллег-физиков. Мой коллега-физик посмотрит на тот параметр, который для меня сам по себе не имеет никакого значения. И наоборот. Добавлять людей для дополнительного взаимодействия непросто (а программист — это ещё один высококвалифицированный специалист, который мог физику и химию последний раз видеть в школе).
Сейчас у нас в группе появился человек, который занимается непосредственно ревизией кода. Это очень, очень, невероятно круто. И это очень большая редкость в мире науки. 
 

Что делаю конкретно я.


Когда я начинал работу в этой группе, передо мной была поставлена задача в формате «вот статья о плавлении в нижней мантии Земли, надо, чтобы это работало в нашем коде». Естественно, я уже довольно давно вышел за рамки конкретной задачи, и сейчас решаю вопросы типа «у нас есть расплав и твёрдая фаза, как они будут перемещаться друг относительно друга», и уже немного перехожу к задачам «как именно плавление вещества где-то давно повлияло на последующую историю планеты».
 

Как я это делаю.


Первое ключевое отличие от работы программистом «на фирме». Я пишу диссертацию. У меня есть 4 года (у кого-то меньше, у кого-то больше) на то, чтобы от момента «я вижу этот код первый раз в жизни» довести себя до состояния «у меня есть материал на несколько статей геологической тематики». Прошу вспомнить, что три месяца может занимать один прогон набора вариантов расчёта (при разных стартовых параметрах). То есть время уже пошло. Если ты нашёл ошибку в уравнениях — перезапускай сначала. 

И, важный нюанс и отличие от "коммерческого" программирования. Взявшись за проект, я обязан его довести до ума. Если завалишь написание диссертации на PhD - твоя карьера в науке закончена. Ты подвёл коллектив.
 

Распределение моего рабочего времени (проценты, разумеется, условны)

 
  • 15% времени — чтение статей (которые совсем по теме).
  • 10% времени — собственно, программирование.
  • 25% времени — отладка-тестирование.
  • 33% времени — участие в конференциях и всякие дополнительные задачи
  • 17% времени — пассивный режим овоща. Например, перед началом работы над куском кода у меня уходит примерно 2 дня на то, чтобы его просто почитать и загрузить в свою память в моём мозге его структуру и взаимосвязи. Ещё два дня — отходняк после кодинга (который обычно идёт 1-2 недели) в полной прострации. Ну и всякие поплевушки в потолки, прокрастинации и тоска «почему я маленьким не сдох».

Как организован рабочий процесс:

 
  1. Я формулирую тот вопрос, на который хочу ответить.
  2. Я ищу материалы по теме, начиная с запроса в google типа «распределение железа расплав твёрдая фаза нижняя мантия». Читаю статьи, читаю цитируемые в них материалы. Обычно надо найти около 5 статей, которые станут основой для решения конкретного вопроса.
  3. Я думаю над тем, как данные в статье можно описать математической моделью. Что это значит. В статье будет написано «при таком-то значении такого-то параметра будет то-то». Мне нужно найти набор уравнений, который опишет это. И далеко не всегда он будет в этой статье.
  4. Я делаю численную схему решения. Часто уравнения содержат частные производные или подразумевают какие-то дополнительные вычисления. Мне нужно придумать, как, в рамках конкретного программного кода, я могу наиболее оптимальным образом заложить эти уравнения.
  5. Я пишу код.
  6. Я отлаживаю код.
  7. Я думаю над тем, как можно проверить корректность модели. Что это означает? Написать работающий без сбоев код — это 5-10% времени. Остальное время уходит на то, чтобы удостовериться, что результат работы этого кода правилен. Проблема в том, что за время симуляции проходят сотни и тысячи итераций — решения систем уравнений для каждого временного интервала. Накопленные численные ошибки и погрешности могут вылезти только через 100-1000 шагов расчёта — когда они превысят хотя бы 0.1%, чтобы стали заметны «невооружённым» глазом.
  8. Я изучаю устойчивость решения. Те параметры, которые приводятся в статьях, обычно имеют погрешность порядка 10%, не считая систематических погрешностей методик и прочих прелестей. Мне надо понять, будет ли решение универсально. Очень часто программа будет стабильно работать при одном значении начального параметра (например, температуры), но при изменении величины на 3% программа будет падать. Как раз из-за накопленных погрешностей.
  9. Из-за чего берутся погрешности. Например. Вязкость расплава составляет 1 Па*с, вязкость твёрдого вещества — 10^22 Па*с. Ни одна численная схема не подразумевает «честного» решения таких перепадов физических свойств на 22 порядка в пределах 1-2 численных ячеек. Скормить это так, чтобы результат был осмысленнен — это непростая задача.
  10. Я оцениваю, насколько данное решение имеет физический смысл. Законы Ома и прочие простые уравнения — это хорошо в лаборатории, но при переходе к более сложным физикам такого уже нет (или невыносимо сложно с точки зрения того, сколько времени это будет считаться). Вместо физических законов используются частные решения для заданных наборов параметров. Как пример — смотрите тут.
  11. Я смотрю на получившиеся картинки (значения параметров) и думаю, что ещё можно вставить в программу, чтобы стало лучше. После чего всё повторяется с пункта 1.

Что мы показываем.


Как ни странно, очень важный раздел. Программа считает тысячи промежуточных значений и величин в каждой из ячеек расчётной сетки. Даже в рамках решения отдельной конкретной задачи, которой я занимаюсь, я должен учитывать примерно 30 численных параметров, рассчитываемых на каждом шаге.
В пределах одного доклада, лекции или даже статьи невозможно показать все эти 30 величин. Более того, целевая аудитория будет разная. Если я делаю доклад по теме «неоднородности химического состава нижней мантии Земли» - это одна область интересов, если же это «температуры плавления вещества на границе ядро-мантия» - это совсем другие величины. Поэтому очень важным является (1) выбрать те параметры, которые представляют наибольший интерес для целевой аудитории и (2) показать их в понятном виде.

Подготовка одного графика, именно хорошего графика — это полдня-день работы. Начиная от подбора оптимальных шрифтов и цвета линий, кончая тем, как именно разместить подписи на рисунке, чтобы график выглядел опрятно.
То же касается и видеоматериалов.
 

Куда уходят написанные строки кода


Здесь я хочу затронуть очень сложную тему, а именно авторское право и open-source. Да, во имя сияния чистого разума, наука должна быть общедоступна, равно как и коды.
Во имя реалий всё совсем по-другому. Допустим, конкретно мой кусок кода. Я обязан опубликовать несколько оригинальных научных статей по тем геологическим прогнозам, которые из него следуют. Соответственно, я категорически против, чтобы кто-то увёл без моего ведома этот код, а потом где-то на 20ой странице статьи поставил «использован код такого-то», тем более без ссылки на публикацию. Поэтому я в принципе не могу позволить себе утечку данных до опубликования статей. И даже затем. Ты прочитал статьи и хочешь использовать мой код? Напиши мне, мы вместе подумаем, какую совместную работу мы можем опубликовать.
Почему совместную? Потому что в современной науке, а, точнее, в системе финансирования работы учёных, основными показателями являются количество статей у автора и количество их цитирований. И не ссылок «мы взяли софт того-то», а ссылок на конкретную статью, в которой я его опишу. Поэтому всё это весьма чувствительно упирается в куски хлеба на душу учёных. К сожалению, наука работает именно так.

Второй, более общей, проблемой является авторское право. Мы работаем в ETH Zurich, а деньги нам платят разные конторы: у нас есть финансирование от швейцарских, европейских и других фондов. Согласовать всё это — это тоже проблема. И точно не моя.

Из светлых вещей могу сказать — к счастью, конкретно я и ещё несколько человек в нашей подгруппе финансируются ERC (European Research Council). У них есть требование, чтобы все статьи, которые мы публикуем, были в открытом доступе, если невозможно иное (требование журнала). Это очень здорово и правильно.
 

Оценка результатов работы.


Тестирование
Начну с конкретного примера. Есть такая физическая величина, как скорость деформации (strain rate). Мы можем закрепить кусок пластилина на столе и пальцем сдвинуть его верхушку. На основании измерения мы можем рассчитать его вязкость. Но тут у нас скорости сдвига — это сантиметры в секунду. В случае природы — это сантиметры, но за годы. Будет ли вязкость та же? Как будет влиять на неё размер зёрен кристаллов породы и содержание в ней влаги? Это одна сторона проблем.
То же касается и других входных параметров. Например, температура плавления вещества на глубинах 2000-3000 км. Только в последние 10 лет начали появляться первые нормальные количественные данные. И то, погрешности типа 100-300 градусов Цельсия, что примерно 5% от величины — это хорошие, качественные данные. Но эти погрешности будут иметь очень большое влияние на результаты расчётов.

Вторая сторона. Допустим, мы моделируем Землю. При этом мы с некоторой точностью знаем строение её глубин на текущий момент времени. Соответственно, когда мы проводим моделирование, мы можем либо использовать это как начальный момент для расчёта либо как конечный. Но, что самое важное, у нас нет и начального, и конечного состояния одновременно.

Разработка критериев достоверности расчётов — это очень сложная тема.

Обычно я веду отладку так. Меняешь один параметр (набор параметров) — полный перезапуск 3-5 моделей. Меняешь другой параметр (набор параметров) — опять перезапуск. Да, очень часто понимаешь, что должно получиться. Всё равно — если поменяешь два набора разных параметров (например, влияние химического состава на плотность пород и набор коэффициентов для уравнений вязкости этих пород), накопленные изменения за сотни шагов расчёта будут такими, что разделить одно и другое будет сложно. И даже если надо внести обе правки, сделав это одновременно, ты не увидишь конкретных последствий изменения этого параметра. А это означает, что ты потеряешь чувство физики — накопленное интуитивное чувство, как что на что влияет. Потому — перезапуски и перезапуски, пусть и каждый отнимет не менее 12 часов.
Кстати, поэтому лично я стараюсь не использовать рестарты программы после N шагов или же специально подобранные входные параметры для «более быстрой» работы кода. Потому что накопленные изменения могут сыграть.

Каждую стабильную сборку кода и тестирую по-чистому. Это означает, что я удаляю все файлы компиляции кода. Я выключаю компьютер на 10 минут. После этого я пересобираю код и запускаю. И это не чёрная магия. Указатели или сами переменные могут вести на незаданные значения — то есть использование переменной без её явной инициализации. Не часто, но такое случается. «Невероятно, но факт» - очистка оперативки перезагрузкой компа таки решает подобные проблемы: по крайней мере, программа выдаст такую чушь, что сможешь понять, где и что пошло не так.

Отдельная головная боль - это корректность работы MPI версии кода, не говоря уже о GPU.
 
Отличия с точки зрения организации рабочего процесса

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

В фундаментальной науке не существует прямой монетизации результатов, и, естественно, это порождает свою специфику. Хотя научная экспертиза проектов тоже присутствует, очень часто ключевым фактором является количество научных публикаций у подающего заявление. Это касается и поддержки проекта бюджетными или благотворительными фондами, и решений о принятии в группу нового сотрудника.
В чём-то сходно с жёлтыми заголовками ссылок на новости и дроблением книг для онлайн-чтения в интернете на страницы, чтобы увеличить количество кликов.

И это очень сильное отличие от любой коммерческой конторы. Если Google хочет увеличить отдел — там создадут новую ставку. И, кстати, зарплаты там будут в разы привлекательнее. В случае научных проектов, есть довольно жёсткий регламент, сколько аспирантов, научных сотрудников и профессоров может быть в проекте и на сколько лет. Как я уже говорил, это безумно круто, что у нас есть человек, который занимается ревизией кода как программист-математик. Это великая привилегия топовой научно-исследовательской группы, которая может себе это позволить. В том числе, и по финансам.

1 комментарий: