I have this code:
def get_field(odb, step, frame, field, element):
if field == 'E':
function = get_strain
for f in odb.steps[step].frames[frame].fieldOutputs[field].getSubset(region=element_set).values:
data = function(f.data)
dict_data[index] = data
index += 1
return dict_data
I want to include section points and section category. What should I change in this code to achieve that?
You need to use another getSubset:
fo = ..... fieldOutput object
f = fo.getSubset(sectionPoint=sp)
Section point objects can be found in the odb:
odbname = 'mine.odb'
odb = session.odbs[odbname]
sp = odb.sectionCategories.values()[0]
If you want a particular section point number, each section Point object has the property
sp.number
Related
I have been trying to write to a database and am having trouble setting data using two different classes in the one function.
Firstly, all values are being passed through a GUI and in this case, only the following entries were passed: 'Categories' = C, 'Usage' = Charter, 'DispTHR' = 5000.
Here you can see that I have two classes I am wanting to access (airport and runway) where the function set_opsdatabase_details() will go to the appropriate class and write to our database. This is all well and good when the airport and runway are separate from each other; however, when integrating them in the same function I can't seem to get the corresponding airportvalueDict = {} and runwayvalueDict = {] to display the values I want. Could someone help me understand how to write the correct entry box values into the corresponding valueDict dictionaries?
Thank you in advance! (a screenshot of the output from the print statements is attached)
Function in python
Output of function with the print statements
Example of code in text format:
#edit function for first part of operational window
def edit_details1(self):
airport = self.manager.get_chosen_airport()
runway = airport.get_chosen_runway()
airportlabels = ['Category', 'Usage', 'Curfew',
'Surveyor', 'LatestSurvey',
'FuelAvail', 'FuelPrice', 'TankerPort', 'RFF']
runwaylabels = ['DispTHR', 'VASI', 'TCH']
airportvalueDict = {}
runwayvalueDict = {}
print(self.entryDict['Category']["state"])
if self.entryDict['Category']["state"] == 'disabled':
for entry in self.entryDict.values():
entry.config(state=tk.NORMAL)
self.editButton.config(text="Confirm")
elif self.entryDict['Category']['state'] == 'normal':
airport = self.manager.get_chosen_airport()
runway = airport.get_chosen_runway()
values = [x.get() for x in self.varDict.values()]
for label, value in zip(airportlabels, values):
airportvalueDict[label] = value
airport.set_opsdatabase_details(airportvalueDict)
print(f'airport: {airportvalueDict}')
for label, value in zip(runwaylabels, values):
runwayvalueDict[label] = value
runway.set_opsdatabase_details(runwayvalueDict)
print(f'runway: {runwayvalueDict}')
for entry in self.entryDict.values():
entry.config(state=tk.DISABLED)
self.editButton.config(text="Edit...")
I'm new in programming and I need to write a code that create an odb that visualize max value of six field output of a single step. For every single node I would like represent the max value of each field output.
Now I've created a code which results in this this error:
myFieldOutput.addData(position=INTEGRATION_POINT, instance=instance1, data=maxStress)
omu_PrimArray from sequence failed - dimensions.
This is the code:
from abaqus import *
from abaqusConstants import *
import visualization
myViewport = session.Viewport(name='Max_Stess',
origin=(10, 10), width=150, height=100)
# Open the tutorial output database.
myOdb = visualization.openOdb(path='PROVA_04_10.odb', readOnly=False)
# Associate the output database with the viewport.
myViewport.setValues(displayedObject=myOdb)
instance1 = myOdb.rootAssembly.instances['MODIFICA_FUNZIONANTE']
# Create variables that refer to the first steps.
firstStep = myOdb.steps['sigma_equivalenti']
frame = firstStep.frames[-1]
#creo nuovo step
# lettura degli stress dallo step sigma
sigma_eq_1 = frame.fieldOutputs['sigma_eq_1']
sigma_eq_2 = frame.fieldOutputs['sigma_eq_2']
sigma_eq_3 = frame.fieldOutputs['sigma_eq_3']
sigma_eq_4 = frame.fieldOutputs['sigma_eq_4']
sigma_eq_5 = frame.fieldOutputs['sigma_eq_5']
sigma_eq_6 = frame.fieldOutputs['sigma_eq_6']
#calcolo del vettore degli sforzi massimi
maxStress=[]
for i in range(len(sigma_eq_1.values)):
v1=sigma_eq_1.values[i]
v2=sigma_eq_2.values[i]
v3=sigma_eq_3.values[i]
v4=sigma_eq_4.values[i]
v5=sigma_eq_5.values[i]
v6=sigma_eq_6.values[i]
maxStress.append((max(v1,v2,v3,v4,v5,v6),)) #max(valori)
myFieldOutput = frame.FieldOutput(name='tensioni_max',description='calcolo delle tensioni massime', type=SCALAR)
myFieldOutput.addData(position=INTEGRATION_POINT, instance=instance1, data=maxStress)
#visualizzazione della variabile delle sigma massima sul programma
myViewport.odbDisplay.setPrimaryVariable(field=myFieldOutput,outputPosition=INTEGRATION_POINT)
myViewport.odbDisplay.display.setValues(plotState=(CONTOURS_ON_DEF,))
You could use field argument to add the field output data as FieldOutput object. However, you should create the field data from already existing field outputs.
In your case, you could do the following:
Access the field output (NOT the field output data), as you did correctly.
sigma_eq_1 = frame.fieldOutputs['sigma_eq_1']
sigma_eq_2 = frame.fieldOutputs['sigma_eq_2']
sigma_eq_3 = frame.fieldOutputs['sigma_eq_3']
sigma_eq_4 = frame.fieldOutputs['sigma_eq_4']
sigma_eq_5 = frame.fieldOutputs['sigma_eq_5']
sigma_eq_6 = frame.fieldOutputs['sigma_eq_6']
Then, manipulate these field output data. You can do any feasible mathematical operation on these data, for ex. add, substract,etc. In this case, to find maximum value, we have specific command called maxEnvelope.
maxS = maxEnvelope([sigma_eq_1, sigma_eq_2, sigma_eq_3, sigma_eq_4, sigma_eq_5, sigma_eq_6])
Please note, this command takes list as an argument. And this command calculates the new field data at the same position where the original data is availble. In this case, it is available at Integration Point, hence it will be written at Integration Point.
3. Now, you could use field arugment to add field output data.
myFieldOutput = frame.FieldOutput(name='tensioni_max',description='calcolo delle tensioni massime', type=SCALAR)
myFieldOutput.addData(field=maxS[0])
P.S.: As you have imported visualization module as import visualization, you should use maxEnvelope method as visualization.maxEnvelope(...)
Lets say I have an assembly like this:
MainProduct:
-Product1 (Instance of Part1)
-Product2 (Instance of Part2)
-Product3 (Instance of Part2)
-Product4 (Instance of Part3)
...
Now, I want to copy/paste a feature from Product3 into another one.
But I run into problems when selecting the feature programmatically, because there are 2 instances of the part of that feature.
I can't control which feature will be selected by CATIA.ActiveDocument.Selection.Add(myExtractReference)
Catia always selects the feature from Product2 instead of the feature from Product3. So the position of the pasted feature will be wrong!
Does anybody know this problem and has a solution to it?
Edit:
The feature reference which I want to copy already exists as a variable because it was newly created (an extract of selected geometry)
I could get help else where. Still want to share my solution. It's written in Python but in VBA its almost the same.
The clue is to access CATIA.Selection.Item(1).LeafProduct in order to know where the initial selection was made.
import win32com.client
import pycatia
CATIA = win32com.client.dynamic.DumbDispatch('CATIA.Application')
c_doc = CATIA.ActiveDocument
c_sel = c_doc.Selection
c_prod = c_doc.Product
# New part where the feature should be pasted
new_prod = c_prod.Products.AddNewComponent("Part", "")
new_part_doc = new_prod.ReferenceProduct.Parent
# from user selection
sel_obj = c_sel.Item(1).Value
sel_prod_by_user = c_sel.Item(1).LeafProduct # reference to the actual product where the selection was made
doc_from_sel = sel_prod_by_user.ReferenceProduct.Parent # part doc from selection
hb = doc_from_sel.Part.HybridBodies.Add() # new hybrid body for the extract. will be deleted later on
extract = doc_from_sel.Part.HybridShapeFactory.AddNewExtract(sel_obj)
hb.AppendHybridShape(extract)
doc_from_sel.Part.Update()
# Add the extract to the selection and copy it
c_sel.Clear()
c_sel.Add(extract)
sel_prod_by_catia = c_sel.Item(1).LeafProduct # reference to the product where Catia makes the selection
c_sel_copy() # will call Selection.Copy from VBA. Buggy in Python.
# Paste the extract into the new part in a new hybrid body
c_sel.Clear()
new_hb = new_part_doc.Part.HybridBodies.Item(1)
c_sel.Add(new_hb)
c_sel.PasteSpecial("CATPrtResultWithOutLink")
new_part_doc.Part.Update()
new_extract = new_hb.HybridShapes.Item(new_hb.HybridShapes.Count)
# Redo changes in the part, where the selection was made
c_sel.Clear()
c_sel.Add(hb)
c_sel.Delete()
# Create axis systems from Position object of sel_prd_by_user and sel_prd_by_catia
prod_list = [sel_prod_by_user, sel_prod_by_catia]
axs_list = []
for prod in prod_list:
pc_pos = pycatia.in_interfaces.position.Position(prod.Position) # conversion to pycata's Position object, necessary
# in order to use Position.GetComponents
ax_comp = pc_pos.get_components()
axs = new_part_doc.Part.AxisSystems.Add()
axs.PutOrigin(ax_comp[9:12])
axs.PutXAxis(ax_comp[0:3])
axs.PutYAxis(ax_comp[3:6])
axs.PutZAxis(ax_comp[6:9])
axs_list.append(axs)
new_part_doc.Part.Update()
# Translate the extract from axis system derived from sel_prd_by_catia to sel_prd_by_user
extract_ref = new_part_doc.Part.CreateReferenceFromObject(new_extract)
tgt_ax_ref = new_part_doc.Part.CreateReferenceFromObject(axs_list[0])
ref_ax_ref = new_part_doc.Part.CreateReferenceFromObject(axs_list[1])
new_extract_translated = new_part_doc.Part.HybridShapeFactory.AddNewAxisToAxis(extract_ref, ref_ax_ref, tgt_ax_ref)
new_hb.AppendHybridShape(new_extract_translated)
new_part_doc.Part.Update()
I would suggest a differed approach. Instead of adding references you get from somewhere (by name probably) add the actual instance of part to selection while iterating trough all the products. Or use instance Names to get the correct part.
Here is a simple VBA example of iterating one lvl tree and select copy paste scenario.
If you want to copy features, you have to dive deeper on the Instance objects.
Public Sub CatMain()
Dim ActiveDoc As ProductDocument
Dim ActiveSel As Selection
If TypeOf CATIA.ActiveDocument Is ProductDocument Then 'of all the checks that people are using I think this one is most elegant and reliable
Set ActiveDoc = CATIA.ActiveDocument
Set ActiveSel = ActiveDoc.Selection
Else
Exit Sub
End If
Dim Instance As Product
For Each Instance In ActiveDoc.Product.Products 'object oriented for ideal for us in this scenario
If Instance.Products.Count = 0 Then 'beware that products without parts have also 0 items and are therefore mistaken for parts
Call ActiveSel.Add(Instance)
End If
Next
Call ActiveSel.Copy
Call ActiveSel.Clear
Dim NewDoc As ProductDocument
Set NewDoc = CATIA.Documents.Add("CATProduct")
Set ActiveSel = NewDoc.Selection
Call ActiveSel.Add(NewDoc.Product)
Call ActiveSel.Paste
Call ActiveSel.Clear
End Sub
I've got a template schematic made in raw .dot format, but I now want to populate the labels using python.
with the https://pypi.org/project/graphviz/ library I've managed to load the .dot file but don't see how I can edit it. Is it possible to convert a Source object to a Graph object, or otherwise use the methods available to the Graph object?
trying:
from graphviz import Source
src = Source('digraph "the holy hand grenade" { rankdir=LR; 1 -> 2 -> 3 -> lob }')
src.node("foo")
_ = src.render('test.gv', view=False)
Source.from_file('test.gv')
I get the error AttributeError: 'Source' object has no attribute 'node'
Following the great answer of #Ray Ronnaret, this is what worked for me.
I have no comments in my dot file, thus it becomes as simple as follows:
from graphviz import Source, Digraph
s = Source.from_file('viz.dot')
g = Digraph()
source_lines = str(s).splitlines()
# Remove 'digraph tree {'
source_lines.pop(0)
# Remove the closing brackets '}'
source_lines.pop(-1)
# Append the nodes to body
g.body += source_lines
Then, I was able to edit the graph.
g.graph_attr['rankdir'] = 'LR'
g.unflatten(stagger=3).render()
I do parse the grapviz.source eliminate non necessary char and append back. This work for me. Note that this assume first line may be contain comment. Thing remains is to make it be function.
src = Source.from_file('Source.gv')
lst = str(src).splitlines()
HasComment = (lst[0].find('//') != -1)
IsDirectGraph = False
skipIndex = 0
if HasComment:
skipIndex = 1
if lst[skipIndex].find('graph {')!=-1 :
IsDirectGraph= False
else:
if lst[0].find('graph {')!=-1 :
IsDirectGraph= False
if IsDirectGraph:
g = Digraph()
else:
g = Graph()
g.body.clear()
s = str()
for i in range(len(lst)):
if( (i>skipIndex) and (i!=len(lst)-1) ):
if HasComment:
g.comment = lst[0].replace('//','')
g.body.append(lst[i])
print(g.source)
display(g)
https://github.com/xflr6/graphviz/issues/76
answers the question that it is not possible with that library, but other ones are available which can.
I'm trying to read data from a csv and then process it on different way. (For starter just the average)
Data
(OneDrive) https://1drv.ms/u/s!ArLDiUd-U5dtg0teQoKGguBA1qt9?e=6wlpko
The data looks like this:
ID; Property1; Property2; Property3...
1; ....
1; ...
1; ...
2; ...
2; ...
3; ...
...
Every line is a GPS point. All points with same ID together (for example 1) produce one Route. The routes are not of the same length and some IDs are skipped. So it isn't a seamless increase of numbers.
I may need to add, that the points are ALWAYS the same set of meters apart from each other. And I don't need the XY information currently.
Wanted Result
In the end I want something like this:
[ID, AVG_Property1, AVG_Property2...] [1, 1.00595, 2.9595, ...] [2,1.50606, 1.5959, ...]
What I got so far
import os
import numpy
import pandas as pd
data = pd.read_csv(os.path.join('C:\\data' ,'data.csv'), sep=';')
# [id, len, prop1, prop2, ...]
routes = numpy.zeros((data.size, 10)) # 10 properties
sums = numpy.zeros(8)
nr_of_entries = 0;
current_id = 1;
for index, row in data.iterrows():
if(int(row['id']) != current_id): #after the last point of the route
routes[current_id-1][0] = current_id;
routes[current_id-1][1] = nr_of_entries; #how many points are in this route?
routes[current_id-1][2] = sums[0] / nr_of_entries;
routes[current_id-1][3] = sums[1] / nr_of_entries;
routes[current_id-1][4] = sums[2] / nr_of_entries;
routes[current_id-1][5] = sums[3] / nr_of_entries;
routes[current_id-1][6] = sums[4] / nr_of_entries;
routes[current_id-1][7] = sums[5] / nr_of_entries;
routes[current_id-1][8] = sums[6] / nr_of_entries;
routes[current_id-1][9] = sums[7] / nr_of_entries;
current_id = int(row['id']);
sums = numpy.zeros(8)
nr_of_entries = 0;
sums[0] += row[3];
sums[1] += row[4];
sums[2] += row[5];
sums[3] += row[6];
sums[4] += row[7];
sums[5] += row[8];
sums[6] += row[9];
sums[7] += row[10];
nr_of_entries = nr_of_entries + 1;
routes
My problem
1.) The way I did it, I have to copy paste the same code for every other processing approach, since as stated I need to do multiple different way. Average is just an example.
2.) The reading of the data is clumsy and fails when IDs are missing
3.) I'm a C# Developer, so my approach would be to create a Class 'Route' which has all the points and then provide methods for 'calculate average for prop 1'. Or something. This way I could also tweak the data if needed. (extreme values for example). But I have no idea how this would be done in Phyton and if this is a reasonable approach in this language.
4.) Is there a more elegant way to iterate through the original csv and getting like Route ID 1, then Route ID 2 and so on? Maybe something like LINQ Queries in C#?
Thanks for any help.
He is a solution and some ideas you can use. The example features multiple options for the same issue so you have to choose which fits the purpose best. Also it is Python 3.7, you didn't specify a version so i hope this works.
class Route(object):
"""description of class"""
def __init__(self, id, rawdata): # on startup
self.id = id
self.rawdata = rawdata
self.avg_Prop1 = self.calculate_average('Prop1')
self.sum_Prop4 = None
def calculate_average(self, Prop_Name): #selfreference for first argument in class method
return self.rawdata[Prop_Name].mean()
def give_Prop_data(self, Prop_Name): #return the Propdata as list
return self.rawdata[Prop_Name].tolist()
def any_function(self, my_function, Prop_Name): #not sure what dataframes support so turning it into a list first
return my_function(self.rawdata[Prop_Name].tolist())
#end of class definiton
data = pd.read_csv('testdata.csv', sep=';')
# [id, len, prop1, prop2, ...]
route_list = [] #List of all the objects created from the route class
for i in data.id.unique():
print('Current id:', i,' with ',len(data[data['id']==i]),'entries')
route_list.append(Route(i,data[data['id']==i]))
#created the Prop1 average in initialization of route so just accessing attribute
print(route_list[1].avg_Prop1)
for current_route in route_list:
print('Route ',current_route.id , ' Properties :')
for i in current_route.rawdata.columns[1:]: #for all except the first (id)
print(i, ' has average ', current_route.calculate_average(i)) #i is the string of the column not just an id
#or pass any function that you want
route_list[1].sum_Prop4 = (route_list[1].any_function(sum,'Prop4'))
print(route_list[1].sum_Prop4)
#which is equivalent to
print(sum(route_list[1].rawdata['Prop4']))
To adress your individual problems out of order:
For 2. and 4.) Looping only over the existing Ids (data.id.unique()) solves the problem. I have no idea what LINQ Queries are, but i assume they are similar. In general, Python has a great way of looping over objects (like for current_route in route_list), which is worth looking into if you want to use it a little more.
For 1. and 3.) Again looping solves the issue. I created a class in the example, mostly to show the syntax for classes. The benefits and drawbacks for using classes should be the same in Python as in C#.
As it is right now the class probably isn't great, but this depends on how you want to use it. If the class should just be a practical way of storing and accessing data it shouldn't have the methods, because you don't need an individual average method for each route. Then you can just access it's data and use it in a function like in sum(route_list[1].rawdata['Prop4']). If however, depending on the data (amount of rows for example) different calculations are necessary, it might come in handy to use the method calculate_average and differentiate in there.
An other example would be the use of the attributes. If you need the average for Prop1 every time, creating it at the initialization sees a good idea, otherwise i wouldn't bother always calculating it.
I hope this helps!