HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SIM_GasAdd.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024
3  * Side Effects Software Inc. All rights reserved.
4  *
5  * Redistribution and use of Houdini Development Kit samples in source and
6  * binary forms, with or without modification, are permitted provided that the
7  * following conditions are met:
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. The name of Side Effects Software may not be used to endorse or
11  * promote products derived from this software without specific prior
12  * written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  *----------------------------------------------------------------------------
26  */
27 
28 #include "SIM_GasAdd.h"
29 #include <UT/UT_DSOVersion.h>
30 #include <UT/UT_Interrupt.h>
31 #include <PRM/PRM_Include.h>
32 #include <SIM/SIM_PRMShared.h>
33 #include <SIM/SIM_DopDescription.h>
34 #include <SIM/SIM_FieldSampler.h>
35 #include <SIM/SIM_ScalarField.h>
36 #include <SIM/SIM_VectorField.h>
37 #include <SIM/SIM_MatrixField.h>
38 #include <SIM/SIM_Object.h>
39 #include <GAS/GAS_SubSolver.h>
40 
41 using namespace HDK_Sample;
42 
43 ///
44 /// This is the hook that Houdini grabs from the dll to link in
45 /// this. As such, it merely has to implement the data factory
46 /// for this node.
47 ///
48 void
50 {
52 }
53 
54 /// Standard constructor, note that BaseClass was crated by the
55 /// DECLARE_DATAFACTORY and provides an easy way to chain through
56 /// the class hierarchy.
58  : BaseClass(factory)
59 {
60 }
61 
63 {
64 }
65 
66 /// Used to automatically populate the node which will represent
67 /// this data type.
68 const SIM_DopDescription *
69 SIM_GasAdd::getDopDescription()
70 {
71  static PRM_Name theDstFieldName(GAS_NAME_FIELDDEST, "Dest Field");
72  static PRM_Name theSrcFieldName(GAS_NAME_FIELDSOURCE, "Source Field");
73 
74  static PRM_Template theTemplates[] = {
75  PRM_Template(PRM_STRING, 1, &theDstFieldName),
76  PRM_Template(PRM_STRING, 1, &theSrcFieldName),
77  PRM_Template()
78  };
79 
80  static SIM_DopDescription theDopDescription(
81  true, // Should we make a DOP?
82  "hdk_gasadd", // Internal name of the DOP.
83  "Gas Add", // Label of the DOP
84  "Solver", // Default data name
85  classname(), // The type of this DOP, usually the class.
86  theTemplates); // Template list for generating the DOP
87 
88  return &theDopDescription;
89 }
90 
91 bool
93  SIM_Object *obj,
94  SIM_Time time,
95  SIM_Time timestep)
96 {
97  SIM_ScalarField *srcscalar, *dstscalar;
98  SIM_VectorField *srcvector, *dstvector;
99  SIM_MatrixField *srcmatrix, *dstmatrix;
100 
102  int i, j, k;
103 
106 
107  // Now for each pair of source and dst fields, we want to add
108  // src to dst. We want to support scalar, vector, and matrix fields,
109  // but only compatible operations. We can determine what type we
110  // have via casting.
111  for (i = 0; i < dst.entries(); i++)
112  {
113  // Check to see if we exceeded our src list.
114  if (i >= src.entries())
115  {
116  addError(obj, SIM_MESSAGE, "Fewer source fields than destination fields.", UT_ERROR_WARNING);
117  break;
118  }
119 
120  // Try each casting option.
121  dstscalar = SIM_DATA_CAST(dst(i), SIM_ScalarField);
122  srcscalar = SIM_DATA_CAST(src(i), SIM_ScalarField);
123 
124  dstvector = SIM_DATA_CAST(dst(i), SIM_VectorField);
125  srcvector = SIM_DATA_CAST(src(i), SIM_VectorField);
126 
127  dstmatrix = SIM_DATA_CAST(dst(i), SIM_MatrixField);
128  srcmatrix = SIM_DATA_CAST(src(i), SIM_MatrixField);
129 
130  if (dstscalar && srcscalar)
131  {
132  addFields(dstscalar->getField(), srcscalar->getField());
133  }
134 
135  if (dstvector && srcvector)
136  {
137  for (j = 0; j < 3; j++)
138  addFields(dstvector->getField(j), srcvector->getField(j));
139  }
140 
141  if (dstmatrix && srcmatrix)
142  {
143  for (j = 0; j < 3; j++)
144  for (k = 0; k < 3; k++)
145  addFields(dstmatrix->getField(j, k), srcmatrix->getField(j, k));
146  }
147 
148  // Make sure we are flagged as dirty
149  if (dstscalar)
150  dstscalar->pubHandleModification();
151  if (dstvector)
152  dstvector->pubHandleModification();
153  if (dstmatrix)
154  dstmatrix->pubHandleModification();
155  }
156 
157  // Successful cook
158  return true;
159 }
160 
161 void
163 {
165  UT_Interrupt *boss = UTgetInterrupt();
166 
167  // Initialize our iterator to run over our destination field.
168  vit.setArray(dst->fieldNC());
169 
170  // When we complete each tile the tile is tested to see if it can be
171  // compressed, ie, is now constant. If so, it is compressed.
172  vit.setCompressOnExit(true);
173 
174  // Restrict our iterator only over part of the range. Using the
175  // info parameters means each thread gets its own subregion.
176  vit.setPartialRange(info.job(), info.numJobs());
177 
178  // Create a sampler for the source field.
179  SIM_ScalarFieldSampler srcsampler(dst, src);
180  float srcval;
181 
182  // Visit every voxel of the destination array.
183  for (vit.rewind(); !vit.atEnd(); vit.advance())
184  {
185  if (vit.isStartOfTile())
186  {
187  if (boss->opInterrupt())
188  break;
189 
190  // Check if both source and destination tiles are constant.
191  if (vit.isTileConstant() &&
192  srcsampler.isTileConstant(vit, srcval))
193  {
194  // If both are constant, we can process the whole tile at
195  // once. We call skipToEndOfTile() here so that the loop's
196  // call to advance() will move us to the next tile.
197  vit.getTile()->makeConstant( vit.getValue() + srcval );
198  vit.skipToEndOfTile();
199  continue;
200  }
201  }
202 
203  // Write out the sum of the two fields. Instead of using the
204  // iterator, we could also have built a UT_VoxelRWProbeF.
205  float srcval = srcsampler.getValue(vit);
206  vit.setValue( vit.getValue() + srcval );
207  }
208 }
SYS_FORCE_INLINE bool isTileConstant(const UT_VoxelArrayIteratorF &iter, float &val)
UT_VoxelTile< T > * getTile() const
Returns the VoxelTile we are currently processing.
bool solveGasSubclass(SIM_Engine &engine, SIM_Object *obj, SIM_Time time, SIM_Time timestep) override
Definition: SIM_GasAdd.C:92
void pubHandleModification()
Signals to the field that it has been altered externally.
bool atEnd() const
Returns true if we have iterated over all of the voxels.
PRM_API const PRM_Type PRM_STRING
#define IMPLEMENT_DATAFACTORY(DataClass)
GT_API const UT_StringHolder time
SYS_FORCE_INLINE float getValue(int x, int y, int z)
~SIM_GasAdd() override
Definition: SIM_GasAdd.C:62
const SIM_RawField * getField(int axis) const
Retrieve raw field.
void setValue(T t) const
Sets the voxel we are currently pointing to the given value.
UT_VoxelArrayF * fieldNC() const
Definition: SIM_RawField.h:507
bool isStartOfTile() const
Returns true if we are at the start of a new tile.
void setArray(UT_VoxelArray< T > *vox)
SIM_GasAdd(const SIM_DataFactory *factory)
Definition: SIM_GasAdd.C:57
void getMatchingData(SIM_DataArray &data, SIM_Object *obj, const char *name, bool silent=false)
void pubHandleModification()
int opInterrupt(int percent=-1)
void setPartialRange(int idx, int numranges)
void pubHandleModification()
void rewind()
Resets the iterator to point to the first voxel.
#define GAS_NAME_FIELDSOURCE
Definition: GAS_Utils.h:29
#define GAS_NAME_FIELDDEST
Definition: GAS_Utils.h:28
void addError(const SIM_RootData *root, int errorcode, const char *errorparm, UT_ErrorSeverity severity) const
Adds an error to our SIM_Engine.
void setCompressOnExit(bool shouldcompress)
This class holds a three dimensional tensor field.
bool isTileConstant() const
Returns true if the tile we are currently in is a constant tile.
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:648
GLint j
Definition: glad.h:2733
const SIM_RawField * getField() const
Retrieve raw field.
GLenum GLenum dst
Definition: glcorearb.h:1793
int numJobs() const
UT_API UT_Interrupt * UTgetInterrupt()
Obtain global UT_Interrupt singleton.
This class holds a three dimensional scalar field.
#define SIM_DATA_CAST(Data, DataClass)
Definition: SIM_Utils.h:28
void initializeSIM(void *)
Definition: SIM_GasAdd.C:49
const SIM_RawField * getField(int i, int j) const
Retrieve raw field.
This class holds a three dimensional vector field.
void addFieldsPartial(SIM_RawField *dst, const SIM_RawField *src, const UT_JobInfo &info)
Definition: SIM_GasAdd.C:162
int job() const
void advance()
Advances the iterator to point to the next voxel.
GLenum src
Definition: glcorearb.h:1793