Skip to content

Commit 025333f

Browse files
committed
[1.3.60] 2025-12-08
## Core - Added vector-scalar arithmetic operators for `std::vector<float>` to enable element-wise operations: addition (`vec + scalar`, `scalar + vec`), subtraction (`vec - scalar`, `scalar - vec`), multiplication (`vec * scalar`, `scalar * vec`), and division (`vec / scalar`, `scalar / vec`). - Fixed an issue with shared materials. If duplicate materials were merged, and the color/texture/etc. is changed for a subset of primitives, all primitives sharing that merged material would be affected. ## Photosynthesis - Added `setCi()` method to manually override intercellular CO2 concentration for specified primitives, bypassing the normal iterative calculation that couples photosynthesis with stomatal conductance. This feature is primarily intended for testing and validation purposes. - CRITICAL BUG: Fixed bug in `evaluateFarquharModel()` where incorrect variable name was used when calling `fzero()`. This could result in parameters reverting to the default values in certain cases. - Added check for Farquhar `Topt` parameters to catch instances where users specify them in units of Kelvin instead of Celsius. ## Plant Architecture - Substantially refactored XML reading/writing to avoid writing position and orientation vectors to XML. Instead, they are auto-computed based on bulk parameters. ## Radiation - Added zoom parameter to the radiation camera parameters structure. By default zoom is 1x, so should be backward compatible. - Added lens flare model to radiation camera. - Radiation sources are now rendered in the radiation camera images if in view of the camera.
1 parent fd8f6aa commit 025333f

44 files changed

Lines changed: 3601 additions & 1994 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

core/include/Context.h

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ namespace helios {
148148
Value of 0 means one-sided (absorb/emit from front face only). */
149149
uint twosided_flag;
150150

151+
//! Reference count - number of primitives currently using this material
152+
/** Used for efficient copy-on-write material sharing */
153+
mutable uint reference_count;
154+
151155
//! Material primitive data storage - type registry
152156
std::map<std::string, HeliosDataType> material_data_types;
153157
//! Material primitive data storage - integer data
@@ -176,11 +180,13 @@ namespace helios {
176180
std::map<std::string, std::vector<bool>> material_data_bool;
177181

178182
//! Default constructor
179-
Material() : materialID(0), label(""), color(make_RGBAcolor(0, 0, 0, 1)), texture_file(""), texture_color_overridden(false), twosided_flag(1) {}
183+
Material() : materialID(0), label(""), color(make_RGBAcolor(0, 0, 0, 1)), texture_file(""), texture_color_overridden(false), twosided_flag(1), reference_count(0) {
184+
}
180185

181186
//! Constructor with parameters
182-
Material(uint ID, const std::string &lbl, const RGBAcolor &c, const std::string &tex, bool override, uint twosided = 1)
183-
: materialID(ID), label(lbl), color(c), texture_file(tex), texture_color_overridden(override), twosided_flag(twosided) {}
187+
Material(uint ID, const std::string &lbl, const RGBAcolor &c, const std::string &tex, bool override, uint twosided = 1) :
188+
materialID(ID), label(lbl), color(c), texture_file(tex), texture_color_overridden(override), twosided_flag(twosided), reference_count(0) {
189+
}
184190

185191
//-------- Material Data Methods ---------- //
186192

@@ -549,7 +555,7 @@ namespace helios {
549555
std::vector<std::string> listMaterialData() const {
550556
std::vector<std::string> data_labels;
551557
data_labels.reserve(material_data_types.size());
552-
for (const auto &data : material_data_types) {
558+
for (const auto &data: material_data_types) {
553559
data_labels.push_back(data.first);
554560
}
555561
return data_labels;
@@ -2472,7 +2478,7 @@ namespace helios {
24722478
* be initialized via a call to initializeContext(), after which geometry and models can be added and simulated.
24732479
*/
24742480
class Context {
2475-
friend class Primitive; // Allow Primitive methods to access private material data
2481+
friend class Primitive; // Allow Primitive methods to access private material data
24762482

24772483
private:
24782484
//---------- PRIMITIVE/OBJECT HELIOS::VECTORS ----------------//
@@ -2608,7 +2614,7 @@ namespace helios {
26082614
//------------ MATERIALS ----------------//
26092615

26102616
//! Reserved label for the default material
2611-
static constexpr const char* DEFAULT_MATERIAL_LABEL = "__default__";
2617+
static constexpr const char *DEFAULT_MATERIAL_LABEL = "__default__";
26122618

26132619
//! Map containing all materials indexed by material ID
26142620
std::map<uint, Material> materials;
@@ -2632,6 +2638,12 @@ namespace helios {
26322638
//! Generate material label from properties for automatic de-duplication
26332639
std::string generateMaterialLabel(const RGBAcolor &color, const std::string &texture, bool texture_override) const;
26342640

2641+
//! Check if a material is shared by multiple primitives
2642+
bool isMaterialShared(uint materialID) const;
2643+
2644+
//! Create a copy of a material for a specific primitive (copy-on-write)
2645+
uint copyMaterialForPrimitive(uint primitiveUUID);
2646+
26352647
//----------- GLOBAL DATA -------------//
26362648

26372649
std::map<std::string, GlobalData> globaldata;
@@ -4418,9 +4430,7 @@ namespace helios {
44184430
}
44194431
// If neither has the data, throw error
44204432
else {
4421-
helios_runtime_error("ERROR (Context::getDataWithMaterialFallback): Data " + std::string(data_label) +
4422-
" does not exist for primitive " + std::to_string(UUID) +
4423-
" (neither in its material nor as primitive data).");
4433+
helios_runtime_error("ERROR (Context::getDataWithMaterialFallback): Data " + std::string(data_label) + " does not exist for primitive " + std::to_string(UUID) + " (neither in its material nor as primitive data).");
44244434
}
44254435
}
44264436

@@ -4436,7 +4446,7 @@ namespace helios {
44364446
* \param[in] materialID Unique identifier of the material
44374447
* \return Constant reference to the Material struct
44384448
*/
4439-
[[nodiscard]] const Material& getMaterial(uint materialID) const;
4449+
[[nodiscard]] const Material &getMaterial(uint materialID) const;
44404450

44414451
//! Get material ID from material label
44424452
/**

core/include/global.h

Lines changed: 118 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,8 @@ namespace helios {
10281028
* \param[in] max_iterations [optional] Maximum number of iterations to allow before exiting solver.
10291029
* \param[in] warnings [optional] Pointer to WarningAggregator for collecting convergence warnings. If nullptr, warnings are not collected.
10301030
*/
1031-
[[nodiscard]] float fzero(float (*function)(float value, std::vector<float> &variables, const void *parameters), std::vector<float> &variables, const void *parameters, float init_guess, float err_tol = 0.0001f, int max_iterations = 100, WarningAggregator* warnings = nullptr);
1031+
[[nodiscard]] float fzero(float (*function)(float value, std::vector<float> &variables, const void *parameters), std::vector<float> &variables, const void *parameters, float init_guess, float err_tol = 0.0001f, int max_iterations = 100,
1032+
WarningAggregator *warnings = nullptr);
10321033

10331034
//! Use Newton-Raphson method to find the zero of a function with convergence status
10341035
/**
@@ -1275,6 +1276,118 @@ namespace helios {
12751276
return result;
12761277
}
12771278

1279+
//! Add a scalar to each element of a vector
1280+
/**
1281+
* \param[in] vec Vector of floats
1282+
* \param[in] scalar Scalar value to add
1283+
* \return New vector with scalar added to each element
1284+
* \ingroup functions
1285+
*/
1286+
inline std::vector<float> operator+(const std::vector<float> &vec, float scalar) {
1287+
std::vector<float> result(vec.size());
1288+
for (std::size_t i = 0; i < vec.size(); ++i) {
1289+
result[i] = vec[i] + scalar;
1290+
}
1291+
return result;
1292+
}
1293+
1294+
//! Add a scalar to each element of a vector (scalar on left)
1295+
/**
1296+
* \param[in] scalar Scalar value to add
1297+
* \param[in] vec Vector of floats
1298+
* \return New vector with scalar added to each element
1299+
* \ingroup functions
1300+
*/
1301+
inline std::vector<float> operator+(float scalar, const std::vector<float> &vec) {
1302+
return vec + scalar;
1303+
}
1304+
1305+
//! Subtract a scalar from each element of a vector
1306+
/**
1307+
* \param[in] vec Vector of floats
1308+
* \param[in] scalar Scalar value to subtract
1309+
* \return New vector with scalar subtracted from each element
1310+
* \ingroup functions
1311+
*/
1312+
inline std::vector<float> operator-(const std::vector<float> &vec, float scalar) {
1313+
std::vector<float> result(vec.size());
1314+
for (std::size_t i = 0; i < vec.size(); ++i) {
1315+
result[i] = vec[i] - scalar;
1316+
}
1317+
return result;
1318+
}
1319+
1320+
//! Subtract each element of a vector from a scalar
1321+
/**
1322+
* \param[in] scalar Scalar value
1323+
* \param[in] vec Vector of floats to subtract from scalar
1324+
* \return New vector with each element being scalar minus the vector element
1325+
* \ingroup functions
1326+
*/
1327+
inline std::vector<float> operator-(float scalar, const std::vector<float> &vec) {
1328+
std::vector<float> result(vec.size());
1329+
for (std::size_t i = 0; i < vec.size(); ++i) {
1330+
result[i] = scalar - vec[i];
1331+
}
1332+
return result;
1333+
}
1334+
1335+
//! Multiply each element of a vector by a scalar
1336+
/**
1337+
* \param[in] vec Vector of floats
1338+
* \param[in] scalar Scalar value to multiply
1339+
* \return New vector with each element multiplied by scalar
1340+
* \ingroup functions
1341+
*/
1342+
inline std::vector<float> operator*(const std::vector<float> &vec, float scalar) {
1343+
std::vector<float> result(vec.size());
1344+
for (std::size_t i = 0; i < vec.size(); ++i) {
1345+
result[i] = vec[i] * scalar;
1346+
}
1347+
return result;
1348+
}
1349+
1350+
//! Multiply each element of a vector by a scalar (scalar on left)
1351+
/**
1352+
* \param[in] scalar Scalar value to multiply
1353+
* \param[in] vec Vector of floats
1354+
* \return New vector with each element multiplied by scalar
1355+
* \ingroup functions
1356+
*/
1357+
inline std::vector<float> operator*(float scalar, const std::vector<float> &vec) {
1358+
return vec * scalar;
1359+
}
1360+
1361+
//! Divide each element of a vector by a scalar
1362+
/**
1363+
* \param[in] vec Vector of floats
1364+
* \param[in] scalar Scalar value to divide by
1365+
* \return New vector with each element divided by scalar
1366+
* \ingroup functions
1367+
*/
1368+
inline std::vector<float> operator/(const std::vector<float> &vec, float scalar) {
1369+
std::vector<float> result(vec.size());
1370+
for (std::size_t i = 0; i < vec.size(); ++i) {
1371+
result[i] = vec[i] / scalar;
1372+
}
1373+
return result;
1374+
}
1375+
1376+
//! Divide a scalar by each element of a vector
1377+
/**
1378+
* \param[in] scalar Scalar value (numerator)
1379+
* \param[in] vec Vector of floats (denominators)
1380+
* \return New vector with each element being scalar divided by vector element
1381+
* \ingroup functions
1382+
*/
1383+
inline std::vector<float> operator/(float scalar, const std::vector<float> &vec) {
1384+
std::vector<float> result(vec.size());
1385+
for (std::size_t i = 0; i < vec.size(); ++i) {
1386+
result[i] = scalar / vec[i];
1387+
}
1388+
return result;
1389+
}
1390+
12781391
/**
12791392
* \class PixelUVKey
12801393
* \brief Represents a unique key for a pixel using its UV coordinates.
@@ -1452,11 +1565,11 @@ namespace helios {
14521565
[[nodiscard]] bool isEnabled() const;
14531566

14541567
private:
1455-
mutable std::mutex mutex_; //!< Thread safety for OpenMP
1568+
mutable std::mutex mutex_; //!< Thread safety for OpenMP
14561569
std::unordered_map<std::string, std::vector<std::string>> warnings_; //!< Storage: category -> messages
1457-
std::unordered_map<std::string, size_t> counts_; //!< Total count per category (may exceed stored messages)
1458-
bool enabled_ = true; //!< Whether to accumulate warnings
1459-
static constexpr size_t MAX_EXAMPLES = 100; //!< Maximum examples to store per category
1570+
std::unordered_map<std::string, size_t> counts_; //!< Total count per category (may exceed stored messages)
1571+
bool enabled_ = true; //!< Whether to accumulate warnings
1572+
static constexpr size_t MAX_EXAMPLES = 100; //!< Maximum examples to store per category
14601573
};
14611574

14621575
//! Default null SphericalCoord that applies no rotation

0 commit comments

Comments
 (0)