CFD Online Discussion Forums

CFD Online Discussion Forums (https://www.cfd-online.com/Forums/)
-   OpenFOAM Community Contributions (https://www.cfd-online.com/Forums/openfoam-community-contributions/)
-   -   [swak4Foam] Post-processing on an empty patch using swak4foam (https://www.cfd-online.com/Forums/openfoam-community-contributions/124623-post-processing-empty-patch-using-swak4foam.html)

buffi October 9, 2013 10:42

Post-processing on an empty patch using swak4foam
 
Hi,

I have a large domain consisting of multiple similar regions for which I want to calculate surface flow field quantities such as U*T*dA through a surface in order to come up with an energy balance.

I used topoSet to create cellSets (for each region) and then created smaller meshes using subsetMesh. However, the new meshes contain an empty patch (which was internal before) called oldInternalFaces. I understand why that empty patch must be there, but how can I now calculate surface field flow?

I tried swak4Foam with this function object:
Code:

  QFlow
  {
    type patchFieldFlow;
    functionObjectLibs
    (
      "libsimpleFunctionObjects.so"
    );
    verbose true;
    patches
    (
      inX
      outX
      oldInternalFaces
    );
    fields
    (
      k
    );
    factor 4185;
    outputControl timeStep;
    outputInterval 1;
  }

but unfortunately, swak4foam reports surface field flow through oldInternalFaces as zero.

Also, the field I'm interested in (T) cannot be found by swak4foam (that's why I used k in the above example). Does anybody know why and how I can fix that? The field is where it's supposed to be and I can view it in paraFoam.

When I do the same calculation in paraFoam using the calculator filter with U*T, the resulting surface field flow is non-zero. So to sum it up: How can I calculate quantities such as U*T*dA and integrate them over an empty patch? I don't want to use paraFoam as I'd like to use the results in scripts (many cases).

Regards

Christoph

gschaider October 9, 2013 11:08

Quote:

Originally Posted by buffi (Post 455949)
Hi,

I have a large domain consisting of multiple similar regions for which I want to calculate surface flow field quantities such as U*T*dA through a surface in order to come up with an energy balance.

I used topoSet to create cellSets (for each region) and then created smaller meshes using subsetMesh. However, the new meshes contain an empty patch (which was internal before) called oldInternalFaces. I understand why that empty patch must be there, but how can I now calculate surface field flow?

I tried swak4Foam with this function object:
Code:

  QFlow
  {
    type patchFieldFlow;
    functionObjectLibs
    (
      "libsimpleFunctionObjects.so"
    );
    verbose true;
    patches
    (
      inX
      outX
      oldInternalFaces
    );
    fields
    (
      k
    );
    factor 4185;
    outputControl timeStep;
    outputInterval 1;
  }

but unfortunately, swak4foam reports surface field flow through oldInternalFaces as zero.

Check phi. I think (but please check before you take my word) that this should be zero on an empty patch. And 0*k is 0

Quote:

Originally Posted by buffi (Post 455949)
Also, the field I'm interested in (T) cannot be found by swak4foam (that's why I used k in the above example). Does anybody know why and how I can fix that? The field is where it's supposed to be and I can view it in paraFoam.

That is strange. Which solver are you using? If T is in the registry swak should find it. But there are very special cases where a second field named T exists and throws the original out of the registry (its still there. Just not registered anymore). On the other hand: then T shouldn't get written anyhow

Quote:

Originally Posted by buffi (Post 455949)
When I do the same calculation in paraFoam using the calculator filter with U*T, the resulting surface field flow is non-zero. So to sum it up: How can I calculate quantities such as U*T*dA and integrate them over an empty patch? I don't want to use paraFoam as I'd like to use the results in scripts (many cases).

That is quite possible. If paraview doesn't understand a boundary condition it uses zeroGradient. So you might get a non-zero U on the empty-boundary (and even a component "through" the empty). Maybe an expression "(U&Sf())*T" will give you your flow (not sure whether U is allowed to be non-zero on the boundary)

buffi October 9, 2013 11:35

Quote:

Originally Posted by gschaider (Post 455958)
Check phi. I think (but please check before you take my word) that this should be zero on an empty patch. And 0*k is 0

I wasn't sure how to check phi, so I just looked at the boundary in phi.gz and it just contains the "empty" patch description. However, the patch normal is aligned with the y coordinate, so I foamCalc'ed components U and the result of Uy*T is zero as well.

I'm using simpleFoam with an added equation for T. Here's the instatiation:
Code:

volScalarField T
(
  IOobject
  (
    "T",
    runTime.timeName(),
    mesh,
    IOobject::MUST_READ,
    IOobject::AUTO_WRITE
  ),
  mesh
);

Quote:

Maybe an expression "(U&Sf())*T" will give you your flow
How would the function object look like then? I tried
Code:

  QFlow1
  {
    type surfaces;
    valueType surface;
    surfaceName oldInternalFaces;
    expression "U&Sf())*T";
    accumulations (sum);
    outputControl timeStep;
    outputInterval 1;
  }

but that also gave me zero.Not sure if the function object is correct, though.

My conclusion for now is that my way of splitting the domain for post-processing is not well suited for my goal of integrating over the new surface created by the split.

buffi October 9, 2013 12:01

If that matters, here's how I execute the function:
Code:

execFlowFunctionObjects -dict funkyDoCalcDict
and the dict is in the system/.

gschaider October 9, 2013 16:23

Quote:

Originally Posted by buffi (Post 455973)
I wasn't sure how to check phi, so I just looked at the boundary in phi.gz and it just contains the "empty" patch description. However, the patch normal is aligned with the y coordinate, so I foamCalc'ed components U and the result of Uy*T is zero as well.

I'm using simpleFoam with an added equation for T. Here's the instatiation:
Code:

volScalarField T
(
  IOobject
  (
    "T",
    runTime.timeName(),
    mesh,
    IOobject::MUST_READ,
    IOobject::AUTO_WRITE
  ),
  mesh
);

How would the function object look like then? I tried
Code:

  QFlow1
  {
    type surfaces;
    valueType surface;
    surfaceName oldInternalFaces;
    expression "U&Sf())*T";
    accumulations (sum);
    outputControl timeStep;
    outputInterval 1;
  }

but that also gave me zero.Not sure if the function object is correct, though.

Looks OK to me.

And it "finds" T (you must have changed something)

Quote:

Originally Posted by buffi (Post 455973)
My conclusion for now is that my way of splitting the domain for post-processing is not well suited for my goal of integrating over the new surface created by the split.

Splitting is OK (I guess). The problem is that "empty" is not the appropriate BC for that. That BC is for "erasing" the 3rd dimension for a 2D-calculation. So it is designed to "not let anything through".

buffi October 10, 2013 03:42

Quote:

Originally Posted by gschaider (Post 456022)
Looks OK to me.
And it "finds" T (you must have changed something)

Yes, it's a totally different function object which presumably is implemented differently. I haven't had a look at the code, though...

Quote:

Originally Posted by gschaider (Post 456022)
Splitting is OK (I guess). The problem is that "empty" is not the appropriate BC for that. That BC is for "erasing" the 3rd dimension for a 2D-calculation. So it is designed to "not let anything through".

Yes, empty is not suitable in this case. Any suggestion what I could use instead without too much hassle? I tried to turn it into a plain patch using createPatch and then remap the fields, but mapFields refused to map anything.

gschaider October 10, 2013 10:57

Quote:

Originally Posted by buffi (Post 456083)
Yes, it's a totally different function object which presumably is implemented differently. I haven't had a look at the code, though...

Both use "lookupObject" so it should be the same

Quote:

Originally Posted by buffi (Post 456083)
Yes, empty is not suitable in this case. Any suggestion what I could use instead without too much hassle? I tried to turn it into a plain patch using createPatch and then remap the fields, but mapFields refused to map anything.

I'm not sure what your "multiple regions" (original posting) are. Your setup only makes sense for a multiRegion-solver like chtFoam. If you want "control surfaces" in a single-region solver then faceZones or faceSets are more what you need

buffi October 10, 2013 11:13

Thanks for the hint, the term "region" in my first post was misleading. I'll try faceSets or faceZones. I have never used faceZones, what exactly are they? The documentation is not very verbose in that respect...

gschaider October 10, 2013 13:31

Quote:

Originally Posted by buffi (Post 456185)
Thanks for the hint, the term "region" in my first post was misleading. I'll try faceSets or faceZones. I have never used faceZones, what exactly are they? The documentation is not very verbose in that respect...

These are collections of faces. Some mesh converters generate them. Another possibility is topoSet (look through the tutorials for examples like lagrangian/reactingParcelFoam/filter/system/topoSetDict).

But that is not a swak-problem anymore

buffi October 11, 2013 04:25

2 Attachment(s)
I did a forum search on the difference between faceSets and faceZones, and found this thread: http://www.cfd-online.com/Forums/ope...condition.html (post #8). So what I would need here is a faceZone wherever I want to sample in the field and I could then use swak4Foam or some other post-processing tool to calculate the quantities I'm interested in and integrate them over the zone. Does that sound viable? It would still be a potential swak-problem ;)

To make this more descriptive, here are two screenshots of the whole mesh and of the subdomain:
Attachment 25994
The whole domain consists of 5 similar subdomains for which I want to calculate an energy balance. This is one of the subdomains I generated with subsetMesh, the new empty patch is on the left side:
Attachment 25995

gschaider October 11, 2013 08:28

Quote:

Originally Posted by buffi (Post 456291)
I did a forum search on the difference between faceSets and faceZones, and found this thread: http://www.cfd-online.com/Forums/ope...condition.html (post #8). So what I would need here is a faceZone wherever I want to sample in the field and I could then use swak4Foam or some other post-processing tool to calculate the quantities I'm interested in and integrate them over the zone. Does that sound viable? It would still be a potential swak-problem ;)

To make this more descriptive, here are two screenshots of the whole mesh and of the subdomain:
Attachment 25994
The whole domain consists of 5 similar subdomains for which I want to calculate an energy balance. This is one of the subdomains I generated with subsetMesh, the new empty patch is on the left side:
Attachment 25995

swak can do calculations on faceSets and faceZones. So if can create them you're in business. Examples for using swakExpression or similar can be found in the examples and in the presentations that are found on the Wiki-page. If you use phi you'll need the flip()-function

buffi October 11, 2013 08:46

Well, I was able to create a faceSet from the new empty patch, but not in the larger domain where these faces would be internal.

Evaluating with swak4foam didn't work as expected. This is the code I used:
Code:

functions
(
  QFlow2
  {
    type swakExpression;
    valueType faceSet;
    setName beforeFilter;
    expression "phi*flip()*T";
    accumulations (
      sum
    );
    verbose true;
  }
);

but I got this error message:
Code:

Unknown function type swakExpression

Table of functionObjects is empty


gschaider October 11, 2013 09:58

Quote:

Originally Posted by buffi (Post 456343)
Well, I was able to create a faceSet from the new empty patch, but not in the larger domain where these faces would be internal.

Evaluating with swak4foam didn't work as expected. This is the code I used:
Code:

functions
(
  QFlow2
  {
    type swakExpression;
    valueType faceSet;
    setName beforeFilter;
    expression "phi*flip()*T";
    accumulations (
      sum
    );
    verbose true;
  }
);

but I got this error message:
Code:

Unknown function type swakExpression

Table of functionObjects is empty


You've got to add the library with the functionObjects to the libs-list in controlDict (check the examples)

buffi October 11, 2013 11:52

Thanks for the hint, will try that on monday...

buffi October 14, 2013 04:59

Adding the lib helped a bit, but didn't give me a result. For
Code:

functions
(
  QFlow2
  {
    type swakExpression;
    valueType faceSet;
    setName intFaces;
    expression "phi*flip()*T";
    accumulations (
      sum
    );
    verbose true;
  }
);

to work, I need a faceSet named "intFaces" and a cellSet named "intFacesSlaveCells". I created those with a topoSetDict containing
Code:

actions
(
  {
    name intFaces;
    type faceSet;
    action new;
    source patchToFace;
    sourceInfo
    {
      name "oldInternalFaces";
    }
  }
  {
    name intFacesSlaveCells;
    type cellSet;
    action new;
    source faceToCell;
    sourceInfo
    {
      set intFaces;            // Name of faceSet
      option any;
    }
  }
);

However, executing
Code:

execFlowFunctionObjects -time 10011 -dict funkyDoCalcDict
returns an error stating: "field T not existing or of wrong type". The field T does exist and can viewed in paraFoam.

gschaider October 14, 2013 08:31

Quote:

Originally Posted by buffi (Post 456771)
Adding the lib helped a bit, but didn't give me a result. For
Code:

functions
(
  QFlow2
  {
    type swakExpression;
    valueType faceSet;
    setName intFaces;
    expression "phi*flip()*T";
    accumulations (
      sum
    );
    verbose true;
  }
);

to work, I need a faceSet named "intFaces" and a cellSet named "intFacesSlaveCells". I created those with a topoSetDict containing
Code:

actions
(
  {
    name intFaces;
    type faceSet;
    action new;
    source patchToFace;
    sourceInfo
    {
      name "oldInternalFaces";
    }
  }
  {
    name intFacesSlaveCells;
    type cellSet;
    action new;
    source faceToCell;
    sourceInfo
    {
      set intFaces;            // Name of faceSet
      option any;
    }
  }
);

However, executing
Code:

execFlowFunctionObjects -time 10011 -dict funkyDoCalcDict
returns an error stating: "field T not existing or of wrong type". The field T does exist and can viewed in paraFoam.

The function objects don't search on the disc for data but only in memory. You can switch that behaviour on with the searchOnDisc-option (must be set in each FO-spec. See the incomplete reference guide). But why don't you use funkyDoCalc?

buffi October 14, 2013 08:49

I didn't use funkyDoCalc because I didn't get it working first, that's all. I didn't know about any substantial differences between the two so this was not real decision.

Removed the "functions" block surrounding the definition to make it work with funkyDoCalc, this is the resulting dict:
Code:

QFlow2
{
  type swakExpression;
  valueType faceSet;
  setName intFaces;
  searchOnDisk true;
  expression "phi*flip()*T";
  accumulations (
    sum
  );
  verbose true;
}

But unfortunately the error remains:
Code:

Could not find a field name T of type scalar (neither surfaceScalarField nor volScalarField) autoInterpolate: 0 (try setting 'autoInterpolate' to 'true')


    From function SubsetValueExpressionDriver::getFieldInternalAndInterpolate(const word &name,const Subset &sub)
    in file SubsetValueExpressionDriverI.H at line 303.


gschaider October 14, 2013 10:15

Quote:

Originally Posted by buffi (Post 456834)
I didn't use funkyDoCalc because I didn't get it working first, that's all. I didn't know about any substantial differences between the two so this was not real decision.

Removed the "functions" block surrounding the definition to make it work with funkyDoCalc, this is the resulting dict:
Code:

QFlow2
{
  type swakExpression;
  valueType faceSet;
  setName intFaces;
  searchOnDisk true;
  expression "phi*flip()*T";
  accumulations (
    sum
  );
  verbose true;
}

But unfortunately the error remains:
Code:

Could not find a field name T of type scalar (neither surfaceScalarField nor volScalarField) autoInterpolate: 0 (try setting 'autoInterpolate' to 'true')


    From function SubsetValueExpressionDriver::getFieldInternalAndInterpolate(const word &name,const Subset &sub)
    in file SubsetValueExpressionDriverI.H at line 303.


I think the error message explains quite well what the problem (you're doing calculations on faces and need a field that is only defined in the cells) is and it even suggests a fix (read the reference guide about autoInterpolate).

No matter what I write into the error messages the effect is similar to writing "There is a problem. Ask Bernhard". And when I ask nobody says "Well. I would have understood that error message if it had said ...." so I guess people think "Ups. I should have read the content of the message before asking"

buffi October 14, 2013 10:37

Quote:

Originally Posted by gschaider (Post 456854)
I think the error message explains quite well what the problem (you're doing calculations on faces and need a field that is only defined in the cells) is and it even suggests a fix (read the reference guide about autoInterpolate).

I read the error message and thought "If there is no field to be found, interpolating that not-a-field will not solve my problem". That's why I didn't even try autoInterpolate.
Quote:

No matter what I write into the error messages the effect is similar to writing "There is a problem. Ask Bernhard". And when I ask nobody says "Well. I would have understood that error message if it had said ...." so I guess people think "Ups. I should have read the content of the message before asking"
I totally understand your point here as I'm in a similar position regularly, but in a different context.

adding autoInterpolate true to the function indeed made the error disappear, I'll see if the results make any sense.

Thanks!

Christoph


All times are GMT -4. The time now is 12:43.