| 1 |
greg |
2.10 |
/* RCSid $Id: RcontribSimulManager.h,v 2.9 2024/12/24 20:57:13 greg Exp $ */ |
| 2 |
greg |
2.1 |
/* |
| 3 |
|
|
* RcontribSimulManager.h |
| 4 |
|
|
* |
| 5 |
|
|
* Rcontrib simulation manager class declaration |
| 6 |
|
|
* |
| 7 |
|
|
* Created by Greg Ward on 10/11/2024. |
| 8 |
|
|
*/ |
| 9 |
|
|
|
| 10 |
|
|
#ifndef RcontribSimulManager_h |
| 11 |
|
|
#define RcontribSimulManager_h |
| 12 |
|
|
|
| 13 |
|
|
#include "RtraceSimulManager.h" |
| 14 |
|
|
#include "RdataShare.h" |
| 15 |
|
|
#include "lookup.h" |
| 16 |
|
|
#include "rtprocess.h" |
| 17 |
|
|
|
| 18 |
|
|
/* |
| 19 |
|
|
* As with other single-object classes, many global variable affect |
| 20 |
|
|
* behavior. Besides rendering parameters, there are spectral parameters |
| 21 |
|
|
* and output dimensions taken from the environment. |
| 22 |
|
|
* |
| 23 |
|
|
* NOTE: "record" and "row" are used interchangeably throughout. |
| 24 |
|
|
*/ |
| 25 |
|
|
|
| 26 |
|
|
extern char RCCONTEXT[]; // global rcontrib context |
| 27 |
|
|
|
| 28 |
greg |
2.2 |
class RcontribSimulManager; // need forward decl |
| 29 |
greg |
2.1 |
|
| 30 |
|
|
/// Shared data object for record output (includes header; may be write-only) |
| 31 |
|
|
class RcontribOutput { |
| 32 |
|
|
RcontribOutput * next; // next in sorted list |
| 33 |
|
|
char * ofname; // output file name |
| 34 |
|
|
uint32 rowCountPos; // row count position in header |
| 35 |
|
|
void * rowp; // current row memory |
| 36 |
|
|
bool NewHeader(const RcontribSimulManager *rcp); |
| 37 |
|
|
int CheckHeader(const RcontribSimulManager *rcp); |
| 38 |
|
|
public: |
| 39 |
|
|
RdataShare * rData; // data sharing object |
| 40 |
|
|
size_t rowBytes; // byte count per row |
| 41 |
|
|
const char * omod; // single modifier (or NULL) |
| 42 |
|
|
int32 obin; // single output bin (or -1) |
| 43 |
|
|
uint32 begData; // start of data (type-aligned) |
| 44 |
|
|
int32 curRow; // current output row |
| 45 |
|
|
uint32 nRows; // total number of rows |
| 46 |
|
|
RcontribOutput(const char *fnm = NULL) { |
| 47 |
|
|
next = NULL; |
| 48 |
|
|
omod = NULL; |
| 49 |
|
|
obin = -1; |
| 50 |
|
|
rData = NULL; |
| 51 |
|
|
ofname = savqstr(fnm); |
| 52 |
|
|
rowBytes = 0; |
| 53 |
|
|
nRows = 0; |
| 54 |
|
|
rowp = NULL; curRow = -1; |
| 55 |
|
|
} |
| 56 |
|
|
~RcontribOutput() { |
| 57 |
|
|
DoneRow(); |
| 58 |
|
|
delete rData; |
| 59 |
|
|
delete next; |
| 60 |
|
|
freeqstr(ofname); |
| 61 |
|
|
} |
| 62 |
|
|
/// Return output channel name |
| 63 |
|
|
const char * GetName() const { |
| 64 |
|
|
if (rData) return rData->GetName(); |
| 65 |
|
|
return ofname; |
| 66 |
|
|
} |
| 67 |
|
|
/// Update output row count |
| 68 |
|
|
bool SetRowsDone(int r) { |
| 69 |
|
|
if (!rData | (0 >= r) | (r > nRows)) return false; |
| 70 |
|
|
char * rbuf = (char *)rData->GetMemory(rowCountPos, 17, 0); |
| 71 |
|
|
sprintf(rbuf, "%-16d", r); |
| 72 |
|
|
rbuf[16] = '\n'; // replaces nul byte |
| 73 |
|
|
return rData->ReleaseMemory(rbuf, RDSwrite); |
| 74 |
|
|
} |
| 75 |
|
|
/// Get buffer for indicated row (contents may be random) |
| 76 |
|
|
void * GetRow(int r) { |
| 77 |
|
|
if (!rData | (r < 0)) return NULL; |
| 78 |
|
|
if (r != curRow) { |
| 79 |
|
|
DoneRow(); |
| 80 |
|
|
if (r < nRows) |
| 81 |
|
|
rowp = rData->GetMemory(begData + r*rowBytes, |
| 82 |
|
|
rowBytes, 0); |
| 83 |
|
|
if (rowp) curRow = r; |
| 84 |
|
|
} |
| 85 |
|
|
return rowp; |
| 86 |
|
|
} |
| 87 |
|
|
/// Current row with byte offset |
| 88 |
|
|
void * InsertionP(int coffset) const { |
| 89 |
|
|
if (!rowp | (coffset < 0) | (coffset >= rowBytes)) |
| 90 |
|
|
return NULL; |
| 91 |
|
|
return (char *)rowp + coffset; |
| 92 |
|
|
} |
| 93 |
|
|
/// Release current row, writing contents |
| 94 |
|
|
void DoneRow() { |
| 95 |
|
|
if (rowp) rData->ReleaseMemory(rowp, RDSwrite); |
| 96 |
|
|
rowp = NULL; curRow = -1; |
| 97 |
|
|
} |
| 98 |
|
|
/// Get next in list |
| 99 |
|
|
const RcontribOutput * Next() const { |
| 100 |
|
|
return next; |
| 101 |
|
|
} |
| 102 |
|
|
RcontribOutput * Next() { |
| 103 |
|
|
return next; |
| 104 |
|
|
} |
| 105 |
|
|
/// RcontribSimulManager gets full access |
| 106 |
|
|
friend class RcontribSimulManager; |
| 107 |
|
|
}; |
| 108 |
|
|
|
| 109 |
|
|
typedef double DCOLORV; // color accumulator type |
| 110 |
|
|
|
| 111 |
|
|
/// Modifier channel for recording contributions (no constructor/destructor) |
| 112 |
|
|
struct RcontribMod; |
| 113 |
|
|
|
| 114 |
|
|
/// Allocate rcontrib accumulator |
| 115 |
|
|
extern RcontribMod * NewRcMod(const char *prms = NULL, const char *binexpr = NULL, int ncbins = 1); |
| 116 |
|
|
/// Free an RcontribMod |
| 117 |
|
|
extern lut_free_t FreeRcMod; |
| 118 |
|
|
|
| 119 |
|
|
/* |
| 120 |
|
|
* General RcontribSimulManager class operation: |
| 121 |
|
|
* |
| 122 |
|
|
* 1) Call LoadOctree(), then alter the header as desired |
| 123 |
|
|
* 2) Set number of spectral samples (NCSAMP) and call SetDataFormat() |
| 124 |
greg |
2.6 |
* 3) Set xres and yres to desired dimensions (xres>0 for picture output) |
| 125 |
|
|
* 4) Call AddModifier() and AddModFile() to indicate tracked modifiers |
| 126 |
|
|
* 5) Set outOp and cdsF according to desired output/recovery |
| 127 |
|
|
* 6) Set desired computation flags via SetFlag() |
| 128 |
|
|
* 7) Call PrepOutput() to open output channels |
| 129 |
|
|
* 8) Call SetThreadCount() to fork children if desired |
| 130 |
|
|
* 9) Set accum to the number of ray samples per record |
| 131 |
|
|
* 10) Call ComputeRecord() with accum ray samples |
| 132 |
|
|
* 11) Continue until GetRowMax() records have been sent |
| 133 |
|
|
* 12) Call Cleanup() |
| 134 |
greg |
2.1 |
* |
| 135 |
|
|
* The order of some of these calls may be changed. Technically, the octree |
| 136 |
|
|
* may be loaded anytime before PrepOutput() is called. Also, SetThreadCount() |
| 137 |
greg |
2.6 |
* may be called anytime *after* PrepOutput(), and may be interleaved with |
| 138 |
greg |
2.1 |
* calls to ComputeRecord(). The accum setting may be changed at any time. |
| 139 |
|
|
* Finally, it is possible to restart the output using ResetRow(), and |
| 140 |
|
|
* a zero argument will rewind to the beginning, whence all records |
| 141 |
|
|
* may be recalculated. The previous output rows are not zeroed or deleted, |
| 142 |
|
|
* but are overwritten as the calculation proceeds from the new starting point. |
| 143 |
|
|
* However, the output file(s) will indicate in the NROWS= line in the header |
| 144 |
greg |
2.7 |
* that only the newly calculated rows are present. If you wish to start over |
| 145 |
|
|
* with a different set of modifiers or outputs, call ClearModifiers() instead, |
| 146 |
|
|
* which keeps the current octree in memory. This call also returns to single |
| 147 |
|
|
* process mode if any children were running. |
| 148 |
greg |
2.1 |
* |
| 149 |
|
|
* It is not possible to write to standard output, but the output |
| 150 |
|
|
* model is quite flexible thanks to the RdataShare polymorphic class. |
| 151 |
|
|
* The current default output class creates a shared, memory-mapped file, |
| 152 |
|
|
* which is the most efficient object on most systems. |
| 153 |
|
|
* |
| 154 |
|
|
* ASCII output is not supported, so full data recovery is. |
| 155 |
|
|
*/ |
| 156 |
|
|
|
| 157 |
|
|
/// Output channel opening options: new/exclusive, overwrite if exists, or recover data |
| 158 |
greg |
2.3 |
enum RCOutputOp {RCOnew=0, RCOforce, RCOrecover}; |
| 159 |
greg |
2.1 |
|
| 160 |
|
|
/// Converts above to RdataShare open flags (may be adjusted by calling program) |
| 161 |
|
|
extern int RSDOflags[]; |
| 162 |
|
|
|
| 163 |
|
|
/// Call-back function type to create named data channel (freed using "delete" operator) |
| 164 |
|
|
typedef RdataShare * RcreateDataShareF(const char *name, RCOutputOp op, size_t siz); |
| 165 |
|
|
|
| 166 |
|
|
/// Our default data share function |
| 167 |
|
|
extern RcreateDataShareF defDataShare; |
| 168 |
|
|
|
| 169 |
greg |
2.2 |
/// Modifiable ray-tracing flags for rcontrib |
| 170 |
greg |
2.6 |
#define RCcontrib (RTmask+1) // compute contributions? (r.t. coefficients) |
| 171 |
|
|
#define RCmask (RTlimDist|RTimmIrrad|RCcontrib) |
| 172 |
greg |
2.1 |
|
| 173 |
|
|
/// rcontrib-like simulation manager (at most one such object) |
| 174 |
|
|
class RcontribSimulManager : protected RtraceSimulManager { |
| 175 |
|
|
protected: |
| 176 |
|
|
static RayReportCall RctCall; // our callback for traced rays |
| 177 |
|
|
ABitMap rowsDone; // bit mask of completed rows |
| 178 |
|
|
uint32 rInPos; // which row (record) is next on input? |
| 179 |
|
|
uby8 nChan; // NCSAMP setting for this calculation |
| 180 |
|
|
char dtyp; // data type ('f', 'd', or 'c') |
| 181 |
|
|
uint16 dsiz; // N-component element size in bytes |
| 182 |
|
|
RcontribOutput * outList; // ordered list of output channels |
| 183 |
|
|
LUTAB modLUT; // modifier lookup table |
| 184 |
|
|
SUBPROC * kid; // array of child processes |
| 185 |
|
|
int32 * kidRow; // row assigned to each child |
| 186 |
|
|
int nkids; // child process count (-1 in child) |
| 187 |
|
|
bool UpdateRowsDone(int r); |
| 188 |
|
|
int GetChild(bool forceWait = false); |
| 189 |
|
|
bool StartKids(int n2go); |
| 190 |
|
|
int StopKids(int n2end = 0); |
| 191 |
|
|
void RunChild(); |
| 192 |
|
|
public: |
| 193 |
|
|
RCOutputOp outOp; // output operation |
| 194 |
|
|
RcreateDataShareF * cdsF; // data share creator |
| 195 |
greg |
2.6 |
int xres, yres; // output (picture) size |
| 196 |
greg |
2.1 |
uint32 accum; // # rays to accumulate per record |
| 197 |
|
|
RcontribSimulManager(const char *octn = NULL) |
| 198 |
|
|
: RtraceSimulManager(NULL, NULL, octn) { |
| 199 |
|
|
rInPos = 0; |
| 200 |
|
|
nChan = 0; |
| 201 |
|
|
dtyp = 'f'; |
| 202 |
|
|
dsiz = 0; |
| 203 |
|
|
outList = NULL; |
| 204 |
|
|
memset(&modLUT, 0, sizeof(modLUT)); |
| 205 |
|
|
modLUT.hashf = lu_shash; |
| 206 |
|
|
modLUT.keycmp = strcmp; |
| 207 |
|
|
modLUT.freek = efree; |
| 208 |
|
|
modLUT.freed = FreeRcMod; |
| 209 |
|
|
kid = NULL; kidRow = NULL; nkids = 0; |
| 210 |
|
|
outOp = RCOnew; |
| 211 |
|
|
cdsF = &defDataShare; |
| 212 |
greg |
2.6 |
xres = yres = 0; |
| 213 |
greg |
2.1 |
accum = 1; |
| 214 |
greg |
2.10 |
if (octname) { |
| 215 |
|
|
SetTraceCall(&RctCall, this); |
| 216 |
|
|
rtFlags |= RTtraceSources; |
| 217 |
|
|
UpdateMode(); |
| 218 |
|
|
} |
| 219 |
greg |
2.1 |
} |
| 220 |
|
|
~RcontribSimulManager() { |
| 221 |
greg |
2.7 |
if (nkids >= 0) ClearModifiers(); |
| 222 |
greg |
2.1 |
} |
| 223 |
greg |
2.2 |
/// Check modifiable ray-tracing computation flag(s) |
| 224 |
|
|
bool HasFlag(int fl) const { |
| 225 |
|
|
return ((rtFlags & RCmask & fl) != 0); |
| 226 |
|
|
} |
| 227 |
|
|
/// Set/reset modifiable ray-tracing computation flag(s) |
| 228 |
|
|
bool SetFlag(int fl, bool val = true) { |
| 229 |
|
|
if (!(fl &= RCmask)) return false; |
| 230 |
|
|
if (val) rtFlags |= fl; |
| 231 |
|
|
else rtFlags &= ~fl; |
| 232 |
|
|
return true; |
| 233 |
|
|
} |
| 234 |
greg |
2.1 |
/// Load octree and prepare renderer |
| 235 |
|
|
bool LoadOctree(const char *octn) { |
| 236 |
greg |
2.10 |
if (octname) Cleanup(false); |
| 237 |
|
|
if (!RtraceSimulManager::LoadOctree(octn)) |
| 238 |
|
|
return false; |
| 239 |
|
|
SetTraceCall(&RctCall, this); |
| 240 |
|
|
rtFlags |= RTtraceSources; |
| 241 |
|
|
return UpdateMode(); |
| 242 |
greg |
2.1 |
} |
| 243 |
|
|
/// Prepare header from previous input (or clear) |
| 244 |
|
|
bool NewHeader(const char *inspec=NULL) { |
| 245 |
|
|
return RtraceSimulManager::NewHeader(inspec); |
| 246 |
|
|
} |
| 247 |
|
|
/// Add a string to header (adds newline if none) |
| 248 |
|
|
bool AddHeader(const char *str) { |
| 249 |
|
|
return RtraceSimulManager::AddHeader(str); |
| 250 |
|
|
} |
| 251 |
|
|
/// Append program line to header |
| 252 |
|
|
bool AddHeader(int ac, char *av[]) { |
| 253 |
|
|
return RtraceSimulManager::AddHeader(ac, av); |
| 254 |
|
|
} |
| 255 |
|
|
/// Get current header length in bytes |
| 256 |
|
|
int GetHeadLen() const { |
| 257 |
|
|
return RtraceSimulManager::GetHeadLen(); |
| 258 |
|
|
} |
| 259 |
|
|
/// Get header lines if any |
| 260 |
|
|
const char * GetHeadStr() const { |
| 261 |
|
|
return RtraceSimulManager::GetHeadStr(); |
| 262 |
|
|
} |
| 263 |
|
|
/// Look for specific header keyword, return value |
| 264 |
|
|
const char * GetHeadStr(const char *key, bool inOK = false) const { |
| 265 |
|
|
return RtraceSimulManager::GetHeadStr(key, inOK); |
| 266 |
|
|
} |
| 267 |
|
|
/// Set output format ('f', 'd', or 'c'), call before mods |
| 268 |
|
|
bool SetDataFormat(int ty); |
| 269 |
|
|
/// Get current format (and element size in bytes) |
| 270 |
|
|
int GetFormat(int *siz = NULL) const { |
| 271 |
|
|
if (siz) *siz = dsiz; |
| 272 |
|
|
return dtyp; |
| 273 |
|
|
} |
| 274 |
|
|
/// Add a modifier and arguments, create output(s) |
| 275 |
|
|
bool AddModifier(const char *modn, const char *outspec, |
| 276 |
|
|
const char *prms = NULL, |
| 277 |
|
|
const char *binval = NULL, int bincnt = 1); |
| 278 |
|
|
/// Add a file of modifiers with associated arguments |
| 279 |
|
|
bool AddModFile(const char *modfn, const char *outspec, |
| 280 |
|
|
const char *prms = NULL, |
| 281 |
|
|
const char *binval = NULL, int bincnt = 1); |
| 282 |
greg |
2.2 |
/// Get named rcontrib output (or list) |
| 283 |
|
|
const RcontribOutput * GetOutput(const char *nm = NULL) const { |
| 284 |
|
|
if (!nm) return outList; |
| 285 |
|
|
const RcontribOutput * op = outList; |
| 286 |
|
|
while (op && strcmp(op->GetName(), nm)) |
| 287 |
|
|
op = op->next; |
| 288 |
|
|
return op; |
| 289 |
|
|
} |
| 290 |
greg |
2.1 |
/// Open output channels and return # completed rows |
| 291 |
|
|
int PrepOutput(); |
| 292 |
|
|
/// Are we ready to compute some records? |
| 293 |
|
|
bool Ready() const { |
| 294 |
greg |
2.4 |
return (rowsDone.Length() > 0) & (accum > 0); |
| 295 |
greg |
2.1 |
} |
| 296 |
|
|
/// Set number of computation threads (0 => #cores) |
| 297 |
|
|
int SetThreadCount(int nt = 0); |
| 298 |
|
|
/// Check thread count (1 means no multi-processing) |
| 299 |
|
|
int NThreads() const { |
| 300 |
|
|
return nkids + !nkids; |
| 301 |
|
|
} |
| 302 |
|
|
/// What is maximum row? |
| 303 |
|
|
int GetRowMax() const { |
| 304 |
|
|
if (!outList) return yres * (xres + !xres); |
| 305 |
|
|
return outList->nRows; |
| 306 |
|
|
} |
| 307 |
|
|
/// Get current row count (# rows sent for computation) |
| 308 |
|
|
int GetRowCount() const { |
| 309 |
|
|
return rInPos; |
| 310 |
|
|
} |
| 311 |
|
|
/// Get # rows completed |
| 312 |
|
|
int GetRowFinished() const { |
| 313 |
|
|
if (!nkids) return rInPos; |
| 314 |
|
|
uint32 nDone = rowsDone.Find(0, false); |
| 315 |
|
|
if (nDone == ABMend) |
| 316 |
|
|
return rowsDone.Length(); |
| 317 |
|
|
return nDone; |
| 318 |
|
|
} |
| 319 |
|
|
/// Add a ray/bundle to compute next record (n=accum) |
| 320 |
|
|
int ComputeRecord(const FVECT orig_direc[]); |
| 321 |
|
|
/// Finish pending rays if multi-processing |
| 322 |
|
|
bool FlushQueue() { |
| 323 |
|
|
if (nkids <= 0) return true; |
| 324 |
|
|
while (GetChild(true) >= 0) |
| 325 |
|
|
; |
| 326 |
|
|
return true; |
| 327 |
|
|
} |
| 328 |
greg |
2.7 |
/// Rewind calculation (previous results unchanged) |
| 329 |
|
|
bool ResetRow(int r); |
| 330 |
|
|
/// Clear the modifiers and close all outputs |
| 331 |
|
|
void ClearModifiers() { |
| 332 |
greg |
2.1 |
if (rowsDone.Length()) { |
| 333 |
|
|
SetThreadCount(1); |
| 334 |
|
|
rowsDone.NewBitMap(0); |
| 335 |
greg |
2.10 |
rInPos = 0; |
| 336 |
greg |
2.1 |
} |
| 337 |
|
|
lu_done(&modLUT); |
| 338 |
|
|
delete outList; outList = NULL; |
| 339 |
|
|
nChan = 0; |
| 340 |
greg |
2.7 |
} |
| 341 |
|
|
/// Close octree, free data, return status |
| 342 |
|
|
int Cleanup(bool everything = false) { |
| 343 |
|
|
ClearModifiers(); |
| 344 |
greg |
2.9 |
cow_doneshare(); |
| 345 |
greg |
2.10 |
if (everything) { |
| 346 |
|
|
dtyp = 'f'; |
| 347 |
|
|
outOp = RCOnew; |
| 348 |
|
|
cdsF = &defDataShare; |
| 349 |
|
|
xres = yres = 0; |
| 350 |
|
|
accum = 1; |
| 351 |
|
|
rtFlags &= ~RCmask; |
| 352 |
|
|
} |
| 353 |
greg |
2.1 |
return RtraceSimulManager::Cleanup(everything); |
| 354 |
|
|
} |
| 355 |
|
|
}; |
| 356 |
|
|
|
| 357 |
greg |
2.8 |
extern const char * formstr(int f); // string from format |
| 358 |
|
|
|
| 359 |
greg |
2.1 |
#endif /* RcontribSimulManager_h */ |