А я еще подумал, по-моему, вообще не очень важно, к какой температуре приводить. Соотношение между абсолютной и относительной влажностью при фиксированной температуре однозначное и монотонное, поэтому условие «абсолютная влажность на улице ниже абсолютной влажности внутри» эквивалентно условию «относительная влажность на улице, приведенная к температуре T, ниже относительной влажности внутри, приведенной к температуре T», для любого T.
То есть если бы реализовывать логику «крутить всегда, когда снаружи суше», то вообще все равно, использовать абсолютные влажности или приведенные относительные. А вот если еще и устанавливать пороговое значение разности влажностей, то для приведенных относительных это может быть проще. В конце концов, нужды очень точно выбирать порог разности влажностей нет, просто хочется придумать метод более подходящий, чем «пороговая разность абсолютных влажностей».
Правда, надо суметь сделать так, чтобы приведенная относительная влажность не оказалась бы слишком низкой (проценты-доли процента?) или слишком высокой (под 100% и выше, тогда вообще непонятно, как формулы себя поведут), но если в качестве температуры выбирать что-нибудь разумное (уличную или внутреннюю или среднюю и т.п., а не приводить в лютый мороз влажность к 30 градусам тепла), то, думаю, проблем не должно возникнуть, или как минимум они будут меньше, чем при описанном в посте методе.
При перепаде температур от +30 до -30 значение абсолютной влажности изменяется в тысячу раз.
А пересчитывать обратно в относительную влажность не пробовали? Казалось бы, мы знаем относительную и абсолютную влажность внутри и относительную и абсолютную влажность снаружи. Мы не можем сравнить относительные влажности, т.к. они относятся к разным температурам. Мы не можем сравнить абсолютные влажности, т.к. они могут быть очень разными по порядку величины. Но давайте сравнивать относительные влажности, приведенные к одной температуре?
Берем абсолютную влажность наружного воздуха. Предполагаем, что этот воздух охлаждается до внутренней температуры, сохраняя свою абсолютную влажность. Тогда мы можем посчитать, какая у него будет относительная влажность, когда он так охладится. Сравним эту относительную влажность с относительной влажностью внутреннего воздуха, и в зависимости от разности примем решение.
В кафе действует ещё красивый метод: могут выдать пречек, но не принести настоящий (с фискальной отметкой — должны быть буквы ФП внизу).
Вот здесь тоже хочется уточнения про ЕНВД. Если ЕНВД, то никаких букв ФП на чеке быть не должно, верно? (Да и чека вообще может не быть?) И есть ли тогда какой-нибудь способ уточнить, работает ли кафе по ЕНВД или нет?
Вот что меня в этой ситуации сильно удивляет, это как многие переживают по поводу того, что гуглоавтомобиль сможет неправильно опознать грузовик. Ясно ведь, что вероятность того, что изображение испортится именно таким специальным образом, крайне мала. И так же ясно, что нет смысла от гугломобилей требовать 100% безопасности, надо лишь требовать безопасности более высокой, чем у обычных машин, управляемых людьми. Условно говоря, если вероятность попасть обычной машине в аварию, допустим, 10^-5 на километр пробега (цифра с потолка, но думаю, что плюс-минус пара порядков верна), а для гугломобиля эта цифра 10^-6, то гугломобиль намного лучше обычных автомобилей. И понятно, что вероятность такого синхронного изменения пикселей, как описано в статье, намного меньше этих 10^-6, поэтому эта ошибка фактически на безопасность не влияет.
Да, со всем согласен (кроме разве что programmer's guide — вроде основы всё те же, а кроме основ в guide мало что есть). Про параллелизацию хотел, но забыл.
Ну я вроде пока еще не приводил ссылок на метод конечных объемов в общем случае. Но в английской википедии он вроде разумно описан. Основной смысл — что уравнения в частных производных мы заменим на интегральные уравнения, проинтегрировав по объему ячейки. В результате производные по времени превратятся в производные от суммарной величины во всей ячейке; а пространственные производные, по крайней мере простые — типа градиента и дивергенции — превратятся в интегралы по поверхности. Соответственно, для вычисления градиента от поля, заданного на поверхностях ячеек, мы просто суммируем его значения, помноженные на векторы нормали и на площадь (формула 2.25 по ссылке на Programmer's manual), а для поля, заданного в объеме — сначала так или иначе интерполируем его на поверхности и потом суммируем.
Насколько я понимаю, это не совсем то. CRTP — это про возможность из базового класса получать доступ к функциям и полям наследника. В частности, там базовый класс должен знать, что от него будут наследоваться, — а здесь несколько другое.
1. Есть генератор сетки по описанию (типа «такой-то параллелепипед разбить на NxMxK ячеек, причем по третьей координате каждую следующую ячейку делать на L% уже», или аналогично можно не только с параллелепипедами, но и с шестигранниками с изогнутыми ребрами и т.п.) — одномерные, двумерные, трехмерные, качество обсуждать бессмысленнно. Есть некий генератор snappyHexMesh, я с ним не работал. Я так понимаю, он тоже должен генерить одно-, двух- и трехмерные сетки.
2. Не очень понятен вопрос. Расчеты идут методом конечных объемов, там про базис говорить бессмысленно (в отличие от конечных элементов). (В тексте в одном месте у меня таки проскочили конечные элементы; сейчас поправлю.) Правда, есть еще разные схемы для градиента, не совсем следующие методу конечных объемов (например, вычисление градиента методом наименьших квадратов, минимизируя отклонение «значение в данной точке, линейно экстраполированное по градиенту на соседние точки» от реальных значений в соседних точках), можете подробнее посмотреть на странице 36 в Programmer's manual.
3. Каких-либо методов общего назначения для нелинейных систем в OpenFOAM нет; все функции fvm:: позволяют создать только линейные члены, и, соответственно, функции solve() решают только линейные системы. Для конкретных нелинейных систем (в первую очередь для уравнений гидродинамики) есть ряд специализированных методов типа SIMPLE, PIMPLE, PISO, решающих уравнения итеративно путем многократного решения специальным образом сконструированных линейных уравнений — эти методы реализованы в отдельных стандартных солверах.
Казалось бы, все просто, но для этого надо уметь вычислять производную левой части уравнения. Эта левая часть у меня была довольно сложная — даже просто вычисление ее значений в программе было разбросано по нескольким функциям,
— нет класса Derivable
— нет рефакторинга, когда нужно добавить поддержку, например, второй производной.
Класс Derivable или его аналог есть, только не в вашем коде, а в том, который вы взяли. Вопрос о том, что лучше — готовые решения или самописные — в каждом случае должен решаться отдельно, но (и я вам это уже отвечал в другом комменте) и по автоматическому дифференцированию есть готовые библиотеки.
И вторая производная там же есть, и все, что надо. И, как верно Mrrl написал ниже, добавить код для вычисления второй производной элементарных функций достаточно просто. Ну или воспользоваться Derivable<Derivable<double> >, что еще проще.
— композиция функций и другие естественные конструкции
С этим разобрались.
— в итоге дает меньше шансов выстрелить себе в ногу
По-моему, максимальное упрощение пользовательского кода, т.е. того, где вы вычисляете функцию, более существенно уменьшает шансы выстрелить в ногу. В вашем варианте выстрел в ногу получается элементарно, если из двух копий формулы забыть исправить одну.
А если и функция задается в силу своего физического смысла не одной строкой, а пятью (см. пример в комментах выше), то прострелить ногу из-за необходимости писать больше кода там еще проще.
— и вообще, всякое явное представление концепции лучше, чем более низкоуровневое описание ее следствий (формула целиком против алгоритма, который ее вычисляет)
— работает, наверное, со сравнимой скоростью внутри горячего цикла, медленнее на старте (накладные расходы на символьные манипуляции)
— это зависит от библиотеки, которую вы возьмете. Со сравнимой скоростью должен работать JIT подход, чисто символьное вычисление, конечно, будет медленным.
не в те ворота
— работает одинаково хорошо для простых примеров, так и для сложных. Вторая производная, производная спец. функций, попытка аналитически решить уравнение до решения численно — это возможно, и инкапсулировано в специализированном пакете, который для того и писан. Посмотрите на возможности GiNaC — вы вряд ли хотите переписывать его функционал.
Все, кроме аналитического решения, вполне реализуется и доступно в имеющихся библиотеках автоматического дифференцирования. Аналитическое решение — конечно нет, но это уже совсем другая задача.
— композиция функций и другие естественные конструкции инкапсулированы в строке, которую обрабатывает внешняя специализированная библиотека. Оно не размазано по коду в форме
трех последовательных присваиваний, за порядком которых приходится следить и сверяться с формулой на бумаге. Цитируемый код заменяется одной строкой в духе
interpreter.evaluate("cos(x^2)", "x = 1");
Вы до сих пор не согласны, что следующий код тоже работает:
Нет, я лишь предлагаю построить аналог вашего класса, который производную той же одной итерации посчитает однажды, но символьно.
Мне кажется, мой код по сути именно так и сработает. Компилятор c++, компилируя строку
x = (ad + x * x)/2/x;
именно что символьно (!) построит код вычисления производной, по результаты построит быстрый исполняемый код, и получит два параллельных численных процесса, сходящиеся к своему ответу. И в том, что компилятор произведет символьные вычисления гарантированно правильно, я не сомневаюсь.
Я еще подумал, в этом коде будут довольно сильные погрешности; например, для a=1 код вернет производную 0, а не 1/2, как должно быть. (Из-за того, что и последовательность значений сходится к нужному значению, и последовательность производных тоже, но последняя на пару итераций медленнее.)
Правда, это решается добавлением нескольких дополнительных итераций, и столь же правда, что другие методы подсчета производной, думаю, будут давать схожие проблемы по тем же в точности причинам.
Поэтому, видимо, этот код стоит считать лежащим на грани применимости автоматического дифференцирования.
А про исходники линукс — по-моему, это слишком сложно для начинающих — да может, и не только для начинающих.
То есть если бы реализовывать логику «крутить всегда, когда снаружи суше», то вообще все равно, использовать абсолютные влажности или приведенные относительные. А вот если еще и устанавливать пороговое значение разности влажностей, то для приведенных относительных это может быть проще. В конце концов, нужды очень точно выбирать порог разности влажностей нет, просто хочется придумать метод более подходящий, чем «пороговая разность абсолютных влажностей».
Правда, надо суметь сделать так, чтобы приведенная относительная влажность не оказалась бы слишком низкой (проценты-доли процента?) или слишком высокой (под 100% и выше, тогда вообще непонятно, как формулы себя поведут), но если в качестве температуры выбирать что-нибудь разумное (уличную или внутреннюю или среднюю и т.п., а не приводить в лютый мороз влажность к 30 градусам тепла), то, думаю, проблем не должно возникнуть, или как минимум они будут меньше, чем при описанном в посте методе.
А пересчитывать обратно в относительную влажность не пробовали? Казалось бы, мы знаем относительную и абсолютную влажность внутри и относительную и абсолютную влажность снаружи. Мы не можем сравнить относительные влажности, т.к. они относятся к разным температурам. Мы не можем сравнить абсолютные влажности, т.к. они могут быть очень разными по порядку величины. Но давайте сравнивать относительные влажности, приведенные к одной температуре?
Берем абсолютную влажность наружного воздуха. Предполагаем, что этот воздух охлаждается до внутренней температуры, сохраняя свою абсолютную влажность. Тогда мы можем посчитать, какая у него будет относительная влажность, когда он так охладится. Сравним эту относительную влажность с относительной влажностью внутреннего воздуха, и в зависимости от разности примем решение.
Примерно так:
Вот здесь тоже хочется уточнения про ЕНВД. Если ЕНВД, то никаких букв ФП на чеке быть не должно, верно? (Да и чека вообще может не быть?) И есть ли тогда какой-нибудь способ уточнить, работает ли кафе по ЕНВД или нет?
stackoverflow.com/a/21671069
2. Не очень понятен вопрос. Расчеты идут методом конечных объемов, там про базис говорить бессмысленно (в отличие от конечных элементов). (В тексте в одном месте у меня таки проскочили конечные элементы; сейчас поправлю.) Правда, есть еще разные схемы для градиента, не совсем следующие методу конечных объемов (например, вычисление градиента методом наименьших квадратов, минимизируя отклонение «значение в данной точке, линейно экстраполированное по градиенту на соседние точки» от реальных значений в соседних точках), можете подробнее посмотреть на странице 36 в Programmer's manual.
3. Каких-либо методов общего назначения для нелинейных систем в OpenFOAM нет; все функции fvm:: позволяют создать только линейные члены, и, соответственно, функции solve() решают только линейные системы. Для конкретных нелинейных систем (в первую очередь для уравнений гидродинамики) есть ряд специализированных методов типа SIMPLE, PIMPLE, PISO, решающих уравнения итеративно путем многократного решения специальным образом сконструированных линейных уравнений — эти методы реализованы в отдельных стандартных солверах.
Я даже выше привел условный, но хорошо передающий задачу, пример: habrahabr.ru/company/intel/blog/170729/#comment_5934705.
И да, в вашем исходном комментарии вы заявляли, что для
sin(x^2)
не сработает, а также утверждали, что все это не нужно вообще.За ссылки на JIT-компиляторы и символьные пакеты для C++ спасибо, но он не отменяют осмысленности и применимости описанного мною подхода.
В исходном посте:
В этом случае (вот условный пример: habrahabr.ru/company/intel/blog/170729/#comment_5934705 ) тоже будет достаточно одной строчки? Или надо будет каждую из функций переписывать, еще и дублируя запись каждой функции?
Класс
Derivable
или его аналог есть, только не в вашем коде, а в том, который вы взяли. Вопрос о том, что лучше — готовые решения или самописные — в каждом случае должен решаться отдельно, но (и я вам это уже отвечал в другом комменте) и по автоматическому дифференцированию есть готовые библиотеки.И вторая производная там же есть, и все, что надо. И, как верно Mrrl написал ниже, добавить код для вычисления второй производной элементарных функций достаточно просто. Ну или воспользоваться
Derivable<Derivable<double> >
, что еще проще.С этим разобрались.
По-моему, максимальное упрощение пользовательского кода, т.е. того, где вы вычисляете функцию, более существенно уменьшает шансы выстрелить в ногу. В вашем варианте выстрел в ногу получается элементарно, если из двух копий формулы забыть исправить одну.
А если и функция задается в силу своего физического смысла не одной строкой, а пятью (см. пример в комментах выше), то прострелить ногу из-за необходимости писать больше кода там еще проще.
С этой точки зрения не вижу разницы между
и
не в те ворота
Все, кроме аналитического решения, вполне реализуется и доступно в имеющихся библиотеках автоматического дифференцирования. Аналитическое решение — конечно нет, но это уже совсем другая задача.
Вы до сих пор не согласны, что следующий код тоже работает:
?
Мне кажется, мой код по сути именно так и сработает. Компилятор c++, компилируя строку
именно что символьно (!) построит код вычисления производной, по результаты построит быстрый исполняемый код, и получит два параллельных численных процесса, сходящиеся к своему ответу. И в том, что компилятор произведет символьные вычисления гарантированно правильно, я не сомневаюсь.
Правда, это решается добавлением нескольких дополнительных итераций, и столь же правда, что другие методы подсчета производной, думаю, будут давать схожие проблемы по тем же в точности причинам.
Поэтому, видимо, этот код стоит считать лежащим на грани применимости автоматического дифференцирования.