Для пользователя неудобно указывать каждый аспект алгоритма. Если алгоритм допускает вложенные компоненты, то конечного числа опций будет недостаточно. Поэтому очень важно, чтобы опции не обязательно «всплыли» на верхний уровень, как в случае явных аргументов или параметров шаблона. Это иногда называют "проблемой конфигурации" в разработке программного обеспечения. Я считаю, что PETSc обладает уникально мощной системой управления конфигурациями. Это похоже на шаблон Service Locator в эссе Мартина Фаулера об инверсии управления .
Система конфигурации PETSc работает через комбинацию заданной пользователем конфигурации, управляемой объектами решателя (с запросами get и set) и базой данных параметров. Любой компонент симуляции может объявить опцию конфигурации, значение по умолчанию и место для размещения результата. Вложенные объекты имеют префиксы, которые можно составлять, так что каждый объект, который нуждается в настройке, может быть адресован независимо. Сами параметры можно прочитать из командной строки, среды, файлов конфигурации или из кода. Когда опция объявлена, указывается строка справки и справочная страница, чтобы -help
опция была понятной и чтобы можно было написать правильно связанный графический интерфейс.
Пользователь вызывает SetFromOptions
метод для настройки объекта на основе параметров командной строки. Вызов этой функции не является обязательным и не может быть вызван, если пользователь (человек, пишущий код, который вызывает PETSc) раскрывает параметры через какой-то другой интерфейс. Мы настоятельно рекомендуем пользователю предоставить базу данных опций, поскольку она дает конечному пользователю (человеку, выполняющему приложение) большую мощность, но это не требуется.
Типичная конфигурация, вызываемая через
PetscObjectOptionsBegin(object); /* object has prefix and descriptive string */
PetscOptionsReal("-ts_atol", /* options database key */
"Absolute tolerance for local truncation error", /* long description */
"TSSetTolerances", /* function and man page on topic */
ts->atol, /* current/default value *?
&ts->atol, /* place to store value */
&option_set); /* TRUE if the option was set */
PetscOptionsList("-ts_type","Time stepping method","TSSetType",TSList,
defaultType,typeName,sizeof typeName,&option_set);
TSAdaptSetFromOptions(ts->adapt); /* configures adaptive controller method */
/* ... many others */
/* ... the following is only called from implicit implementations */
SNESSetFromOptions(ts->snes); /* configure nonlinear solver. */
PetscOptionsEnd();
Примечания:
PetscOptionsList()
предоставляет пользователю выбор из динамического списка. Существует архитектура плагинов, которую новые реализации могут использовать, чтобы представить себя первоклассным для вызывающих. (Эти реализации могут быть размещены в общих библиотеках и использованы как первоклассные без перекомпиляции программ.)
SNESSetFromOptions()
рекурсивно конфигурирует линейные решатели, предобусловливатели и любые другие компоненты, требующие настройки.
Во-первых, я хотел бы сделать алгоритм и программное обеспечение как можно более общим. Я научился этому трудному пути.
Допустим, вы начали с простого контрольного примера. Вы можете сделать это быстрее. Но затем, если вы сделали программное обеспечение слишком специфичным (слишком мало параметров) для этого начального случая, вы будете терять все больше и больше времени на его адаптацию каждый раз, когда добавляете новую степень свободы. Что я делаю сейчас, так это провожу больше времени вначале, делая вещи довольно общими и увеличивая разброс параметров по мере продвижения вперед.
Это включает в себя больше тестирования с самого начала, так как у вас будет больше параметров с начальной точки, но это будет означать, что вы можете позже много играть с алгоритмом по нулевой или очень низкой цене.
Пример: алгоритм включает в себя вычисление поверхностного интеграла от точечного произведения двух векторных функций. Не предполагайте с самого начала размер, геометрию и дискретность поверхности, если в будущем вы захотите изменить это. Сделайте функцию скалярного произведения, сделайте поверхность максимально возможной, вычислите интеграл хорошим формальным способом. Вы можете проверить каждую функцию, которую вы делаете отдельно.
В начале, вы можете и начать интегрировать по простым геометриям и объявить параметры в начале как константы. Со временем, если вы хотите изменить геометрию, вы можете сделать это легко. Если бы вы сделали предположения в начале, вам бы пришлось каждый раз менять весь код.
источник