User Guide
units_visitor.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
9 #include "utils/string_utils.hpp"
10 
11 #include "ast/all.hpp"
12 
13 /**
14  * \file
15  * \brief AST Visitor to parse the ast::UnitDefs and ast::FactorDefs from the mod file
16  * by the Units Parser used to parse the \c nrnunits.lib file
17  */
18 
19 namespace nmodl {
20 namespace visitor {
21 
24  node.visit_children(*this);
25 }
26 
27 /**
28  * \details units::Unit definition is based only on pre-defined units, parse only the
29  * new unit and the pre-defined units. <br>
30  * Example:
31  * \code
32  * (nA) = (nanoamp) => nA nanoamp)
33  * \endcode
34  * The ast::UnitDef is converted to a string that is able to be parsed by the
35  * unit parser which was used for parsing the \c nrnunits.lib file.
36  * On \c nrnunits.lib constant "1" is defined as "fuzz", so it must be converted.
37  */
39  std::ostringstream ss;
40  /*
41  * In nrnunits.lib file "1" is defined as "fuzz", so there
42  * must be a conversion to be able to parse "1" as unit
43  */
44  if (node.get_unit2()->get_node_name() == "1") {
45  ss << node.get_unit1()->get_node_name() << '\t';
46  ss << UNIT_FUZZ;
47  } else {
48  ss << node.get_unit1()->get_node_name() << '\t' << node.get_unit2()->get_node_name();
49  }
50 
51  // Parse the generated string for the defined unit using the units::UnitParser
52  units_driver.parse_string(ss.str());
53 }
54 
55 /**
56  * \details The new unit definition is based on a factor combined with
57  * units or other defined units.
58  * In the first case the factor saved to the ast::FactorDef node and
59  * printed to \c .cpp file is the one defined on the modfile. The factor
60  * and the dimensions saved to the units::UnitTable are based on the
61  * factor and the units defined in the modfile, so this factor will be
62  * calculated based on the base units of the units::UnitTable. <br>
63  * Example:
64  * \code
65  * R = 8.314 (volt-coul/degC))
66  * \endcode
67  * In the second case, the factor and the dimensions that are inserted
68  * to the units::UnitTable are based on the ast::FactorDef::unit1, like
69  * in MOD2C.
70  * \b However, the factor that is saved in the ast::FactorDef and printed
71  * in the \c .cpp file is the factor of the ast::FactorDef::unit1 divided
72  * by the factor of ast::FactorDef::unit2. <br>
73  * Example:
74  * \code
75  * R = (mole k) (mV-coulomb/degC)
76  * \endcode
77  * `unit1` is `mole k` and unit2 is `mV-coulomb/degC` <br>
78  * To parse the units defined in modfiles there are stringstreams
79  * created that are passed to the string parser, to be parsed by the
80  * unit parser used for parsing the \c nrnunits.lib file, which takes
81  * care of all the units calculations.
82  */
84  const auto node_has_value_defined_in_modfile = node.get_value() != nullptr;
85  if (!node_has_value_defined_in_modfile) {
86  std::ostringstream ss_unit1, ss_unit2;
87  std::string unit1_name, unit2_name;
88  /*
89  * In nrnunits.lib file "1" is defined as "fuzz", so
90  * there must be a conversion to be able to parse "1" as unit
91  */
92  if (node.get_unit1()->get_node_name() == "1") {
93  unit1_name = UNIT_FUZZ;
94  } else {
95  unit1_name = node.get_unit1()->get_node_name();
96  }
97  if (node.get_unit2()->get_node_name() == "1") {
98  unit2_name = UNIT_FUZZ;
99  } else {
100  unit2_name = node.get_unit2()->get_node_name();
101  }
102  /*
103  * Create dummy unit "node.get_node_name()_unit1" and parse
104  * it to calculate its factor
105  */
106  ss_unit1 << node.get_node_name() << "_unit1\t" << unit1_name;
107  units_driver.parse_string(ss_unit1.str());
108  /*
109  * Create dummy unit "node.get_node_name()_unit2" and parse
110  * it to calculate its factor
111  */
112  ss_unit2 << node.get_node_name() << "_unit2\t" << unit2_name;
113  units_driver.parse_string(ss_unit2.str());
114 
115  /**
116  * \note If the ast::FactorDef was made by using two units (second case),
117  * the factors of both of them must be calculated based on the
118  * units::UnitTable and then they must be divided to produce the unit's
119  * factor that will be printed to the \c .cpp file. <br>
120  * Example:
121  * \code
122  * FARADAY = (faraday) (10000 coulomb)
123  * \endcode
124  * In the \c .cpp file the printed factor will be `9.64853090` but in the
125  * units::UnitTable the factor of `FARADAY` will be `96485.30900000`
126  */
127 
128  auto node_unit_name = node.get_node_name();
129  auto unit1_factor = units_driver.table->get_unit(node_unit_name + "_unit1")->get_factor();
130  auto unit2_factor = units_driver.table->get_unit(node_unit_name + "_unit2")->get_factor();
131  auto unit_factor = stringutils::to_string(unit1_factor / unit2_factor, "{:a}");
132  auto double_value_ptr = std::make_shared<ast::Double>(ast::Double(unit_factor));
133  node.set_value(std::move(double_value_ptr));
134  }
135 }
136 
137 } // namespace visitor
138 } // namespace nmodl
nmodl::parser::UnitDriver::table
std::shared_ptr< nmodl::units::UnitTable > table
shared pointer to the UnitTable that stores all the unit definitions
Definition: unit_driver.hpp:52
nmodl::visitor::UnitsVisitor::UNIT_FUZZ
const std::string UNIT_FUZZ
Declaration of fuzz constant unit, which is the equivilant of 1 in mod files UNITS definitions.
Definition: units_visitor.hpp:53
nmodl::ast::FactorDef::get_node_name
std::string get_node_name() const override
Return name of the node.
Definition: ast.cpp:7483
nmodl::ast::FactorDef
TODO.
Definition: factor_def.hpp:38
nmodl::ast::Double
Represents a double variable.
Definition: double.hpp:53
nmodl::visitor::UnitsVisitor::visit_program
void visit_program(ast::Program &node) override
Override visit_program function to parse the nrnunits.lib unit file before starting visiting the AST ...
Definition: units_visitor.cpp:22
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
string_utils.hpp
Implement string manipulation functions.
nmodl::visitor::UnitsVisitor::units_driver
parser::UnitDriver units_driver
Units Driver needed to parse the units file and the string produces by mod files' units.
Definition: units_visitor.hpp:46
nmodl::ast::UnitDef::get_unit1
std::shared_ptr< Unit > get_unit1() const noexcept
Getter for member variable UnitDef::unit1.
Definition: unit_def.hpp:157
nmodl::ast::UnitDef
TODO.
Definition: unit_def.hpp:38
nmodl::ast::FactorDef::get_value
std::shared_ptr< Double > get_value() const noexcept
Getter for member variable FactorDef::value.
Definition: factor_def.hpp:173
nmodl::visitor::UnitsVisitor::visit_factor_def
void visit_factor_def(ast::FactorDef &node) override
Function to visit all the ast::FactorDef nodes and parse the units defined as ast::FactorDef in the U...
Definition: units_visitor.cpp:83
nmodl::ast::Program::visit_children
void visit_children(visitor::Visitor &v) override
visit children i.e.
Definition: ast.cpp:12902
nmodl::ast::FactorDef::get_unit2
std::shared_ptr< Unit > get_unit2() const noexcept
Getter for member variable FactorDef::unit2.
Definition: factor_def.hpp:200
nmodl::visitor::UnitsVisitor::units_dir
std::string units_dir
Directory of units lib file that defines all the basic units.
Definition: units_visitor.hpp:49
nmodl::parser::UnitDriver::parse_string
bool parse_string(const std::string &input)
parser Units provided as string (used for testing)
Definition: unit_driver.cpp:40
units_visitor.hpp
Visitor for Units blocks of AST.
nmodl::visitor::UnitsVisitor::visit_unit_def
void visit_unit_def(ast::UnitDef &node) override
Function to visit all the ast::UnitDef nodes and parse the units defined as ast::UnitDef in the UNITS...
Definition: units_visitor.cpp:38
nmodl::ast::FactorDef::get_unit1
std::shared_ptr< Unit > get_unit1() const noexcept
Getter for member variable FactorDef::unit1.
Definition: factor_def.hpp:182
nmodl::ast::UnitDef::get_unit2
std::shared_ptr< Unit > get_unit2() const noexcept
Getter for member variable UnitDef::unit2.
Definition: unit_def.hpp:166
nmodl::ast::Program
Represents top level AST node for whole NMODL input.
Definition: program.hpp:39
nmodl::ast::FactorDef::set_value
void set_value(std::shared_ptr< Double > &&value)
Setter for member variable FactorDef::value (rvalue reference)
Definition: ast.cpp:7642
nmodl::parser::UnitDriver::parse_file
bool parse_file(const std::string &filename)
parse Units file
Definition: unit_driver.cpp:29
nmodl::stringutils::to_string
std::string to_string(double value, const std::string &format_spec)
Convert double value to string without trailing zeros.
Definition: string_utils.cpp:18
all.hpp
Auto generated AST classes declaration.