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) 2021
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_ScalarField.h>
35 #include <SIM/SIM_VectorField.h>
36 #include <SIM/SIM_MatrixField.h>
37 #include <SIM/SIM_Object.h>
38 #include <GAS/GAS_SubSolver.h>
39 
40 using namespace HDK_Sample;
41 
42 ///
43 /// This is the hook that Houdini grabs from the dll to link in
44 /// this. As such, it merely has to implement the data factory
45 /// for this node.
46 ///
47 void
49 {
51 }
52 
53 /// Standard constructor, note that BaseClass was crated by the
54 /// DECLARE_DATAFACTORY and provides an easy way to chain through
55 /// the class hierarchy.
57  : BaseClass(factory)
58 {
59 }
60 
62 {
63 }
64 
65 /// Used to automatically populate the node which will represent
66 /// this data type.
67 const SIM_DopDescription *
68 SIM_GasAdd::getDopDescription()
69 {
70  static PRM_Name theDstFieldName(GAS_NAME_FIELDDEST, "Dest Field");
71  static PRM_Name theSrcFieldName(GAS_NAME_FIELDSOURCE, "Source Field");
72 
73  static PRM_Template theTemplates[] = {
74  PRM_Template(PRM_STRING, 1, &theDstFieldName),
75  PRM_Template(PRM_STRING, 1, &theSrcFieldName),
76  PRM_Template()
77  };
78 
79  static SIM_DopDescription theDopDescription(
80  true, // Should we make a DOP?
81  "hdk_gasadd", // Internal name of the DOP.
82  "Gas Add", // Label of the DOP
83  "Solver", // Default data name
84  classname(), // The type of this DOP, usually the class.
85  theTemplates); // Template list for generating the DOP
86 
87  return &theDopDescription;
88 }
89 
90 bool
92  SIM_Object *obj,
93  SIM_Time time,
94  SIM_Time timestep)
95 {
96  SIM_ScalarField *srcscalar, *dstscalar;
97  SIM_VectorField *srcvector, *dstvector;
98  SIM_MatrixField *srcmatrix, *dstmatrix;
99 
101  int i, j, k;
102 
105 
106  // Now for each pair of source and dst fields, we want to add
107  // src to dst. We want to support scalar, vector, and matrix fields,
108  // but only compatible operations. We can determine what type we
109  // have via casting.
110  for (i = 0; i < dst.entries(); i++)
111  {
112  // Check to see if we exceeded our src list.
113  if (i >= src.entries())
114  {
115  addError(obj, SIM_MESSAGE, "Fewer source fields than destination fields.", UT_ERROR_WARNING);
116  break;
117  }
118 
119  // Try each casting option.
120  dstscalar = SIM_DATA_CAST(dst(i), SIM_ScalarField);
121  srcscalar = SIM_DATA_CAST(src(i), SIM_ScalarField);
122 
123  dstvector = SIM_DATA_CAST(dst(i), SIM_VectorField);
124  srcvector = SIM_DATA_CAST(src(i), SIM_VectorField);
125 
126  dstmatrix = SIM_DATA_CAST(dst(i), SIM_MatrixField);
127  srcmatrix = SIM_DATA_CAST(src(i), SIM_MatrixField);
128 
129  if (dstscalar && srcscalar)
130  {
131  addFields(dstscalar->getField(), srcscalar->getField());
132  }
133 
134  if (dstvector && srcvector)
135  {
136  for (j = 0; j < 3; j++)
137  addFields(dstvector->getField(j), srcvector->getField(j));
138  }
139 
140  if (dstmatrix && srcmatrix)
141  {
142  for (j = 0; j < 3; j++)
143  for (k = 0; k < 3; k++)
144  addFields(dstmatrix->getField(j, k), srcmatrix->getField(j, k));
145  }
146 
147  // Make sure we are flagged as dirty
148  if (dstscalar)
149  dstscalar->pubHandleModification();
150  if (dstvector)
151  dstvector->pubHandleModification();
152  if (dstmatrix)
153  dstmatrix->pubHandleModification();
154  }
155 
156  // Successful cook
157  return true;
158 }
159 
160 void
162 {
164  UT_Interrupt *boss = UTgetInterrupt();
165 
166  // Initialize our iterator to run over our destination field.
167  vit.setArray(dst->fieldNC());
168 
169  // When we complete each tile the tile is tested to see if it can be
170  // compressed, ie, is now constant. If so, it is compressed.
171  vit.setCompressOnExit(true);
172 
173  // Restrict our iterator only over part of the range. Using the
174  // info parameters means each thread gets its own subregion.
175  vit.setPartialRange(info.job(), info.numJobs());
176 
177  // Check if we are aligned. If we are aligned, we have a precise
178  // 1:1 mapping of our voxels so we don't need to do any lookups
179  // from world space, which is much faster.
180  if (dst->isAligned(src))
181  {
182  UT_VoxelProbeF probe;
183 
184  probe.setConstArray(src->field());
185 
186  for (vit.rewind(); !vit.atEnd(); vit.advance())
187  {
188  if (vit.isStartOfTile() && boss->opInterrupt())
189  break;
190 
191  // Update our read probe to match our current iterator
192  // position
193  probe.setIndex(vit);
194 
195  // Write out the sum of the two fields.
196  // Instead of using the iterator, we could also
197  // have built a UT_VoxelRWProbeF.
198  vit.setValue( vit.getValue() + probe.getValue() );
199  }
200  }
201  else
202  {
203  // We need to lookup the world space position of our voxel so we can
204  // find it in our destination.
205  UT_Vector3 pos;
206 
207  for (vit.rewind(); !vit.atEnd(); vit.advance())
208  {
209  if (vit.isStartOfTile() && boss->opInterrupt())
210  break;
211  dst->indexToPos(vit.x(), vit.y(), vit.z(), pos);
212 
213  // Read the source field with trilinear interpolation
214  // according to our world space position, this allows
215  // us to thus work with misaligned fields.
216  vit.setValue( vit.getValue() + src->getValue(pos) );
217  }
218  }
219 }
int x() const
Retrieve the current location of the iterator.
SIM_RawField * getField(int axis) const
Retrieve raw field.
GLenum src
Definition: glew.h:2410
bool solveGasSubclass(SIM_Engine &engine, SIM_Object *obj, SIM_Time time, SIM_Time timestep) override
Definition: SIM_GasAdd.C:91
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)
Definition: SIM_DataUtils.h:97
GT_API const UT_StringHolder time
~SIM_GasAdd() override
Definition: SIM_GasAdd.C:61
void setValue(T t) const
Sets the voxel we are currently pointing to the given value.
UT_VoxelArrayF * fieldNC() const
Definition: SIM_RawField.h:495
SIM_RawField * getField(int i, int j) const
Retrieve raw field.
fpreal getValue(UT_Vector3 pos) const
Functions to resolve quantities about the field.
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:56
GLhandleARB obj
Definition: glew.h:6236
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.
T getValue() const
#define GAS_NAME_FIELDSOURCE
Definition: GAS_Utils.h:29
GLenum GLenum dst
Definition: glew.h:2410
#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)
bool setIndex(UT_VoxelArrayIterator< S > &vit)
This class holds a three dimensional tensor field.
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:460
void setConstArray(const UT_VoxelArray< T > *vox, int prex=0, int postx=0)
int numJobs() const
UT_API UT_Interrupt * UTgetInterrupt()
Obtain global UT_Interrupt singleton.
This class holds a three dimensional scalar field.
bool isAligned(const SIM_RawField *field) const
bool indexToPos(int x, int y, int z, UT_Vector3 &pos) const
#define SIM_DATA_CAST(Data, DataClass)
Definition: SIM_Utils.h:28
void initializeSIM(void *)
Definition: SIM_GasAdd.C:48
SIM_RawField * getField() const
Retrieve raw field.
This class holds a three dimensional vector field.
UT_VoxelArrayF UT_VoxelArrayF & field
void addFieldsPartial(SIM_RawField *dst, const SIM_RawField *src, const UT_JobInfo &info)
Definition: SIM_GasAdd.C:161
int job() const
void advance()
Advances the iterator to point to the next voxel.